diff --git a/build.gradle b/build.gradle index 7c73f44cf..928cd432d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ buildscript { repositories { maven { url = 'https://maven.minecraftforge.net' } - jcenter() mavenCentral() maven { url = 'https://repo.spongepowered.org/repository/maven-public' } maven { url = 'https://maven.parchmentmc.org' } @@ -37,6 +36,7 @@ println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getPro minecraft { mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}" + runs { client { workingDirectory project.file('run') diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 63ca7a78f..3ae7e9691 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -5,7 +5,7 @@ import org.slf4j.Logger; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.OptifineHandler; -import com.jozufozu.flywheel.config.EngineArgument; +import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.Contexts; @@ -88,7 +88,7 @@ public class Flywheel { } private static void setup(final FMLCommonSetupEvent event) { - ArgumentTypes.register(rl("engine").toString(), EngineArgument.class, new EmptyArgumentSerializer<>(EngineArgument::getInstance)); + ArgumentTypes.register(rl("engine").toString(), BackendTypeArgument.class, new EmptyArgumentSerializer<>(BackendTypeArgument::getInstance)); } public static ArtifactVersion getVersion() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 90a853493..d3be6f353 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -6,8 +6,9 @@ import org.slf4j.Logger; import com.jozufozu.flywheel.api.FlywheelWorld; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; +import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine; import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.config.FlwEngine; +import com.jozufozu.flywheel.config.BackendType; import com.jozufozu.flywheel.core.shader.ProgramSpec; import com.mojang.logging.LogUtils; @@ -19,12 +20,30 @@ import net.minecraft.world.level.LevelAccessor; public class Backend { public static final Logger LOGGER = LogUtils.getLogger(); - private static FlwEngine engine; + private static BackendType backendType; + + private static ParallelTaskEngine taskEngine; private static final Loader loader = new Loader(); - public static FlwEngine getEngine() { - return engine; + /** + * Get the current Flywheel backend type. + */ + public static BackendType getBackendType() { + return backendType; + } + + /** + * Get a thread pool for running Flywheel related work in parallel. + * @return A global Flywheel thread pool. + */ + public static ParallelTaskEngine getTaskEngine() { + if (taskEngine == null) { + taskEngine = new ParallelTaskEngine("Flywheel"); + taskEngine.startWorkers(); + } + + return taskEngine; } /** @@ -32,7 +51,7 @@ public class Backend { * (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use. */ public static String getBackendDescriptor() { - return engine == null ? "Uninitialized" : engine.getProperName(); + return backendType == null ? "Uninitialized" : backendType.getProperName(); } @Nullable @@ -41,11 +60,11 @@ public class Backend { } public static void refresh() { - engine = chooseEngine(); + backendType = chooseEngine(); } public static boolean isOn() { - return engine != FlwEngine.OFF; + return backendType != BackendType.OFF; } public static boolean canUseInstancing(@Nullable Level world) { @@ -73,9 +92,9 @@ public class Backend { RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged); } - private static FlwEngine chooseEngine() { - FlwEngine preferredChoice = FlwConfig.get() - .getEngine(); + private static BackendType chooseEngine() { + BackendType preferredChoice = FlwConfig.get() + .getBackendType(); boolean usingShaders = OptifineHandler.isUsingShaders(); boolean canUseEngine = switch (preferredChoice) { @@ -84,7 +103,7 @@ public class Backend { case INSTANCING -> !usingShaders && GlCompat.getInstance().instancedArraysSupported(); }; - return canUseEngine ? preferredChoice : FlwEngine.OFF; + return canUseEngine ? preferredChoice : BackendType.OFF; } public static void init() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index ac6b9037a..c3ee1a1f6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -7,7 +7,6 @@ import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; -import com.jozufozu.flywheel.config.FlwEngine; import com.jozufozu.flywheel.core.Contexts; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.BeginFrameEvent; @@ -17,7 +16,6 @@ import com.jozufozu.flywheel.util.ClientLevelExtension; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.entity.BlockEntity; @@ -34,33 +32,35 @@ public class InstanceWorld { public final ParallelTaskEngine taskEngine; - public InstanceWorld(LevelAccessor levelAccessor) { - Level world = (Level) levelAccessor; - - this.taskEngine = new ParallelTaskEngine("Flywheel " + world.dimension().location()); - this.taskEngine.startWorkers(); - - FlwEngine engine = Backend.getEngine(); - - switch (engine) { + public static InstanceWorld create(LevelAccessor level) { + return switch (Backend.getBackendType()) { case INSTANCING -> { InstancingEngine manager = InstancingEngine.builder(Contexts.WORLD) .build(); - entityInstanceManager = new EntityInstanceManager(manager); - blockEntityInstanceManager = new BlockEntityInstanceManager(manager); + var entityInstanceManager = new EntityInstanceManager(manager); + var blockEntityInstanceManager = new BlockEntityInstanceManager(manager); manager.addListener(entityInstanceManager); manager.addListener(blockEntityInstanceManager); - this.engine = manager; + yield new InstanceWorld(manager, entityInstanceManager, blockEntityInstanceManager); } case BATCHING -> { - this.engine = new BatchingEngine(); - entityInstanceManager = new EntityInstanceManager(this.engine); - blockEntityInstanceManager = new BlockEntityInstanceManager(this.engine); + var manager = new BatchingEngine(); + var entityInstanceManager = new EntityInstanceManager(manager); + var blockEntityInstanceManager = new BlockEntityInstanceManager(manager); + + yield new InstanceWorld(manager, entityInstanceManager, blockEntityInstanceManager); } default -> throw new IllegalArgumentException("Unknown engine type"); - } + }; + } + + public InstanceWorld(Engine engine, InstanceManager entityInstanceManager, InstanceManager blockEntityInstanceManager) { + this.engine = engine; + this.entityInstanceManager = entityInstanceManager; + this.blockEntityInstanceManager = blockEntityInstanceManager; + this.taskEngine = Backend.getTaskEngine(); } public InstanceManager getEntityInstanceManager() { @@ -75,7 +75,6 @@ public class InstanceWorld { * Free all acquired resources and invalidate this instance world. */ public void delete() { - taskEngine.stopWorkers(); engine.delete(); entityInstanceManager.detachLightListeners(); blockEntityInstanceManager.detachLightListeners(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index 908f2381b..6f8f77e3d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -27,7 +27,7 @@ import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber(Dist.CLIENT) public class InstancedRenderDispatcher { - private static final WorldAttached instanceWorlds = new WorldAttached<>(InstanceWorld::new); + private static final WorldAttached instanceWorlds = new WorldAttached<>(InstanceWorld::create); /** * Call this when you want to manually run {@link AbstractInstance#update()}. @@ -61,10 +61,6 @@ public class InstancedRenderDispatcher { return getInstanceWorld(world).getEntityInstanceManager(); } - public static ParallelTaskEngine getTaskEngine(LevelAccessor world) { - return getInstanceWorld(world).taskEngine; - } - /** * Get or create the {@link InstanceWorld} for the given world. * @throws NullPointerException if the backend is off diff --git a/src/main/java/com/jozufozu/flywheel/config/BackendType.java b/src/main/java/com/jozufozu/flywheel/config/BackendType.java new file mode 100644 index 000000000..b5244b500 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/BackendType.java @@ -0,0 +1,51 @@ +package com.jozufozu.flywheel.config; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import javax.annotation.Nullable; + +public enum BackendType { + OFF("Off"), + + /** + * Use a thread pool to buffer instances in parallel on the CPU. + */ + BATCHING("Parallel Batching"), + + /** + * Use GPU instancing to render everything. + */ + INSTANCING("GL33 Instanced Arrays"), + ; + + private static final Map lookup; + + static { + lookup = new HashMap<>(); + for (BackendType value : values()) { + lookup.put(value.name().toLowerCase(Locale.ROOT), value); + } + } + + private final String properName; + + BackendType(String properName) { + this.properName = properName; + } + + public String getProperName() { + return properName; + } + + @Nullable + public static BackendType byName(String name) { + return lookup.get(name); + } + + public static Collection validNames() { + return lookup.keySet(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/EngineArgument.java b/src/main/java/com/jozufozu/flywheel/config/BackendTypeArgument.java similarity index 72% rename from src/main/java/com/jozufozu/flywheel/config/EngineArgument.java rename to src/main/java/com/jozufozu/flywheel/config/BackendTypeArgument.java index 497a60870..7f2545a3a 100644 --- a/src/main/java/com/jozufozu/flywheel/config/EngineArgument.java +++ b/src/main/java/com/jozufozu/flywheel/config/BackendTypeArgument.java @@ -14,7 +14,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.TranslatableComponent; -public enum EngineArgument implements ArgumentType { +public enum BackendTypeArgument implements ArgumentType { INSTANCE; private static final Dynamic2CommandExceptionType INVALID = new Dynamic2CommandExceptionType((found, constants) -> { @@ -23,28 +23,28 @@ public enum EngineArgument implements ArgumentType { }); @Override - public FlwEngine parse(StringReader reader) throws CommandSyntaxException { + public BackendType parse(StringReader reader) throws CommandSyntaxException { String string = reader.readUnquotedString(); - FlwEngine engine = FlwEngine.byName(string); + BackendType engine = BackendType.byName(string); if (engine == null) { - throw INVALID.createWithContext(reader, string, FlwEngine.validNames()); + throw INVALID.createWithContext(reader, string, BackendType.validNames()); } return engine; } public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { - return SharedSuggestionProvider.suggest(FlwEngine.validNames(), builder); + return SharedSuggestionProvider.suggest(BackendType.validNames(), builder); } @Override public Collection getExamples() { - return FlwEngine.validNames(); + return BackendType.validNames(); } - public static EngineArgument getInstance() { + public static BackendTypeArgument getInstance() { return INSTANCE; } } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index ccd9e262d..7575111e0 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -27,7 +27,7 @@ public class FlwCommands { ConfigCommandBuilder commandBuilder = new ConfigCommandBuilder("flywheel"); - commandBuilder.addValue(config.client.engine, "backend", (builder, value) -> + commandBuilder.addValue(config.client.backend, "backend", (builder, value) -> builder .executes(context -> { LocalPlayer player = Minecraft.getInstance().player; @@ -36,11 +36,11 @@ public class FlwCommands { } return Command.SINGLE_SUCCESS; }) - .then(Commands.argument("type", EngineArgument.INSTANCE) + .then(Commands.argument("type", BackendTypeArgument.INSTANCE) .executes(context -> { LocalPlayer player = Minecraft.getInstance().player; if (player != null) { - FlwEngine type = context.getArgument("type", FlwEngine.class); + BackendType type = context.getArgument("type", BackendType.class); value.set(type); Component message = getEngineMessage(type); @@ -51,7 +51,7 @@ public class FlwCommands { return Command.SINGLE_SUCCESS; }))); - commandBuilder.addValue(config.client.debugNormals, "debugNormals", (builder, value) -> booleanValueCommand(builder, config, value, + commandBuilder.addValue(config.client.debugNormals, "debugNormals", (builder, value) -> booleanValueCommand(builder, value, (source, bool) -> { LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; @@ -68,7 +68,7 @@ public class FlwCommands { } )); - commandBuilder.addValue(config.client.limitUpdates, "limitUpdates", (builder, value) -> booleanValueCommand(builder, config, value, + commandBuilder.addValue(config.client.limitUpdates, "limitUpdates", (builder, value) -> booleanValueCommand(builder, value, (source, bool) -> { LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; @@ -90,7 +90,7 @@ public class FlwCommands { commandBuilder.build(event.getDispatcher()); } - public static void booleanValueCommand(LiteralArgumentBuilder builder, FlwConfig config, ConfigValue value, BiConsumer displayAction, BiConsumer setAction) { + public static void booleanValueCommand(LiteralArgumentBuilder builder, ConfigValue value, BiConsumer displayAction, BiConsumer setAction) { builder .executes(context -> { displayAction.accept(context.getSource(), value.get()); @@ -114,7 +114,7 @@ public class FlwCommands { return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED); } - public static Component getEngineMessage(@NotNull FlwEngine type) { + public static Component getEngineMessage(@NotNull BackendType type) { return switch (type) { case OFF -> new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED); case INSTANCING -> new TextComponent("Using Instancing Engine").withStyle(ChatFormatting.GREEN); diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index 95be3cc46..1872131f7 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -27,8 +27,8 @@ public class FlwConfig { return INSTANCE; } - public FlwEngine getEngine() { - return client.engine.get(); + public BackendType getBackendType() { + return client.backend.get(); } public boolean debugNormals() { @@ -43,15 +43,15 @@ public class FlwConfig { } public static class ClientConfig { - public final EnumValue engine; + public final EnumValue backend; public final BooleanValue debugNormals; public final BooleanValue limitUpdates; public ClientConfig(ForgeConfigSpec.Builder builder) { - engine = builder.comment("Enable or disable the entire engine") - .defineEnum("backend", FlwEngine.INSTANCING); + backend = builder.comment("Select the backend to use.") + .defineEnum("backend", BackendType.INSTANCING); - debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal") + debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal.") .define("debugNormals", false); limitUpdates = builder.comment("Enable or disable instance update limiting with distance.") diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java b/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java deleted file mode 100644 index f5665e1f4..000000000 --- a/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.jozufozu.flywheel.config; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; - -public enum FlwEngine { - OFF("off", "Off"), - BATCHING("batching", "Parallel Batching"), - INSTANCING("instancing", "GL33 Instanced Arrays"), - ; - - private static final Map lookup; - - static { - lookup = new HashMap<>(); - for (FlwEngine value : values()) { - lookup.put(value.shortName, value); - } - } - - private final String shortName; - private final String properName; - - FlwEngine(String shortName, String properName) { - this.shortName = shortName; - this.properName = properName; - } - - public String getShortName() { - return shortName; - } - - public String getProperName() { - return properName; - } - - @Nullable - public static FlwEngine byName(String name) { - return lookup.get(name); - } - - public static Collection validNames() { - return lookup.keySet(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java b/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java index 7692126a9..6161fd803 100644 --- a/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java +++ b/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java @@ -5,7 +5,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Stream; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine; import com.jozufozu.flywheel.util.WeakHashSet; import com.jozufozu.flywheel.util.WorldAttached; @@ -37,7 +37,7 @@ public class LightUpdater { private final WeakContainmentMultiMap chunks = new WeakContainmentMultiMap<>(); public LightUpdater(LevelAccessor world) { - taskEngine = InstancedRenderDispatcher.getTaskEngine(world); + taskEngine = Backend.getTaskEngine(); provider = new BasicProvider(world); }