From fe0eacad8e8df7f52c2b67927632746706eadc13 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Mon, 15 Jul 2024 15:36:52 -0600 Subject: [PATCH] Light clean up - Ensure section set returned by SectionTracker is Unmodifiable to avoid copy in LightUpdatedVisualStorage - Do not recompute section set in ShaderLightVisualStorage if not dirty - Fix BlockEntityStorage not clearing posLookup on recreation or invalidation - Fix Storage.invalidate not clearing everything - Inline TopLevelEmbeddedEnvironment and NestedEmbeddedEnvironment into AbstractEmbeddedEnvironment and rename to EmbeddedEnvironment - Move some classes between packages - Remove unused fields in EmbeddingUniforms - Remove suffix on field names in BufferBindings - Rename enqueueLightUpdateSection methods to onLightUpdate - Rename SectionCollectorImpl to SectionTracker - Rename classes, methods, fields, and parameters and edit javadoc and comments to match previously done renames, new renames, and other existing classes --- .../flywheel/api/backend/Engine.java | 14 +- .../api/visual/LightUpdatedVisual.java | 5 +- .../api/visual/SectionTrackedVisual.java | 8 +- .../flywheel/api/visual/Visual.java | 1 + .../{engine/embed => }/LightUpdateHolder.java | 13 +- .../component/SsboInstanceComponent.java | 2 +- .../backend/engine/{embed => }/Arena.java | 2 +- .../flywheel/backend/engine/DrawManager.java | 1 - .../flywheel/backend/engine/EngineImpl.java | 30 ++-- .../backend/engine/EnvironmentStorage.java | 19 --- .../backend/engine/{embed => }/LightLut.java | 8 +- .../engine/{embed => }/LightStorage.java | 3 +- ...ironment.java => EmbeddedEnvironment.java} | 89 +++++++----- .../engine/embed/EmbeddingUniforms.java | 14 +- .../backend/engine/embed/Environment.java | 4 +- .../engine/embed/EnvironmentStorage.java | 18 +++ .../engine/embed/GlobalEnvironment.java | 9 +- .../embed/NestedEmbeddedEnvironment.java | 23 --- .../embed/TopLevelEmbeddedEnvironment.java | 19 --- .../engine/indirect/BufferBindings.java | 16 +-- .../engine/indirect/IndirectBuffers.java | 4 +- .../engine/indirect/IndirectDrawManager.java | 9 +- .../backend/engine/indirect/LightBuffers.java | 11 +- .../instancing/InstancedDrawManager.java | 2 +- .../engine/instancing/InstancedLight.java | 6 +- .../backend/mixin/ClientChunkCacheMixin.java | 2 +- .../internal/indirect/buffer_bindings.glsl | 4 +- .../flywheel/internal/indirect/light.glsl | 4 +- .../impl/mixin/ClientChunkCacheMixin.java | 2 +- .../VisualizationManagerImpl.java | 23 ++- .../manager/BlockEntityStorage.java | 14 +- .../manager/VisualManagerImpl.java | 23 +-- ...ge.java => LightUpdatedVisualStorage.java} | 77 +++++----- ...CollectorImpl.java => SectionTracker.java} | 19 ++- .../storage/ShaderLightStorage.java | 52 ------- .../storage/ShaderLightVisualStorage.java | 53 +++++++ .../impl/visualization/storage/Storage.java | 131 +++++++++--------- .../flywheel/vanilla/MinecartVisual.java | 2 +- 38 files changed, 364 insertions(+), 372 deletions(-) rename common/src/backend/java/dev/engine_room/flywheel/backend/{engine/embed => }/LightUpdateHolder.java (84%) rename common/src/backend/java/dev/engine_room/flywheel/backend/engine/{embed => }/Arena.java (95%) delete mode 100644 common/src/backend/java/dev/engine_room/flywheel/backend/engine/EnvironmentStorage.java rename common/src/backend/java/dev/engine_room/flywheel/backend/engine/{embed => }/LightLut.java (96%) rename common/src/backend/java/dev/engine_room/flywheel/backend/engine/{embed => }/LightStorage.java (99%) rename common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/{AbstractEmbeddedEnvironment.java => EmbeddedEnvironment.java} (70%) create mode 100644 common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EnvironmentStorage.java delete mode 100644 common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/NestedEmbeddedEnvironment.java delete mode 100644 common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/TopLevelEmbeddedEnvironment.java rename common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/{LightUpdatedStorage.java => LightUpdatedVisualStorage.java} (74%) rename common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/{SectionCollectorImpl.java => SectionTracker.java} (58%) delete mode 100644 common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightStorage.java create mode 100644 common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java diff --git a/common/src/api/java/dev/engine_room/flywheel/api/backend/Engine.java b/common/src/api/java/dev/engine_room/flywheel/api/backend/Engine.java index 86865e33b..b6b7baa25 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/backend/Engine.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/backend/Engine.java @@ -62,13 +62,6 @@ public interface Engine { */ Vec3i renderOrigin(); - /** - * Free all resources associated with this engine. - *
- * This engine will not be used again after this method is called. - */ - void delete(); - /** * Assign the set of sections that visuals have requested GPU light for. * @@ -78,6 +71,13 @@ public interface Engine { */ void lightSections(LongSet sections); + /** + * Free all resources associated with this engine. + *
+ * This engine will not be used again after this method is called. + */ + void delete(); + /** * A block to be rendered as a crumbling overlay. * @param progress The progress of the crumbling animation in the range [0, 10). diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/LightUpdatedVisual.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/LightUpdatedVisual.java index 3ac56d93d..52015c436 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/LightUpdatedVisual.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/LightUpdatedVisual.java @@ -9,7 +9,8 @@ package dev.engine_room.flywheel.api.visual; */ public non-sealed interface LightUpdatedVisual extends SectionTrackedVisual { /** - * Called when a section this visual is contained in receives a light update. + * Called when a section this visual is contained in receives a light update. It is not called + * unconditionally after visual creation or {@link SectionCollector#sections}. * *

Even if multiple sections are updated at the same time, this method will only be called once.

* @@ -17,8 +18,6 @@ public non-sealed interface LightUpdatedVisual extends SectionTrackedVisual { * returned by {@link DynamicVisual#planFrame} simultaneously. It is safe to query/update light here, * but you must ensure proper synchronization if you want to mutate anything outside this visual or * anything that is also mutated within {@link DynamicVisual#planFrame}.

- * - *

This method not is invoked automatically after visual creation.

*/ void updateLight(float partialTick); } diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/SectionTrackedVisual.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/SectionTrackedVisual.java index 725d4a4ed..a2189357a 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/SectionTrackedVisual.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/SectionTrackedVisual.java @@ -6,15 +6,15 @@ import it.unimi.dsi.fastutil.longs.LongSet; public sealed interface SectionTrackedVisual extends Visual permits ShaderLightVisual, LightUpdatedVisual { /** - * Set the section property object. + * Set the section collector object. * *

This method is only called once, upon visual creation. - *
If the property is assigned to in this method, the + *
If the collector is invoked in this method, the * visual will immediately be tracked in the given sections. * - * @param property The property. + * @param collector The collector. */ - void setSectionCollector(SectionCollector property); + void setSectionCollector(SectionCollector collector); @ApiStatus.NonExtendable interface SectionCollector { diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java index 60b42fd15..f6d44d1de 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java @@ -6,6 +6,7 @@ package dev.engine_room.flywheel.api.visual; * @see DynamicVisual * @see TickableVisual * @see LightUpdatedVisual + * @see ShaderLightVisual */ public interface Visual { /** diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightUpdateHolder.java b/common/src/backend/java/dev/engine_room/flywheel/backend/LightUpdateHolder.java similarity index 84% rename from common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightUpdateHolder.java rename to common/src/backend/java/dev/engine_room/flywheel/backend/LightUpdateHolder.java index 52c5c09f7..e6f9e856d 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightUpdateHolder.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/LightUpdateHolder.java @@ -1,7 +1,8 @@ -package dev.engine_room.flywheel.backend.engine.embed; +package dev.engine_room.flywheel.backend; import dev.engine_room.flywheel.lib.util.LevelAttached; import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.world.level.LevelAccessor; @@ -11,12 +12,15 @@ import net.minecraft.world.level.LevelAccessor; public class LightUpdateHolder { private static final LevelAttached HOLDERS = new LevelAttached<>(level -> new LightUpdateHolder()); + private final LongSet updatedSections = new LongOpenHashSet(); + + private LightUpdateHolder() { + } + public static LightUpdateHolder get(LevelAccessor level) { return HOLDERS.get(level); } - private final LongSet updatedSections = new LongArraySet(); - public LongSet getAndClearUpdatedSections() { if (updatedSections.isEmpty()) { return LongSet.of(); @@ -30,7 +34,4 @@ public class LightUpdateHolder { public void add(long section) { updatedSections.add(section); } - - private LightUpdateHolder() { - } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/component/SsboInstanceComponent.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/component/SsboInstanceComponent.java index 92fb61099..c8902b2d4 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/component/SsboInstanceComponent.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/component/SsboInstanceComponent.java @@ -43,7 +43,7 @@ public class SsboInstanceComponent extends InstanceAssemblerComponent { fnBody.ret(GlslExpr.call(STRUCT_NAME, unpackArgs)); - builder._addRaw("layout(std430, binding = " + BufferBindings.INSTANCE_BUFFER_BINDING + ") restrict readonly buffer InstanceBuffer {\n" + builder._addRaw("layout(std430, binding = " + BufferBindings.INSTANCE + ") restrict readonly buffer InstanceBuffer {\n" + " uint _flw_instances[];\n" + "};"); builder.blankLine(); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Arena.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/Arena.java similarity index 95% rename from common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Arena.java rename to common/src/backend/java/dev/engine_room/flywheel/backend/engine/Arena.java index a43d6cbe5..101cc0013 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Arena.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/Arena.java @@ -1,4 +1,4 @@ -package dev.engine_room.flywheel.backend.engine.embed; +package dev.engine_room.flywheel.backend.engine; import dev.engine_room.flywheel.lib.memory.MemoryBlock; import it.unimi.dsi.fastutil.ints.IntArrayList; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/DrawManager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/DrawManager.java index 8f8def6e0..8b78be928 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/DrawManager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/DrawManager.java @@ -16,7 +16,6 @@ import dev.engine_room.flywheel.api.instance.Instancer; import dev.engine_room.flywheel.api.model.Model; import dev.engine_room.flywheel.backend.FlwBackend; import dev.engine_room.flywheel.backend.engine.embed.Environment; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; import dev.engine_room.flywheel.lib.util.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EngineImpl.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EngineImpl.java index fa36cd21f..46e66c007 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EngineImpl.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EngineImpl.java @@ -14,9 +14,9 @@ import dev.engine_room.flywheel.api.task.Plan; import dev.engine_room.flywheel.api.task.TaskExecutor; import dev.engine_room.flywheel.api.visualization.VisualEmbedding; import dev.engine_room.flywheel.api.visualization.VisualizationContext; +import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment; import dev.engine_room.flywheel.backend.engine.embed.Environment; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; -import dev.engine_room.flywheel.backend.engine.embed.TopLevelEmbeddedEnvironment; +import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.backend.gl.GlStateTracker; import dev.engine_room.flywheel.lib.task.Flag; @@ -30,11 +30,11 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.phys.Vec3; public class EngineImpl implements Engine { - private final int sqrMaxOriginDistance; private final DrawManager> drawManager; + private final int sqrMaxOriginDistance; + private final Flag flushFlag = new NamedFlag("flushed"); private final EnvironmentStorage environmentStorage; private final LightStorage lightStorage; - private final Flag flushFlag = new NamedFlag("flushed"); private BlockPos renderOrigin = BlockPos.ZERO; @@ -45,6 +45,11 @@ public class EngineImpl implements Engine { lightStorage = new LightStorage(level); } + @Override + public VisualizationContext createVisualizationContext(RenderStage stage) { + return new VisualizationContextImpl(stage); + } + @Override public Plan createFramePlan() { return lightStorage.createFramePlan() @@ -69,11 +74,6 @@ public class EngineImpl implements Engine { drawManager.renderCrumbling(crumblingBlocks); } - @Override - public VisualizationContext createVisualizationContext(RenderStage stage) { - return new VisualizationContextImpl(stage); - } - @Override public boolean updateRenderOrigin(Camera camera) { Vec3 cameraPos = camera.getPosition(); @@ -97,14 +97,14 @@ public class EngineImpl implements Engine { } @Override - public void delete() { - drawManager.delete(); - lightStorage.delete(); + public void lightSections(LongSet sections) { + lightStorage.sections(sections); } @Override - public void lightSections(LongSet sections) { - lightStorage.sections(sections); + public void delete() { + drawManager.delete(); + lightStorage.delete(); } public Instancer instancer(Environment environment, InstanceType type, Model model, RenderStage stage) { @@ -150,7 +150,7 @@ public class EngineImpl implements Engine { @Override public VisualEmbedding createEmbedding() { - var out = new TopLevelEmbeddedEnvironment(EngineImpl.this, stage); + var out = new EmbeddedEnvironment(EngineImpl.this, stage); environmentStorage.track(out); return out; } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EnvironmentStorage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EnvironmentStorage.java deleted file mode 100644 index e68ea5250..000000000 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/EnvironmentStorage.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.engine_room.flywheel.backend.engine; - -import dev.engine_room.flywheel.backend.engine.embed.AbstractEmbeddedEnvironment; -import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -import it.unimi.dsi.fastutil.objects.ReferenceSet; -import it.unimi.dsi.fastutil.objects.ReferenceSets; - -public class EnvironmentStorage { - protected final ReferenceSet environments = ReferenceSets.synchronize(new ReferenceLinkedOpenHashSet<>()); - - public void track(AbstractEmbeddedEnvironment environment) { - environments.add(environment); - } - - public void flush() { - environments.removeIf(AbstractEmbeddedEnvironment::isDeleted); - environments.forEach(AbstractEmbeddedEnvironment::flush); - } -} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightLut.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java similarity index 96% rename from common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightLut.java rename to common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java index 736811c5a..bb04c7760 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightLut.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java @@ -1,4 +1,4 @@ -package dev.engine_room.flywheel.backend.engine.embed; +package dev.engine_room.flywheel.backend.engine; import org.jetbrains.annotations.NotNull; @@ -11,8 +11,8 @@ import it.unimi.dsi.fastutil.longs.LongComparator; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import net.minecraft.core.SectionPos; -public class LightLut { - public static final LongComparator SECTION_X_THEN_Y_THEN_Z = (long a, long b) -> { +public final class LightLut { + private static final LongComparator SECTION_X_THEN_Y_THEN_Z = (long a, long b) -> { final var xComp = Integer.compare(SectionPos.x(a), SectionPos.x(b)); if (xComp != 0) { return xComp; @@ -24,6 +24,8 @@ public class LightLut { return Integer.compare(SectionPos.z(a), SectionPos.z(b)); }; + private LightLut() { + } // Massive kudos to RogueLogix for figuring out this LUT scheme. // TODO: switch to y x z or x z y ordering diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightStorage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java similarity index 99% rename from common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightStorage.java rename to common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java index 90f551e9a..909dbdb95 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/LightStorage.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java @@ -1,4 +1,4 @@ -package dev.engine_room.flywheel.backend.engine.embed; +package dev.engine_room.flywheel.backend.engine; import java.util.BitSet; @@ -7,6 +7,7 @@ import org.lwjgl.system.MemoryUtil; import dev.engine_room.flywheel.api.event.RenderContext; import dev.engine_room.flywheel.api.task.Plan; +import dev.engine_room.flywheel.backend.LightUpdateHolder; import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer; import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer; import dev.engine_room.flywheel.lib.task.SimplePlan; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/AbstractEmbeddedEnvironment.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddedEnvironment.java similarity index 70% rename from common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/AbstractEmbeddedEnvironment.java rename to common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddedEnvironment.java index 6bf89450c..fef623172 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/AbstractEmbeddedEnvironment.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddedEnvironment.java @@ -1,5 +1,6 @@ package dev.engine_room.flywheel.backend.engine.embed; +import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix3fc; import org.joml.Matrix4f; @@ -17,61 +18,44 @@ import dev.engine_room.flywheel.backend.engine.EngineImpl; import dev.engine_room.flywheel.backend.gl.shader.GlProgram; import net.minecraft.core.Vec3i; -public abstract class AbstractEmbeddedEnvironment implements Environment, VisualEmbedding { - protected final Matrix4f pose = new Matrix4f(); - protected final Matrix3f normal = new Matrix3f(); +public class EmbeddedEnvironment implements VisualEmbedding, Environment { + private final EngineImpl engine; + private final RenderStage renderStage; + @Nullable + private final EmbeddedEnvironment parent; + private final InstancerProvider instancerProvider; + + private final Matrix4f pose = new Matrix4f(); + private final Matrix3f normal = new Matrix3f(); private final Matrix4f poseComposed = new Matrix4f(); private final Matrix3f normalComposed = new Matrix3f(); - private final InstancerProvider instancerProvider; - protected final EngineImpl engine; - private final RenderStage renderStage; private boolean deleted = false; - public AbstractEmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) { + public EmbeddedEnvironment(EngineImpl engine, RenderStage renderStage, @Nullable EmbeddedEnvironment parent) { this.engine = engine; this.renderStage = renderStage; + this.parent = parent; instancerProvider = new InstancerProvider() { @Override public Instancer instancer(InstanceType type, Model model) { // Kinda cursed usage of anonymous classes here, but it does the job. - return engine.instancer(AbstractEmbeddedEnvironment.this, type, model, renderStage); + return engine.instancer(EmbeddedEnvironment.this, type, model, renderStage); } }; } + public EmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) { + this(engine, renderStage, null); + } + @Override public void transforms(Matrix4fc pose, Matrix3fc normal) { this.pose.set(pose); this.normal.set(normal); } - public void flush() { - poseComposed.identity(); - normalComposed.identity(); - - composeMatrices(poseComposed, normalComposed); - } - - @Override - public void setupDraw(GlProgram program) { - program.setMat4(EmbeddingUniforms.MODEL_MATRIX, poseComposed); - program.setMat3(EmbeddingUniforms.NORMAL_MATRIX, normalComposed); - } - - @Override - public void setupCull(GlProgram program) { - program.setBool(EmbeddingUniforms.USE_MODEL_MATRIX, true); - - program.setMat4(EmbeddingUniforms.MODEL_MATRIX1, poseComposed); - } - - @Override - public ContextShader contextShader() { - return ContextShader.EMBEDDED; - } - @Override public InstancerProvider instancerProvider() { return instancerProvider; @@ -84,12 +68,47 @@ public abstract class AbstractEmbeddedEnvironment implements Environment, Visual @Override public VisualEmbedding createEmbedding() { - var out = new NestedEmbeddedEnvironment(this, engine, renderStage); + var out = new EmbeddedEnvironment(engine, renderStage, this); engine.environmentStorage() .track(out); return out; } + @Override + public ContextShader contextShader() { + return ContextShader.EMBEDDED; + } + + @Override + public void setupCull(GlProgram program) { + program.setBool(EmbeddingUniforms.USE_MODEL_MATRIX, true); + program.setMat4(EmbeddingUniforms.MODEL_MATRIX, poseComposed); + } + + @Override + public void setupDraw(GlProgram program) { + program.setMat4(EmbeddingUniforms.MODEL_MATRIX, poseComposed); + program.setMat3(EmbeddingUniforms.NORMAL_MATRIX, normalComposed); + } + + public void flush() { + poseComposed.identity(); + normalComposed.identity(); + + composeMatrices(poseComposed, normalComposed); + } + + private void composeMatrices(Matrix4f pose, Matrix3f normal) { + if (parent != null) { + parent.composeMatrices(pose, normal); + pose.mul(this.pose); + normal.mul(this.normal); + } else { + pose.set(this.pose); + normal.set(this.normal); + } + } + public boolean isDeleted() { return deleted; } @@ -101,6 +120,4 @@ public abstract class AbstractEmbeddedEnvironment implements Environment, Visual public void delete() { deleted = true; } - - public abstract void composeMatrices(Matrix4f pose, Matrix3f normal); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddingUniforms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddingUniforms.java index eb0c58bef..e62f0b018 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddingUniforms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EmbeddingUniforms.java @@ -1,11 +1,13 @@ package dev.engine_room.flywheel.backend.engine.embed; -public class EmbeddingUniforms { +public final class EmbeddingUniforms { + /** + * Only used by cull shaders. + */ + public static final String USE_MODEL_MATRIX = "_flw_useModelMatrix"; public static final String MODEL_MATRIX = "_flw_modelMatrix"; public static final String NORMAL_MATRIX = "_flw_normalMatrix"; - public static final String USE_MODEL_MATRIX = "_flw_useModelMatrix"; - public static final String MODEL_MATRIX1 = "_flw_modelMatrix"; - public static final String ONE_OVER_LIGHT_BOX_SIZE = "_flw_oneOverLightBoxSize"; - public static final String LIGHT_VOLUME_MIN = "_flw_lightVolumeMin"; - public static final String USE_LIGHT_VOLUME = "_flw_useLightVolume"; + + private EmbeddingUniforms() { + } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Environment.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Environment.java index 626f103e5..83fa60d62 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Environment.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/Environment.java @@ -6,7 +6,7 @@ import dev.engine_room.flywheel.backend.gl.shader.GlProgram; public interface Environment { ContextShader contextShader(); - void setupDraw(GlProgram drawProgram); - void setupCull(GlProgram cullProgram); + + void setupDraw(GlProgram drawProgram); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EnvironmentStorage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EnvironmentStorage.java new file mode 100644 index 000000000..9206b9cf3 --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/EnvironmentStorage.java @@ -0,0 +1,18 @@ +package dev.engine_room.flywheel.backend.engine.embed; + +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import it.unimi.dsi.fastutil.objects.ReferenceSet; +import it.unimi.dsi.fastutil.objects.ReferenceSets; + +public class EnvironmentStorage { + protected final ReferenceSet environments = ReferenceSets.synchronize(new ReferenceLinkedOpenHashSet<>()); + + public void track(EmbeddedEnvironment environment) { + environments.add(environment); + } + + public void flush() { + environments.removeIf(EmbeddedEnvironment::isDeleted); + environments.forEach(EmbeddedEnvironment::flush); + } +} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/GlobalEnvironment.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/GlobalEnvironment.java index c6e50acbd..aaac1ca35 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/GlobalEnvironment.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/GlobalEnvironment.java @@ -14,13 +14,12 @@ public class GlobalEnvironment implements Environment { return ContextShader.DEFAULT; } - @Override - public void setupDraw(GlProgram drawProgram) { - - } - @Override public void setupCull(GlProgram cullProgram) { cullProgram.setBool(EmbeddingUniforms.USE_MODEL_MATRIX, false); } + + @Override + public void setupDraw(GlProgram drawProgram) { + } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/NestedEmbeddedEnvironment.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/NestedEmbeddedEnvironment.java deleted file mode 100644 index fb4bfbb49..000000000 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/NestedEmbeddedEnvironment.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.engine_room.flywheel.backend.engine.embed; - -import org.joml.Matrix3f; -import org.joml.Matrix4f; - -import dev.engine_room.flywheel.api.event.RenderStage; -import dev.engine_room.flywheel.backend.engine.EngineImpl; - -public class NestedEmbeddedEnvironment extends AbstractEmbeddedEnvironment { - private final AbstractEmbeddedEnvironment parent; - - public NestedEmbeddedEnvironment(AbstractEmbeddedEnvironment parent, EngineImpl engine, RenderStage renderStage) { - super(engine, renderStage); - this.parent = parent; - } - - @Override - public void composeMatrices(Matrix4f pose, Matrix3f normal) { - parent.composeMatrices(pose, normal); - pose.mul(this.pose); - normal.mul(this.normal); - } -} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/TopLevelEmbeddedEnvironment.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/TopLevelEmbeddedEnvironment.java deleted file mode 100644 index 297c3dd6b..000000000 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/embed/TopLevelEmbeddedEnvironment.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.engine_room.flywheel.backend.engine.embed; - -import org.joml.Matrix3f; -import org.joml.Matrix4f; - -import dev.engine_room.flywheel.api.event.RenderStage; -import dev.engine_room.flywheel.backend.engine.EngineImpl; - -public class TopLevelEmbeddedEnvironment extends AbstractEmbeddedEnvironment { - public TopLevelEmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) { - super(engine, renderStage); - } - - @Override - public void composeMatrices(Matrix4f pose, Matrix3f normal) { - pose.set(this.pose); - normal.set(this.normal); - } -} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/BufferBindings.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/BufferBindings.java index 97970f3b5..a0ae93a28 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/BufferBindings.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/BufferBindings.java @@ -1,13 +1,13 @@ package dev.engine_room.flywheel.backend.engine.indirect; -public class BufferBindings { - public static final int INSTANCE_BUFFER_BINDING = 0; - public static final int TARGET_BUFFER_BINDING = 1; - public static final int MODEL_INDEX_BUFFER_BINDING = 2; - public static final int MODEL_BUFFER_BINDING = 3; - public static final int DRAW_BUFFER_BINDING = 4; - public static final int LIGHT_LUT_BINDING = 5; - public static final int LIGHT_SECTION_BINDING = 6; +public final class BufferBindings { + public static final int INSTANCE = 0; + public static final int TARGET = 1; + public static final int MODEL_INDEX = 2; + public static final int MODEL = 3; + public static final int DRAW = 4; + public static final int LIGHT_LUT = 5; + public static final int LIGHT_SECTION = 6; private BufferBindings() { } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java index 68034d16a..90ecd4149 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectBuffers.java @@ -110,7 +110,7 @@ public class IndirectBuffers { private void multiBind() { final long ptr = multiBindBlock.ptr(); - nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET); + nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET); } /** @@ -118,7 +118,7 @@ public class IndirectBuffers { */ public void bindForCrumbling() { final long ptr = multiBindBlock.ptr(); - nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET); + nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET); } public void delete() { diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java index 1aadae5a3..d9ef2254a 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java @@ -20,10 +20,10 @@ import dev.engine_room.flywheel.backend.engine.CommonCrumbling; import dev.engine_room.flywheel.backend.engine.DrawManager; import dev.engine_room.flywheel.backend.engine.GroupKey; import dev.engine_room.flywheel.backend.engine.InstancerKey; +import dev.engine_room.flywheel.backend.engine.LightStorage; import dev.engine_room.flywheel.backend.engine.MaterialRenderState; import dev.engine_room.flywheel.backend.engine.MeshPool; import dev.engine_room.flywheel.backend.engine.TextureBinder; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.backend.gl.GlStateTracker; import dev.engine_room.flywheel.backend.gl.array.GlVertexArray; @@ -40,18 +40,15 @@ public class IndirectDrawManager extends DrawManager> { private final GlVertexArray vertexArray; private final Map, IndirectCullingGroup> cullingGroups = new HashMap<>(); private final GlBuffer crumblingDrawBuffer = new GlBuffer(); - private final LightBuffers lightBuffers; public IndirectDrawManager(IndirectPrograms programs) { this.programs = programs; programs.acquire(); + stagingBuffer = new StagingBuffer(this.programs); - meshPool = new MeshPool(); - vertexArray = GlVertexArray.create(); - meshPool.bind(vertexArray); lightBuffers = new LightBuffers(); } @@ -170,7 +167,7 @@ public class IndirectDrawManager extends DrawManager> { var block = MemoryBlock.malloc(IndirectBuffers.DRAW_COMMAND_STRIDE); GlBufferType.DRAW_INDIRECT_BUFFER.bind(crumblingDrawBuffer.handle()); - glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.DRAW_BUFFER_BINDING, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE); + glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.DRAW, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE); for (var groupEntry : byType.entrySet()) { var byProgress = groupEntry.getValue(); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/LightBuffers.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/LightBuffers.java index 2423ae0fb..9db63afb0 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/LightBuffers.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/LightBuffers.java @@ -3,14 +3,11 @@ package dev.engine_room.flywheel.backend.engine.indirect; import org.lwjgl.opengl.GL46; import org.lwjgl.system.MemoryUtil; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; +import dev.engine_room.flywheel.backend.engine.LightStorage; public class LightBuffers { - private final ResizableStorageArray sections = new ResizableStorageArray(LightStorage.SECTION_SIZE_BYTES); private final ResizableStorageArray lut = new ResizableStorageArray(4); - - public LightBuffers() { - } + private final ResizableStorageArray sections = new ResizableStorageArray(LightStorage.SECTION_SIZE_BYTES); public void flush(StagingBuffer staging, LightStorage light) { var capacity = light.capacity(); @@ -40,7 +37,7 @@ public class LightBuffers { return; } - GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.LIGHT_LUT_BINDING, lut.handle(), 0, lut.byteCapacity()); - GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.LIGHT_SECTION_BINDING, sections.handle(), 0, sections.byteCapacity()); + GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.LIGHT_LUT, lut.handle(), 0, lut.byteCapacity()); + GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.LIGHT_SECTION, sections.handle(), 0, sections.byteCapacity()); } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java index 6ea923cc1..ae231de0b 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java @@ -18,11 +18,11 @@ import dev.engine_room.flywheel.backend.engine.CommonCrumbling; import dev.engine_room.flywheel.backend.engine.DrawManager; import dev.engine_room.flywheel.backend.engine.GroupKey; import dev.engine_room.flywheel.backend.engine.InstancerKey; +import dev.engine_room.flywheel.backend.engine.LightStorage; import dev.engine_room.flywheel.backend.engine.MaterialEncoder; import dev.engine_room.flywheel.backend.engine.MaterialRenderState; import dev.engine_room.flywheel.backend.engine.MeshPool; import dev.engine_room.flywheel.backend.engine.TextureBinder; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.backend.gl.GlStateTracker; import dev.engine_room.flywheel.backend.gl.TextureBuffer; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedLight.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedLight.java index 3d966f0c8..7831019d1 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedLight.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedLight.java @@ -4,7 +4,7 @@ import org.lwjgl.opengl.GL32; import org.lwjgl.system.MemoryUtil; import dev.engine_room.flywheel.backend.Samplers; -import dev.engine_room.flywheel.backend.engine.embed.LightStorage; +import dev.engine_room.flywheel.backend.engine.LightStorage; import dev.engine_room.flywheel.backend.gl.TextureBuffer; import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer; import dev.engine_room.flywheel.lib.memory.MemoryBlock; @@ -16,8 +16,8 @@ public class InstancedLight { private final TextureBuffer sectionsTexture; public InstancedLight() { - sections = new GlBuffer(); lut = new GlBuffer(); + sections = new GlBuffer(); lutTexture = new TextureBuffer(GL32.GL_R32UI); sectionsTexture = new TextureBuffer(GL32.GL_R32UI); } @@ -54,8 +54,8 @@ public class InstancedLight { } public void delete() { - sections.delete(); lut.delete(); + sections.delete(); lutTexture.delete(); sectionsTexture.delete(); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/ClientChunkCacheMixin.java b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/ClientChunkCacheMixin.java index 11ea0cea2..eb8c974ec 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/ClientChunkCacheMixin.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/ClientChunkCacheMixin.java @@ -7,7 +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 dev.engine_room.flywheel.backend.engine.embed.LightUpdateHolder; +import dev.engine_room.flywheel.backend.LightUpdateHolder; import net.minecraft.client.multiplayer.ClientChunkCache; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.SectionPos; diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/buffer_bindings.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/buffer_bindings.glsl index 604da5269..c37db3502 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/buffer_bindings.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/buffer_bindings.glsl @@ -3,5 +3,5 @@ #define _FLW_MODEL_INDEX_BUFFER_BINDING 2 #define _FLW_MODEL_BUFFER_BINDING 3 #define _FLW_DRAW_BUFFER_BINDING 4 -#define _FLW_LIGHT_LUT_BINDING 5 -#define _FLW_LIGHT_SECTIONS_BINDING 6 +#define _FLW_LIGHT_LUT_BUFFER_BINDING 5 +#define _FLW_LIGHT_SECTIONS_BUFFER_BINDING 6 diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/light.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/light.glsl index bd688ef28..48975050e 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/light.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/light.glsl @@ -1,10 +1,10 @@ #include "flywheel:internal/light_lut.glsl" -layout(std430, binding = _FLW_LIGHT_LUT_BINDING) restrict readonly buffer LightLut { +layout(std430, binding = _FLW_LIGHT_LUT_BUFFER_BINDING) restrict readonly buffer LightLut { uint _flw_lightLut[]; }; -layout(std430, binding = _FLW_LIGHT_SECTIONS_BINDING) restrict readonly buffer LightSections { +layout(std430, binding = _FLW_LIGHT_SECTIONS_BUFFER_BINDING) restrict readonly buffer LightSections { uint _flw_lightSections[]; }; diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/mixin/ClientChunkCacheMixin.java b/common/src/main/java/dev/engine_room/flywheel/impl/mixin/ClientChunkCacheMixin.java index d12415179..f55d6d2e9 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/mixin/ClientChunkCacheMixin.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/mixin/ClientChunkCacheMixin.java @@ -24,7 +24,7 @@ abstract class ClientChunkCacheMixin { var manager = VisualizationManagerImpl.get(level); if (manager != null) { - manager.enqueueLightUpdateSection(pos.asLong()); + manager.onLightUpdate(pos.asLong()); } } } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/VisualizationManagerImpl.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/VisualizationManagerImpl.java index efd5c6820..ccf69cc0e 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/VisualizationManagerImpl.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/VisualizationManagerImpl.java @@ -106,11 +106,11 @@ public class VisualizationManagerImpl implements VisualizationManager { .ifFalse(update) .plan() .then(SimplePlan.of(() -> { - if (blockEntities.lightSectionsDirty() || entities.lightSectionsDirty() || effects.lightSectionsDirty()) { + if (blockEntities.areGpuLightSectionsDirty() || entities.areGpuLightSectionsDirty() || effects.areGpuLightSectionsDirty()) { var out = new LongOpenHashSet(); - out.addAll(blockEntities.lightSections()); - out.addAll(entities.lightSections()); - out.addAll(effects.lightSections()); + out.addAll(blockEntities.gpuLightSections()); + out.addAll(entities.gpuLightSections()); + out.addAll(effects.gpuLightSections()); engine.lightSections(out); } })) @@ -302,6 +302,12 @@ public class VisualizationManagerImpl implements VisualizationManager { } } + public void onLightUpdate(long section) { + blockEntities.onLightUpdate(section); + entities.onLightUpdate(section); + effects.onLightUpdate(section); + } + /** * Free all acquired resources and delete this manager. */ @@ -315,13 +321,4 @@ public class VisualizationManagerImpl implements VisualizationManager { effects.invalidate(); engine.delete(); } - - public void enqueueLightUpdateSection(long section) { - blockEntities.getStorage() - .enqueueLightUpdateSection(section); - entities.getStorage() - .enqueueLightUpdateSection(section); - effects.getStorage() - .enqueueLightUpdateSection(section); - } } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java index db465f461..d3d065c5c 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java @@ -69,8 +69,20 @@ public class BlockEntityStorage extends Storage { @Override public void remove(BlockEntity obj) { - super.remove(obj); posLookup.remove(obj.getBlockPos() .asLong()); + super.remove(obj); + } + + @Override + public void recreateAll(float partialTick) { + posLookup.clear(); + super.recreateAll(partialTick); + } + + @Override + public void invalidate() { + posLookup.clear(); + super.invalidate(); } } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/VisualManagerImpl.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/VisualManagerImpl.java index e8c0b88c9..f0d3420bb 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/VisualManagerImpl.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/VisualManagerImpl.java @@ -54,10 +54,6 @@ public class VisualManagerImpl> implements VisualManager queue.add(Transaction.update(obj)); } - public void invalidate() { - getStorage().invalidate(); - } - public void processQueue(float partialTick) { var storage = getStorage(); Transaction transaction; @@ -76,13 +72,22 @@ public class VisualManagerImpl> implements VisualManager .then(storage.tickPlan()); } - public boolean lightSectionsDirty() { - return getStorage().smoothLitStorage() - .sectionsDirty(); + public void onLightUpdate(long section) { + getStorage().lightUpdatedVisuals() + .onLightUpdate(section); } - public LongSet lightSections() { - return getStorage().smoothLitStorage() + public boolean areGpuLightSectionsDirty() { + return getStorage().shaderLightVisuals() + .isDirty(); + } + + public LongSet gpuLightSections() { + return getStorage().shaderLightVisuals() .sections(); } + + public void invalidate() { + getStorage().invalidate(); + } } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedVisualStorage.java similarity index 74% rename from common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedStorage.java rename to common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedVisualStorage.java index d2df21868..3f730abc0 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LightUpdatedVisualStorage.java @@ -16,7 +16,6 @@ import dev.engine_room.flywheel.lib.task.SimplyComposedPlan; import dev.engine_room.flywheel.lib.task.Synchronizer; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -24,15 +23,15 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; /** * Keeps track of what chunks/sections each listener is in, so we can update exactly what needs to be updated. */ -public class LightUpdatedStorage { +public class LightUpdatedVisualStorage { private static final long NEVER_UPDATED = Long.MIN_VALUE; private static final long INITIAL_UPDATE_ID = NEVER_UPDATED + 1; - private final Map visuals2Sections = new WeakHashMap<>(); - private final Long2ObjectMap> sections2Visuals = new Long2ObjectOpenHashMap<>(); + private final Map visual2Sections = new WeakHashMap<>(); + private final Long2ObjectMap> section2Updaters = new Long2ObjectOpenHashMap<>(); - private final Queue movedVisuals = new ConcurrentLinkedQueue<>(); private final LongSet sectionsUpdatedThisFrame = new LongOpenHashSet(); + private final Queue movedVisuals = new ConcurrentLinkedQueue<>(); private long updateId = INITIAL_UPDATE_ID; @@ -54,9 +53,9 @@ public class LightUpdatedStorage { Updater.Context updaterContext = new Updater.Context(updateId, context.partialTick()); for (long section : sectionsUpdatedThisFrame) { - var visuals = sections2Visuals.get(section); - if (visuals != null && !visuals.isEmpty()) { - taskExecutor.execute(() -> Distribute.tasks(taskExecutor, updaterContext, sync, visuals, Updater::updateLight)); + var updaters = section2Updaters.get(section); + if (updaters != null && !updaters.isEmpty()) { + taskExecutor.execute(() -> Distribute.tasks(taskExecutor, updaterContext, sync, updaters, Updater::updateLight)); } else { sync.decrementAndEventuallyRun(); } @@ -69,7 +68,7 @@ public class LightUpdatedStorage { while ((moved = movedVisuals.poll()) != null) { // If the visual isn't there when we try to remove it that means it was deleted before we got to it. if (remove(moved.visual)) { - updateTracking(moved.tracker, moved.visual); + addInner(moved.visual, moved.tracker); } } } @@ -86,43 +85,32 @@ public class LightUpdatedStorage { return out; } - public boolean isEmpty() { - return visuals2Sections.isEmpty(); - } - - public void add(SectionCollectorImpl tracker, LightUpdatedVisual visual) { - var moved = new MovedVisual(tracker, visual); + public void add(LightUpdatedVisual visual, SectionTracker tracker) { + var moved = new MovedVisual(visual, tracker); tracker.addListener(() -> movedVisuals.add(moved)); - updateTracking(tracker, visual); + addInner(visual, tracker); } - public void updateTracking(SectionCollectorImpl tracker, LightUpdatedVisual visual) { - if (tracker.sections.isEmpty()) { + private void addInner(LightUpdatedVisual visual, SectionTracker tracker) { + if (tracker.sections().isEmpty()) { // Add the visual to the map even if sections is empty, this way we can distinguish from deleted visuals - visuals2Sections.put(visual, LongSet.of()); + visual2Sections.put(visual, LongSet.of()); // Don't bother creating an updater if the visual isn't in any sections. return; } - // Create a copy of the array, so we know what section to remove the visual from later. - var sections = new LongArraySet(tracker.sections); - - visuals2Sections.put(visual, sections); - + var sections = tracker.sections(); + visual2Sections.put(visual, sections); var updater = createUpdater(visual, sections.size()); for (long section : sections) { - sections2Visuals.computeIfAbsent(section, $ -> new ObjectArrayList<>()) + section2Updaters.computeIfAbsent(section, $ -> new ObjectArrayList<>()) .add(updater); } } - public void enqueueLightUpdateSection(long section) { - sectionsUpdatedThisFrame.add(section); - } - /** * Remove the visual from this storage. * @@ -130,31 +118,36 @@ public class LightUpdatedStorage { * @return {@code true} if the visual was removed, {@code false} otherwise. */ public boolean remove(LightUpdatedVisual visual) { - var sections = visuals2Sections.remove(visual); + var sections = visual2Sections.remove(visual); if (sections == null) { return false; } for (long section : sections) { - List listeners = sections2Visuals.get(section); - if (listeners != null) { - listeners.remove(indexOfUpdater(listeners, visual)); + List updaters = section2Updaters.get(section); + if (updaters != null) { + updaters.remove(indexOfUpdater(updaters, visual)); } } return true; } - public void clear() { - visuals2Sections.clear(); - sections2Visuals.clear(); - sectionsUpdatedThisFrame.clear(); + public void onLightUpdate(long section) { + sectionsUpdatedThisFrame.add(section); } - private static int indexOfUpdater(List listeners, LightUpdatedVisual visual) { - for (int i = 0; i < listeners.size(); i++) { - if (listeners.get(i) + public void clear() { + visual2Sections.clear(); + section2Updaters.clear(); + sectionsUpdatedThisFrame.clear(); + movedVisuals.clear(); + } + + private static int indexOfUpdater(List updaters, LightUpdatedVisual visual) { + for (int i = 0; i < updaters.size(); i++) { + if (updaters.get(i) .visual() == visual) { return i; } @@ -171,7 +164,7 @@ public class LightUpdatedStorage { } // Breaking this into 2 separate cases allows us to avoid the overhead of atomics in the common case. - sealed interface Updater { + private sealed interface Updater { void updateLight(Context ctx); LightUpdatedVisual visual(); @@ -201,6 +194,6 @@ public class LightUpdatedStorage { } } - private record MovedVisual(SectionCollectorImpl tracker, LightUpdatedVisual visual) { + private record MovedVisual(LightUpdatedVisual visual, SectionTracker tracker) { } } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionCollectorImpl.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionTracker.java similarity index 58% rename from common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionCollectorImpl.java rename to common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionTracker.java index faa1d7b45..9cba32f69 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionCollectorImpl.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/SectionTracker.java @@ -3,20 +3,27 @@ package dev.engine_room.flywheel.impl.visualization.storage; import java.util.ArrayList; import java.util.List; +import org.jetbrains.annotations.Unmodifiable; + import dev.engine_room.flywheel.api.visual.SectionTrackedVisual; import it.unimi.dsi.fastutil.longs.LongArraySet; import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.longs.LongSets; -public class SectionCollectorImpl implements SectionTrackedVisual.SectionCollector { - public final LongSet sections = new LongArraySet(); - +public class SectionTracker implements SectionTrackedVisual.SectionCollector { private final List listeners = new ArrayList<>(2); + @Unmodifiable + private LongSet sections = LongSet.of(); + + @Unmodifiable + public LongSet sections() { + return sections; + } + @Override public void sections(LongSet sections) { - this.sections.clear(); - this.sections.addAll(sections); - + this.sections = LongSets.unmodifiable(new LongArraySet(sections)); listeners.forEach(Runnable::run); } diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightStorage.java deleted file mode 100644 index c51a55467..000000000 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightStorage.java +++ /dev/null @@ -1,52 +0,0 @@ -package dev.engine_room.flywheel.impl.visualization.storage; - -import java.util.Map; - -import org.jetbrains.annotations.Nullable; - -import dev.engine_room.flywheel.api.visual.ShaderLightVisual; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; -import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; - -public class ShaderLightStorage { - private final Map visuals = new Reference2ObjectOpenHashMap<>(); - - @Nullable - private LongSet cachedSections; - - public boolean sectionsDirty() { - return cachedSections == null; - } - - public void markDirty() { - cachedSections = null; - } - - public LongSet sections() { - cachedSections = new LongOpenHashSet(); - for (var value : visuals.values()) { - cachedSections.addAll(value.sections); - } - return cachedSections; - } - - public void remove(ShaderLightVisual visual) { - visuals.remove(visual); - } - - public void add(SectionCollectorImpl tracker, ShaderLightVisual visual) { - visuals.put(visual, tracker); - - tracker.addListener(this::markDirty); - - if (!tracker.sections.isEmpty()) { - markDirty(); - } - } - - public void clear() { - visuals.clear(); - } - -} diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java new file mode 100644 index 000000000..052a9e06c --- /dev/null +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java @@ -0,0 +1,53 @@ +package dev.engine_room.flywheel.impl.visualization.storage; + +import java.util.Map; + +import dev.engine_room.flywheel.api.visual.ShaderLightVisual; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; + +public class ShaderLightVisualStorage { + private final Map trackers = new Reference2ReferenceOpenHashMap<>(); + + private final LongSet sections = new LongOpenHashSet(); + private boolean isDirty; + + public LongSet sections() { + if (isDirty) { + sections.clear(); + for (var tracker : trackers.values()) { + sections.addAll(tracker.sections()); + } + isDirty = false; + } + return sections; + } + + public boolean isDirty() { + return isDirty; + } + + public void markDirty() { + isDirty = true; + } + + public void add(ShaderLightVisual visual, SectionTracker tracker) { + trackers.put(visual, tracker); + + tracker.addListener(this::markDirty); + + if (!tracker.sections().isEmpty()) { + markDirty(); + } + } + + public void remove(ShaderLightVisual visual) { + trackers.remove(visual); + } + + public void clear() { + trackers.clear(); + markDirty(); + } +} diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java index f219e9138..4e2d1ebaf 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java @@ -25,14 +25,14 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; public abstract class Storage { protected final Supplier visualizationContextSupplier; + + private final Map visuals = new Reference2ObjectOpenHashMap<>(); protected final PlanMap dynamicVisuals = new PlanMap<>(); protected final PlanMap tickableVisuals = new PlanMap<>(); protected final List simpleDynamicVisuals = new ArrayList<>(); protected final List simpleTickableVisuals = new ArrayList<>(); - protected final LightUpdatedStorage litVisuals = new LightUpdatedStorage(); - protected final ShaderLightStorage smoothLitVisuals = new ShaderLightStorage(); - - private final Map visuals = new Reference2ObjectOpenHashMap<>(); + protected final LightUpdatedVisualStorage lightUpdatedVisuals = new LightUpdatedVisualStorage(); + protected final ShaderLightVisualStorage shaderLightVisuals = new ShaderLightVisualStorage(); public Storage(Supplier visualizationContextSupplier) { this.visualizationContextSupplier = visualizationContextSupplier; @@ -42,6 +42,29 @@ public abstract class Storage { return visuals.values(); } + public Plan framePlan() { + return NestedPlan.of(dynamicVisuals, lightUpdatedVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame)); + } + + public Plan tickPlan() { + return NestedPlan.of(tickableVisuals, ForEachPlan.of(() -> simpleTickableVisuals, SimpleTickableVisual::tick)); + } + + public LightUpdatedVisualStorage lightUpdatedVisuals() { + return lightUpdatedVisuals; + } + + public ShaderLightVisualStorage shaderLightVisuals() { + return shaderLightVisuals; + } + + /** + * Is the given object currently capable of being added? + * + * @return true if the object is currently capable of being visualized. + */ + public abstract boolean willAccept(T obj); + public void add(T obj, float partialTick) { Visual visual = visuals.get(obj); @@ -57,13 +80,6 @@ public abstract class Storage { return; } - if (visual instanceof TickableVisual tickable) { - if (visual instanceof SimpleTickableVisual simpleTickable) { - simpleTickableVisuals.remove(simpleTickable); - } else { - tickableVisuals.remove(tickable); - } - } if (visual instanceof DynamicVisual dynamic) { if (visual instanceof SimpleDynamicVisual simpleDynamic) { simpleDynamicVisuals.remove(simpleDynamic); @@ -71,12 +87,20 @@ public abstract class Storage { dynamicVisuals.remove(dynamic); } } - if (visual instanceof LightUpdatedVisual lit) { - litVisuals.remove(lit); + if (visual instanceof TickableVisual tickable) { + if (visual instanceof SimpleTickableVisual simpleTickable) { + simpleTickableVisuals.remove(simpleTickable); + } else { + tickableVisuals.remove(tickable); + } } - if (visual instanceof ShaderLightVisual smoothLit) { - smoothLitVisuals.remove(smoothLit); + if (visual instanceof LightUpdatedVisual lightUpdated) { + lightUpdatedVisuals.remove(lightUpdated); } + if (visual instanceof ShaderLightVisual shaderLight) { + shaderLightVisuals.remove(shaderLight); + } + visual.delete(); } @@ -91,12 +115,13 @@ public abstract class Storage { } public void recreateAll(float partialTick) { - tickableVisuals.clear(); dynamicVisuals.clear(); - simpleTickableVisuals.clear(); + tickableVisuals.clear(); simpleDynamicVisuals.clear(); - litVisuals.clear(); - smoothLitVisuals.clear(); + simpleTickableVisuals.clear(); + lightUpdatedVisuals.clear(); + shaderLightVisuals.clear(); + visuals.replaceAll((obj, visual) -> { visual.delete(); @@ -110,15 +135,6 @@ public abstract class Storage { }); } - public void invalidate() { - tickableVisuals.clear(); - dynamicVisuals.clear(); - litVisuals.clear(); - visuals.values() - .forEach(Visual::delete); - visuals.clear(); - } - private void create(T obj, float partialTick) { var visual = createRaw(obj, partialTick); @@ -131,27 +147,7 @@ public abstract class Storage { @Nullable protected abstract Visual createRaw(T obj, float partialTick); - public Plan framePlan() { - return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame)); - } - - public Plan tickPlan() { - return NestedPlan.of(tickableVisuals, ForEachPlan.of(() -> simpleTickableVisuals, SimpleTickableVisual::tick)); - } - - public void enqueueLightUpdateSection(long section) { - litVisuals.enqueueLightUpdateSection(section); - } - private void setup(Visual visual) { - if (visual instanceof TickableVisual tickable) { - if (visual instanceof SimpleTickableVisual simpleTickable) { - simpleTickableVisuals.add(simpleTickable); - } else { - tickableVisuals.add(tickable, tickable.planTick()); - } - } - if (visual instanceof DynamicVisual dynamic) { if (visual instanceof SimpleDynamicVisual simpleDynamic) { simpleDynamicVisuals.add(simpleDynamic); @@ -160,30 +156,39 @@ public abstract class Storage { } } - if (visual instanceof SectionTrackedVisual tracked) { - SectionCollectorImpl sectionProperty = new SectionCollectorImpl(); + if (visual instanceof TickableVisual tickable) { + if (visual instanceof SimpleTickableVisual simpleTickable) { + simpleTickableVisuals.add(simpleTickable); + } else { + tickableVisuals.add(tickable, tickable.planTick()); + } + } - // Give the visual a chance to fill in the property. - tracked.setSectionCollector(sectionProperty); + if (visual instanceof SectionTrackedVisual tracked) { + SectionTracker tracker = new SectionTracker(); + + // Give the visual a chance to invoke the collector. + tracked.setSectionCollector(tracker); if (visual instanceof LightUpdatedVisual lightUpdated) { - litVisuals.add(sectionProperty, lightUpdated); + lightUpdatedVisuals.add(lightUpdated, tracker); } if (visual instanceof ShaderLightVisual shaderLight) { - smoothLitVisuals.add(sectionProperty, shaderLight); + shaderLightVisuals.add(shaderLight, tracker); } } } - /** - * Is the given object currently capable of being added? - * - * @return true if the object is currently capable of being visualized. - */ - public abstract boolean willAccept(T obj); - - public ShaderLightStorage smoothLitStorage() { - return smoothLitVisuals; + public void invalidate() { + dynamicVisuals.clear(); + tickableVisuals.clear(); + simpleDynamicVisuals.clear(); + simpleTickableVisuals.clear(); + lightUpdatedVisuals.clear(); + shaderLightVisuals.clear(); + visuals.values() + .forEach(Visual::delete); + visuals.clear(); } } diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java index b0a72f0a7..873ff2bce 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java @@ -194,7 +194,7 @@ public class MinecartVisual extends SimpleEntityVisu body.setTransform(stack) .setChanged(); - // TODO: Use LitVisual if possible. + // TODO: Use LightUpdatedVisual/ShaderLightVisual if possible. updateLight(partialTick); }