Layoff some workers

- Only one task engine for everything now
 - Fixes crash on LightUpdater init when Flywheel is off
 - Attempt to wrangle InstanceWorld init code
 - Misc. cleanup/renaming
This commit is contained in:
Jozufozu 2022-04-07 14:19:36 -07:00
parent 19d757d702
commit 9a69ed1906
11 changed files with 125 additions and 108 deletions

View file

@ -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')

View file

@ -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() {

View file

@ -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() {

View file

@ -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<WorldProgram> 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<Entity> entityInstanceManager, InstanceManager<BlockEntity> blockEntityInstanceManager) {
this.engine = engine;
this.entityInstanceManager = entityInstanceManager;
this.blockEntityInstanceManager = blockEntityInstanceManager;
this.taskEngine = Backend.getTaskEngine();
}
public InstanceManager<Entity> 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();

View file

@ -27,7 +27,7 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class InstancedRenderDispatcher {
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>(InstanceWorld::new);
private static final WorldAttached<InstanceWorld> 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

View file

@ -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<String, BackendType> 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<String> validNames() {
return lookup.keySet();
}
}

View file

@ -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<FlwEngine> {
public enum BackendTypeArgument implements ArgumentType<BackendType> {
INSTANCE;
private static final Dynamic2CommandExceptionType INVALID = new Dynamic2CommandExceptionType((found, constants) -> {
@ -23,28 +23,28 @@ public enum EngineArgument implements ArgumentType<FlwEngine> {
});
@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 <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return SharedSuggestionProvider.suggest(FlwEngine.validNames(), builder);
return SharedSuggestionProvider.suggest(BackendType.validNames(), builder);
}
@Override
public Collection<String> getExamples() {
return FlwEngine.validNames();
return BackendType.validNames();
}
public static EngineArgument getInstance() {
public static BackendTypeArgument getInstance() {
return INSTANCE;
}
}

View file

@ -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<CommandSourceStack> builder, FlwConfig config, ConfigValue<Boolean> value, BiConsumer<CommandSourceStack, Boolean> displayAction, BiConsumer<CommandSourceStack, Boolean> setAction) {
public static void booleanValueCommand(LiteralArgumentBuilder<CommandSourceStack> builder, ConfigValue<Boolean> value, BiConsumer<CommandSourceStack, Boolean> displayAction, BiConsumer<CommandSourceStack, Boolean> 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);

View file

@ -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<FlwEngine> engine;
public final EnumValue<BackendType> 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.")

View file

@ -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<String, FlwEngine> 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<String> validNames() {
return lookup.keySet();
}
}

View file

@ -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<LightListener> chunks = new WeakContainmentMultiMap<>();
public LightUpdater(LevelAccessor world) {
taskEngine = InstancedRenderDispatcher.getTaskEngine(world);
taskEngine = Backend.getTaskEngine();
provider = new BasicProvider(world);
}