diff --git a/changelog.txt b/changelog.txt index 1a62e6f1a..5efc1aa0b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +0.5.0a: +Fixes + - Address crash experienced by some users while rendering any tile. + - Fix crash caused by loading a world with flywheel backend off. + 0.5.0: New - Added parallel batching backend, effectively a CPU instancer. diff --git a/gradle.properties b/gradle.properties index 84eb4d04f..fb86b8d59 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G org.gradle.daemon = false # mod version info -mod_version = 0.5.0 +mod_version = 0.5.0a mc_update_version = 1.18 minecraft_version = 1.18.1 forge_version = 39.0.8 diff --git a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java index 3ec94f352..3d7f7adb5 100644 --- a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java +++ b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java @@ -9,12 +9,16 @@ import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; import com.jozufozu.flywheel.vanilla.VanillaInstances; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.CrashReportCallables; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; public class FlywheelClient { public static void clientInit() { + CrashReportCallables.registerCrashCallable("Flywheel Backend", () -> + Backend.getInstance().getBackendDescriptor()); + Backend.init(); IEventBus modEventBus = FMLJavaModLoadingContext.get() .getModEventBus(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 1d5f931eb..bffbddc46 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -27,7 +27,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; public class Backend { - public static final Logger log = LogManager.getLogger(Backend.class); + public static final Logger LOGGER = LogManager.getLogger(Backend.class); protected static final Backend INSTANCE = new Backend(); public static Backend getInstance() { @@ -39,8 +39,6 @@ public class Backend { public GLCapabilities capabilities; public GlCompat compat; - private boolean enabled; - public final Loader loader; private final List> contexts = new ArrayList<>(); private final Map> materialRegistry = new HashMap<>(); @@ -93,7 +91,7 @@ public class Backend { } materialRegistry.put(name, spec); - log.debug("registered material '" + name + "' with instance size " + spec.getLayout().getStride()); + LOGGER.debug("registered material '" + name + "' with instance size " + spec.getLayout().getStride()); return spec; } @@ -104,20 +102,12 @@ public class Backend { public void refresh() { OptifineHandler.refresh(); - boolean usingShaders = OptifineHandler.usingShaders(); capabilities = GL.createCapabilities(); compat = new GlCompat(capabilities); - engine = FlwConfig.get() - .getEngine(); - - enabled = switch (engine) { - case OFF -> false; - case BATCHING -> true; - case INSTANCING -> !usingShaders && compat.instancedArraysSupported(); - }; + engine = chooseEngine(compat); } public Collection> allMaterials() { @@ -133,7 +123,7 @@ public class Backend { } public static boolean isOn() { - return getInstance().enabled; + return getInstance().engine != FlwEngine.OFF; } public static boolean canUseInstancing(@Nullable Level world) { @@ -174,4 +164,18 @@ public class Backend { public static void init() { } + + private static FlwEngine chooseEngine(GlCompat compat) { + FlwEngine preferredChoice = FlwConfig.get() + .getEngine(); + + boolean usingShaders = OptifineHandler.usingShaders(); + boolean canUseEngine = switch (preferredChoice) { + case OFF -> true; + case BATCHING -> !usingShaders; + case INSTANCING -> !usingShaders && compat.instancedArraysSupported(); + }; + + return canUseEngine ? preferredChoice : FlwEngine.OFF; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 9bf8d3b80..188900381 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -85,10 +85,10 @@ public class Loader implements ResourceManagerReloadListener { throw new ShaderLoadingException("Could not load all shaders, see log for details"); } - Backend.log.info("Loaded all shader programs."); + Backend.LOGGER.info("Loaded all shader programs."); ClientLevel world = Minecraft.getInstance().level; - if (Backend.isFlywheelWorld(world)) { + if (Backend.canUseInstancing(world)) { // TODO: looks like it might be good to have another event here InstancedRenderDispatcher.resetInstanceWorld(world); CrumblingRenderer.reset(); @@ -118,7 +118,7 @@ public class Loader implements ResourceManagerReloadListener { backend.register(spec); } catch (Exception e) { - Backend.log.error(e); + Backend.LOGGER.error(e); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java index 1fd8fbd2f..f003208fe 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java @@ -44,9 +44,9 @@ public class OptifineHandler { optifine = Package.getPackage(OPTIFINE_ROOT_PACKAGE); if (optifine == null) { - Backend.log.info("Optifine not detected."); + Backend.LOGGER.info("Optifine not detected."); } else { - Backend.log.info("Optifine detected."); + Backend.LOGGER.info("Optifine detected."); refresh(); } @@ -79,7 +79,7 @@ public class OptifineHandler { return false; }); } catch (IOException e) { - Backend.log.info("No shader config found."); + Backend.LOGGER.info("No shader config found."); } return shadersOff; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java index 79f6148ef..fb783dc4f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -12,7 +12,6 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlFence; import com.jozufozu.flywheel.backend.gl.error.GlError; import com.jozufozu.flywheel.backend.gl.error.GlException; -import com.jozufozu.flywheel.util.StringUtil; public class PersistentGlBuffer extends GlBuffer implements Mappable { @@ -49,13 +48,6 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable { Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags); - GlError error = GlError.poll(); - if (error != null) { - // If this error is being thrown but everything seems fine, - // GlError.poll() might be returning an error from something earlier. - throw new GlException(error, StringUtil.args("bufferStorage", type, size, flags)); - } - ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags); if (byteBuffer == null) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/error/GlError.java b/src/main/java/com/jozufozu/flywheel/backend/gl/error/GlError.java index 41b9ddf46..a0cdbded8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/error/GlError.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/error/GlError.java @@ -5,8 +5,6 @@ import java.util.function.Supplier; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; -import com.jozufozu.flywheel.Flywheel; - import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -41,10 +39,10 @@ public enum GlError { } public static void pollAndThrow(Supplier context) { - // TODO: build flag? to enable or disable this function - GlError err = GlError.poll(); - if (err != null) { - Flywheel.LOGGER.error("{}: {}", err.name(), context.get()); - } +// This was a bad idea. +// GlError err = GlError.poll(); +// if (err != null) { +// Flywheel.LOGGER.error("{}: {}", err.name(), context.get()); +// } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java index 8fbac95cd..432575f5e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java @@ -49,7 +49,7 @@ public abstract class GlProgram extends GlObject { int index = glGetUniformLocation(this.handle(), uniform); if (index < 0) { - Backend.log.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); + Backend.LOGGER.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); } return index; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index f6464778c..bde532d88 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -46,7 +46,7 @@ public class GlShader extends GlObject { needsSourceDump = true; } } - Backend.log.error("Errors compiling '" + name + "': \n" + errors); + Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors); if (needsSourceDump) { // TODO: generated code gets its own "file" ErrorReporter.printLines(source); 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 216cceebc..51755ed9f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -29,8 +29,11 @@ public class InstancedRenderDispatcher { * @param te The tile whose instance you want to update. */ public static void enqueueUpdate(BlockEntity te) { - if (te.hasLevel() && te.getLevel() instanceof ClientLevel) - getTiles(te.getLevel()).queueUpdate(te); + if (Backend.isOn() && te.hasLevel() && te.getLevel() instanceof ClientLevel) { + instanceWorlds.get(te.getLevel()) + .getTileEntityInstanceManager() + .queueUpdate(te); + } } /** @@ -38,17 +41,29 @@ public class InstancedRenderDispatcher { * @param entity The entity whose instance you want to update. */ public static void enqueueUpdate(Entity entity) { - getEntities(entity.level).queueUpdate(entity); + if (Backend.isOn()) { + instanceWorlds.get(entity.level) + .getEntityInstanceManager() + .queueUpdate(entity); + } } public static InstanceManager getTiles(LevelAccessor world) { - return instanceWorlds.get(world) - .getTileEntityInstanceManager(); + if (Backend.isOn()) { + return instanceWorlds.get(world) + .getTileEntityInstanceManager(); + } else { + throw new NullPointerException("Backend is off, cannot retrieve instance world."); + } } public static InstanceManager getEntities(LevelAccessor world) { - return instanceWorlds.get(world) - .getEntityInstanceManager(); + if (Backend.isOn()) { + return instanceWorlds.get(world) + .getEntityInstanceManager(); + } else { + throw new NullPointerException("Backend is off, cannot retrieve instance world."); + } } @SubscribeEvent @@ -61,12 +76,15 @@ public class InstancedRenderDispatcher { ClientLevel world = mc.level; AnimationTickHolder.tick(); - instanceWorlds.get(world).tick(); + if (Backend.isOn()) { + instanceWorlds.get(world) + .tick(); + } } @SubscribeEvent public static void onBeginFrame(BeginFrameEvent event) { - if (Backend.isGameActive()) { + if (Backend.isGameActive() && Backend.isOn()) { instanceWorlds.get(event.getWorld()) .beginFrame(event); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java index c3abd0e40..09cc90041 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java @@ -38,7 +38,7 @@ public class ProgramAssembler { String log = glGetProgramInfoLog(this.program); if (!log.isEmpty()) { - Backend.log.debug("Program link log for " + name + ": " + log); + Backend.LOGGER.debug("Program link log for " + name + ": " + log); } int result = glGetProgrami(this.program, GL_LINK_STATUS); diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java index 00f1593a6..f186543aa 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java @@ -72,7 +72,7 @@ public class FileResolution { builder.pointAtFile(span.getSourceFile()) .pointAt(span, 1); } - Backend.log.error(builder.build()); + Backend.LOGGER.error(builder.build()); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java index 5829a8279..7a11ee253 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java @@ -21,7 +21,7 @@ public class ErrorReporter { .pointAt(span, 2) .build(); - Backend.log.error(error); + Backend.LOGGER.error(error); } public static void generateFileError(SourceFile file, String message) { @@ -30,7 +30,7 @@ public class ErrorReporter { .pointAtFile(file) .build(); - Backend.log.error(error); + Backend.LOGGER.error(error); } public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) { @@ -48,7 +48,7 @@ public class ErrorReporter { .pointAt(vertexName, 1) .hintIncludeFor(span.orElse(null), hint); - Backend.log.error(error.build()); + Backend.LOGGER.error(error.build()); } public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) { @@ -65,7 +65,7 @@ public class ErrorReporter { .pointAtFile(file) .hintIncludeFor(span.orElse(null), hint); - Backend.log.error(error.build()); + Backend.LOGGER.error(error.build()); } public static void printLines(CharSequence source) { diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index d9b608608..de1d1bea5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -36,7 +36,7 @@ public class WorldContext

implements ShaderContext

{ @Override public void load() { - Backend.log.info("Loading context '{}'", name); + Backend.LOGGER.info("Loading context '{}'", name); specStream.get() .map(backend::getSpec) @@ -48,11 +48,11 @@ public class WorldContext

implements ShaderContext

{ try { programs.put(spec.name, new LazyCompiler<>(pipeline, spec)); - Backend.log.debug("Loaded program {}", spec.name); + Backend.LOGGER.debug("Loaded program {}", spec.name); } catch (Exception e) { - Backend.log.error("Error loading program {}", spec.name); + Backend.LOGGER.error("Error loading program {}", spec.name); if (!(e instanceof ShaderLoadingException)) { - Backend.log.error("", e); + Backend.LOGGER.error("", e); } backend.loader.notifyError(); } diff --git a/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java b/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java index 10707ea24..c68054208 100644 --- a/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java +++ b/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.event; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import net.minecraftforge.api.distmarker.Dist; @@ -13,13 +14,13 @@ public class EntityWorldHandler { @SubscribeEvent public static void onEntityJoinWorld(EntityJoinWorldEvent event) { - if (event.getWorld().isClientSide) InstancedRenderDispatcher.getEntities(event.getWorld()) + if (event.getWorld().isClientSide && Backend.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld()) .queueAdd(event.getEntity()); } @SubscribeEvent public static void onEntityLeaveWorld(EntityLeaveWorldEvent event) { - if (event.getWorld().isClientSide) InstancedRenderDispatcher.getEntities(event.getWorld()) + if (event.getWorld().isClientSide && Backend.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld()) .remove(event.getEntity()); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/ChunkRebuildHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/ChunkRebuildHooksMixin.java index 2ddc15562..861fa7c06 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/ChunkRebuildHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/ChunkRebuildHooksMixin.java @@ -23,7 +23,7 @@ public class ChunkRebuildHooksMixin { @Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true) private void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set set, E be, CallbackInfo ci) { - if (Backend.isOn() && Backend.isFlywheelWorld(be.getLevel())) { + if (Backend.canUseInstancing(be.getLevel())) { InstancedRenderRegistry registry = InstancedRenderRegistry.getInstance(); if (registry.canInstance(be.getType())) diff --git a/src/main/java/com/jozufozu/flywheel/mixin/InstanceAddMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/InstanceAddMixin.java index dabee25e5..53137d485 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/InstanceAddMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/InstanceAddMixin.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import net.minecraft.world.level.Level; @@ -26,7 +27,9 @@ public class InstanceAddMixin { @Inject(method = "setBlockEntity", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) private void tileAdded(BlockEntity be, CallbackInfo ci) { - if (level.isClientSide) InstancedRenderDispatcher.getTiles(this.level) - .add(be); + if (level.isClientSide && Backend.isOn()) { + InstancedRenderDispatcher.getTiles(this.level) + .add(be); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/InstanceRemoveMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/InstanceRemoveMixin.java index e0282a5c8..9a6862ddf 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/InstanceRemoveMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/InstanceRemoveMixin.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import net.minecraft.client.multiplayer.ClientLevel; @@ -23,8 +24,10 @@ public class InstanceRemoveMixin { @Inject(at = @At("TAIL"), method = "setRemoved") private void removeInstance(CallbackInfo ci) { - if (level instanceof ClientLevel) InstancedRenderDispatcher.getTiles(this.level) - .remove((BlockEntity) (Object) this); + if (level instanceof ClientLevel && Backend.isOn()) { + InstancedRenderDispatcher.getTiles(this.level) + .remove((BlockEntity) (Object) this); + } } // /** diff --git a/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java index 9e963213e..5452c100e 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java @@ -86,7 +86,9 @@ public class RenderHooksMixin { */ @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V") private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) { - InstancedRenderDispatcher.getTiles(level) - .update(level.getBlockEntity(pos)); + if (Backend.isOn()) { + InstancedRenderDispatcher.getTiles(level) + .update(level.getBlockEntity(pos)); + } } }