diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
index 6b84b53ba..daa4fc311 100644
--- a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
+++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
@@ -48,4 +48,13 @@ public interface VisualEmbedding extends VisualizationContext {
* @param sizeZ The size of the box in the z direction.
*/
void invalidateLight(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ);
+
+ /**
+ * Delete this embedding.
+ *
+ *
After this method exits, the embedding will continue to function in the state it was in before
+ * this method was called. Once all child instancers are deleted, the resources owned by this embedding
+ * will be freed. Creating new instancers after calling this method will throw an error.
+ */
+ void delete();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backends.java b/src/main/java/com/jozufozu/flywheel/backend/Backends.java
index 132782e66..dc668de74 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/Backends.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/Backends.java
@@ -4,8 +4,9 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
-import com.jozufozu.flywheel.backend.engine.indirect.IndirectEngine;
-import com.jozufozu.flywheel.backend.engine.instancing.InstancingEngine;
+import com.jozufozu.flywheel.backend.engine.EngineImpl;
+import com.jozufozu.flywheel.backend.engine.indirect.IndirectDrawManager;
+import com.jozufozu.flywheel.backend.engine.instancing.InstancedDrawManager;
import com.jozufozu.flywheel.backend.gl.GlCompat;
import com.jozufozu.flywheel.lib.backend.SimpleBackend;
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
@@ -15,7 +16,7 @@ public final class Backends {
* Use GPU instancing to render everything.
*/
public static final Backend INSTANCING = SimpleBackend.builder()
- .engineFactory(level -> new InstancingEngine(InstancingPrograms.get(), 256))
+ .engineFactory(level -> new EngineImpl(new InstancedDrawManager(InstancingPrograms.get()), 256))
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsInstancing() && InstancingPrograms.allLoaded())
.register(Flywheel.rl("instancing"));
@@ -23,7 +24,7 @@ public final class Backends {
* Use Compute shaders to cull instances.
*/
public static final Backend INDIRECT = SimpleBackend.builder()
- .engineFactory(level -> new IndirectEngine(IndirectPrograms.get(), 256))
+ .engineFactory(level -> new EngineImpl(new IndirectDrawManager(IndirectPrograms.get()), 256))
.fallback(() -> Backends.INSTANCING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsIndirect() && IndirectPrograms.allLoaded())
.register(Flywheel.rl("indirect"));
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java
index 921c57e40..8dc46f6e9 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java
@@ -138,7 +138,7 @@ public class IndirectPrograms extends AtomicReferenceCounted {
}
@Override
- protected void delete() {
+ protected void _delete() {
pipeline.values()
.forEach(GlProgram::delete);
culling.values()
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java
index ee4924656..5a8589a66 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java
@@ -66,7 +66,7 @@ public class InstancingPrograms extends AtomicReferenceCounted {
}
@Override
- protected void delete() {
+ protected void _delete() {
pipeline.values()
.forEach(GlProgram::delete);
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java
deleted file mode 100644
index 2d529517a..000000000
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.jozufozu.flywheel.backend.engine;
-
-import com.jozufozu.flywheel.api.backend.Engine;
-import com.jozufozu.flywheel.api.event.RenderStage;
-import com.jozufozu.flywheel.api.instance.Instance;
-import com.jozufozu.flywheel.api.instance.InstanceType;
-import com.jozufozu.flywheel.api.instance.Instancer;
-import com.jozufozu.flywheel.api.instance.InstancerProvider;
-import com.jozufozu.flywheel.api.model.Model;
-import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
-import com.jozufozu.flywheel.api.visualization.VisualizationContext;
-import com.jozufozu.flywheel.backend.engine.embed.EmbeddedEnvironment;
-import com.jozufozu.flywheel.backend.engine.embed.Environment;
-
-import net.minecraft.client.Camera;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Vec3i;
-import net.minecraft.world.phys.Vec3;
-
-public abstract class AbstractEngine implements Engine {
- protected final int sqrMaxOriginDistance;
- protected BlockPos renderOrigin = BlockPos.ZERO;
-
- public AbstractEngine(int maxOriginDistance) {
- sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance;
- }
-
- public Instancer instancer(Environment environment, InstanceType type, Model model, RenderStage stage) {
- return getStorage().getInstancer(environment, type, model, stage);
- }
-
- @Override
- public VisualizationContext createVisualizationContext(RenderStage stage) {
- return new VisualizationContextImpl(stage);
- }
-
- @Override
- public boolean updateRenderOrigin(Camera camera) {
- Vec3 cameraPos = camera.getPosition();
- double dx = renderOrigin.getX() - cameraPos.x;
- double dy = renderOrigin.getY() - cameraPos.y;
- double dz = renderOrigin.getZ() - cameraPos.z;
- double distanceSqr = dx * dx + dy * dy + dz * dz;
-
- if (distanceSqr <= sqrMaxOriginDistance) {
- return false;
- }
-
- renderOrigin = BlockPos.containing(cameraPos);
- getStorage().onRenderOriginChanged();
- return true;
- }
-
- @Override
- public Vec3i renderOrigin() {
- return renderOrigin;
- }
-
- protected abstract InstancerStorage extends AbstractInstancer>> getStorage();
-
- private class VisualizationContextImpl implements VisualizationContext {
- private final InstancerProviderImpl instancerProvider;
- private final RenderStage stage;
-
- public VisualizationContextImpl(RenderStage stage) {
- instancerProvider = new InstancerProviderImpl(AbstractEngine.this, stage);
- this.stage = stage;
- }
-
- @Override
- public InstancerProvider instancerProvider() {
- return instancerProvider;
- }
-
- @Override
- public Vec3i renderOrigin() {
- return AbstractEngine.this.renderOrigin();
- }
-
- @Override
- public VisualEmbedding createEmbedding() {
- return new EmbeddedEnvironment(AbstractEngine.this, stage);
- }
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
index 84becc5bd..95fece409 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
@@ -25,6 +25,8 @@ public abstract class AbstractInstancer implements Instancer
protected AbstractInstancer(InstanceType type, Environment environment) {
this.type = type;
this.environment = environment;
+
+ environment.acquire();
}
@Override
@@ -159,6 +161,10 @@ public abstract class AbstractInstancer implements Instancer
deleted.clear();
}
+ public void delete() {
+ environment.release();
+ }
+
@Override
public String toString() {
return "AbstractInstancer[" + instanceCount() + ']';
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java b/src/main/java/com/jozufozu/flywheel/backend/engine/DrawManager.java
similarity index 78%
rename from src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java
rename to src/main/java/com/jozufozu/flywheel/backend/engine/DrawManager.java
index a521aa49d..ae0969004 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/DrawManager.java
@@ -6,6 +6,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.jozufozu.flywheel.Flywheel;
+import com.jozufozu.flywheel.api.backend.Engine;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
@@ -13,17 +14,13 @@ import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.engine.embed.Environment;
-import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
-import it.unimi.dsi.fastutil.objects.ReferenceSet;
-
-public abstract class InstancerStorage> {
+public abstract class DrawManager> {
/**
* A map of instancer keys to instancers.
*
* This map is populated as instancers are requested and contains both initialized and uninitialized instancers.
*/
protected final Map, N> instancers = new ConcurrentHashMap<>();
- protected final ReferenceSet environments = new ReferenceLinkedOpenHashSet<>();
/**
* A list of instancers that have not yet been initialized.
*
@@ -37,12 +34,6 @@ public abstract class InstancerStorage> {
}
public void delete() {
- // FIXME: The ownership of environments is a bit weird. Their resources are created and destroyed by the engine,
- // but the engine doesn't own the things themselves. This makes it hard for the engine to know when to delete
- // environments. For now, we just delete all environments when the engine is deleted, but this is not ideal.
- environments.forEach(Environment::delete);
- environments.clear();
-
instancers.clear();
initializationQueue.clear();
}
@@ -61,6 +52,10 @@ public abstract class InstancerStorage> {
.forEach(AbstractInstancer::clear);
}
+ public abstract void renderCrumbling(List crumblingBlocks);
+
+ public abstract void renderStage(RenderStage stage);
+
protected abstract N create(InstancerKey type);
protected abstract void initialize(InstancerKey key, N instancer);
@@ -68,15 +63,13 @@ public abstract class InstancerStorage> {
private N createAndDeferInit(InstancerKey> key) {
var out = create(key);
- environments.add(key.environment());
-
// Only queue the instancer for initialization if it has anything to render.
- if (checkAndWarnEmptyModel(key.model())) {
+ if (checkAndWarnEmptyModel(key.model())) {
// Thread safety: this method is called atomically from within computeIfAbsent,
// so we don't need extra synchronization to protect the queue.
initializationQueue.add(new UninitializedInstancer<>(key, out));
}
- return out;
+ return out;
}
protected record UninitializedInstancer(InstancerKey key, N instancer) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/EngineImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/EngineImpl.java
new file mode 100644
index 000000000..6f1a5754f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/EngineImpl.java
@@ -0,0 +1,145 @@
+package com.jozufozu.flywheel.backend.engine;
+
+import java.util.List;
+
+import com.jozufozu.flywheel.api.backend.Engine;
+import com.jozufozu.flywheel.api.event.RenderContext;
+import com.jozufozu.flywheel.api.event.RenderStage;
+import com.jozufozu.flywheel.api.instance.Instance;
+import com.jozufozu.flywheel.api.instance.InstanceType;
+import com.jozufozu.flywheel.api.instance.Instancer;
+import com.jozufozu.flywheel.api.instance.InstancerProvider;
+import com.jozufozu.flywheel.api.model.Model;
+import com.jozufozu.flywheel.api.task.Plan;
+import com.jozufozu.flywheel.api.task.TaskExecutor;
+import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
+import com.jozufozu.flywheel.api.visualization.VisualizationContext;
+import com.jozufozu.flywheel.backend.engine.embed.EmbeddedEnvironment;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
+import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
+import com.jozufozu.flywheel.backend.gl.GlStateTracker;
+import com.jozufozu.flywheel.lib.task.Flag;
+import com.jozufozu.flywheel.lib.task.NamedFlag;
+import com.jozufozu.flywheel.lib.task.SyncedPlan;
+
+import net.minecraft.client.Camera;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Vec3i;
+import net.minecraft.world.phys.Vec3;
+
+public class EngineImpl implements Engine {
+ private final int sqrMaxOriginDistance;
+ private final DrawManager extends AbstractInstancer>> drawManager;
+ private final EnvironmentStorage environmentStorage = new EnvironmentStorage(this);
+ private final Flag flushFlag = new NamedFlag("flushed");
+
+ private BlockPos renderOrigin = BlockPos.ZERO;
+
+ public EngineImpl(DrawManager extends AbstractInstancer>> drawManager, int maxOriginDistance) {
+ this.drawManager = drawManager;
+ sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance;
+ }
+
+ @Override
+ public Plan createFramePlan() {
+ return SyncedPlan.of(this::flush);
+ }
+
+ @Override
+ public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
+ executor.syncUntil(flushFlag::isRaised);
+ if (stage.isLast()) {
+ flushFlag.lower();
+ }
+
+ drawManager.renderStage(stage);
+ }
+
+ @Override
+ public void renderCrumbling(TaskExecutor executor, RenderContext context, List crumblingBlocks) {
+ // Need to wait for flush before we can inspect instancer state.
+ executor.syncUntil(flushFlag::isRaised);
+
+ drawManager.renderCrumbling(crumblingBlocks);
+ }
+
+ @Override
+ public VisualizationContext createVisualizationContext(RenderStage stage) {
+ return new VisualizationContextImpl(stage);
+ }
+
+ @Override
+ public boolean updateRenderOrigin(Camera camera) {
+ Vec3 cameraPos = camera.getPosition();
+ double dx = renderOrigin.getX() - cameraPos.x;
+ double dy = renderOrigin.getY() - cameraPos.y;
+ double dz = renderOrigin.getZ() - cameraPos.z;
+ double distanceSqr = dx * dx + dy * dy + dz * dz;
+
+ if (distanceSqr <= sqrMaxOriginDistance) {
+ return false;
+ }
+
+ renderOrigin = BlockPos.containing(cameraPos);
+ drawManager.onRenderOriginChanged();
+ return true;
+ }
+
+ @Override
+ public Vec3i renderOrigin() {
+ return renderOrigin;
+ }
+
+ @Override
+ public void delete() {
+ drawManager.delete();
+ environmentStorage.delete();
+ }
+
+ public Instancer instancer(Environment environment, InstanceType type, Model model, RenderStage stage) {
+ return drawManager.getInstancer(environment, type, model, stage);
+ }
+
+ private void flush(RenderContext ctx) {
+ try (var state = GlStateTracker.getRestoreState()) {
+ Uniforms.updateContext(ctx);
+ drawManager.flush();
+ environmentStorage.flush();
+ }
+
+ flushFlag.raise();
+ }
+
+ public VisualEmbedding createEmbedding(RenderStage renderStage) {
+ return environmentStorage.create(renderStage);
+ }
+
+ public void freeEmbedding(EmbeddedEnvironment embeddedEnvironment) {
+ environmentStorage.enqueueDeletion(embeddedEnvironment);
+ }
+
+ private class VisualizationContextImpl implements VisualizationContext {
+ private final InstancerProviderImpl instancerProvider;
+ private final RenderStage stage;
+
+ public VisualizationContextImpl(RenderStage stage) {
+ instancerProvider = new InstancerProviderImpl(EngineImpl.this, stage);
+ this.stage = stage;
+ }
+
+ @Override
+ public InstancerProvider instancerProvider() {
+ return instancerProvider;
+ }
+
+ @Override
+ public Vec3i renderOrigin() {
+ return EngineImpl.this.renderOrigin();
+ }
+
+ @Override
+ public VisualEmbedding createEmbedding() {
+ return EngineImpl.this.createEmbedding(stage);
+ }
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/EnvironmentStorage.java b/src/main/java/com/jozufozu/flywheel/backend/engine/EnvironmentStorage.java
new file mode 100644
index 000000000..9a0e72270
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/EnvironmentStorage.java
@@ -0,0 +1,51 @@
+package com.jozufozu.flywheel.backend.engine;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import com.jozufozu.flywheel.api.event.RenderStage;
+import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
+import com.jozufozu.flywheel.backend.engine.embed.EmbeddedEnvironment;
+
+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<>());
+ private final Queue forDeletion = new ConcurrentLinkedQueue<>();
+ private final EngineImpl engine;
+
+ public EnvironmentStorage(EngineImpl engine) {
+ this.engine = engine;
+ }
+
+ public VisualEmbedding create(RenderStage stage) {
+ var out = new EmbeddedEnvironment(engine, stage);
+
+ environments.add(out);
+
+ return out;
+ }
+
+ public void enqueueDeletion(EmbeddedEnvironment environment) {
+ environments.remove(environment);
+
+ forDeletion.add(environment);
+ }
+
+ public void flush() {
+ EmbeddedEnvironment env;
+
+ while ((env = forDeletion.poll()) != null) {
+ env.actuallyDelete();
+ }
+
+ environments.forEach(EmbeddedEnvironment::flush);
+ }
+
+ public void delete() {
+ environments.forEach(EmbeddedEnvironment::actuallyDelete);
+ environments.clear();
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
index d0aacd2a5..6c95568f4 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
@@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.instance.InstancerProvider;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.engine.embed.GlobalEnvironment;
-public record InstancerProviderImpl(AbstractEngine engine, RenderStage renderStage) implements InstancerProvider {
+public record InstancerProviderImpl(EngineImpl engine, RenderStage renderStage) implements InstancerProvider {
@Override
public Instancer instancer(InstanceType type, Model model) {
return engine.instancer(GlobalEnvironment.INSTANCE, type, model, renderStage);
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java
index 9c0b9768b..e789c3b7b 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java
@@ -189,7 +189,7 @@ public class MeshPool {
}
@Override
- protected void delete() {
+ protected void _delete() {
MeshPool.this.dirty = true;
MeshPool.this.anyToRemove = true;
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
index cdcc68a3a..28050386c 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
@@ -14,13 +14,14 @@ import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
import com.jozufozu.flywheel.backend.Samplers;
import com.jozufozu.flywheel.backend.compile.ContextShader;
-import com.jozufozu.flywheel.backend.engine.AbstractEngine;
+import com.jozufozu.flywheel.backend.engine.EngineImpl;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
+import com.jozufozu.flywheel.backend.util.AtomicReferenceCounted;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.BlockAndTintGetter;
-public class EmbeddedEnvironment implements Environment, VisualEmbedding {
+public class EmbeddedEnvironment extends AtomicReferenceCounted implements Environment, VisualEmbedding {
private final Matrix4f pose = new Matrix4f();
private final Matrix3f normal = new Matrix3f();
@@ -28,10 +29,10 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
private final EmbeddedLightTexture lightTexture = new EmbeddedLightTexture();
private final InstancerProvider instancerProvider;
- private final AbstractEngine engine;
+ private final EngineImpl engine;
private final RenderStage renderStage;
- public EmbeddedEnvironment(AbstractEngine engine, RenderStage renderStage) {
+ public EmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) {
this.engine = engine;
this.renderStage = renderStage;
@@ -42,6 +43,22 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
return engine.instancer(EmbeddedEnvironment.this, type, model, renderStage);
}
};
+
+ // Acquire the reference owned by the visual that created this.
+ acquire();
+ }
+
+ public void flush() {
+ if (lightVolume.empty()) {
+ return;
+ }
+ Samplers.EMBEDDED_LIGHT.makeActive();
+
+ lightTexture.bind();
+
+ lightTexture.ensureCapacity(lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
+
+ lightTexture.upload(lightVolume.ptr(), lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
}
@Override
@@ -72,10 +89,6 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
lightTexture.bind();
- lightTexture.ensureCapacity(lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
-
- lightTexture.upload(lightVolume.ptr(), lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
-
float oneOverSizeX = 1f / (float) lightTexture.sizeX;
float oneOverSizeY = 1f / (float) lightTexture.sizeY;
float oneOverSizeZ = 1f / (float) lightTexture.sizeZ;
@@ -105,11 +118,35 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
@Override
public VisualEmbedding createEmbedding() {
- return new EmbeddedEnvironment(engine, renderStage);
+ return engine.createEmbedding(renderStage);
}
+ /**
+ * Called by visuals
+ */
@Override
public void delete() {
+ // Release the reference owned by the visual that created this.
+ // Note that visuals don't explicitly call acquire, instead the
+ // storage acquired a reference when this was constructed.
+ release();
+ }
+
+ /**
+ * Called when referenceCount goes to 0
+ */
+ @Override
+ public void _delete() {
+ engine.freeEmbedding(this);
+ }
+
+ /**
+ * Called in EnvironmentStorage#flush
+ */
+ public void actuallyDelete() {
+ // We could technically free the light volume right away in _delete, but
+ // the control flow here is so convoluted that it's probably best to do
+ // everything in one place.
lightVolume.delete();
lightTexture.delete();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
index e139ac234..d9db66cc3 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
@@ -10,5 +10,7 @@ public interface Environment {
void setupCull(GlProgram cullProgram);
- void delete();
+ void acquire();
+
+ void release();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
index ff29e474d..6d7fbc987 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
@@ -25,7 +25,12 @@ public class GlobalEnvironment implements Environment {
}
@Override
- public void delete() {
+ public void acquire() {
+
+ }
+
+ @Override
+ public void release() {
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
index f524a2219..d0ffde51e 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
@@ -77,9 +77,7 @@ public class IndirectCullingGroup {
if (instanceCount == 0) {
iterator.remove();
- for (IndirectDraw draw : instancer.draws()) {
- draw.delete();
- }
+ instancer.delete();
continue;
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
index 5b760f93d..e97f99a96 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
@@ -19,9 +19,9 @@ import com.jozufozu.flywheel.backend.Samplers;
import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
+import com.jozufozu.flywheel.backend.engine.DrawManager;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.InstancerKey;
-import com.jozufozu.flywheel.backend.engine.InstancerStorage;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.MeshPool;
import com.jozufozu.flywheel.backend.engine.TextureBinder;
@@ -39,7 +39,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.resources.model.ModelBakery;
-public class IndirectDrawManager extends InstancerStorage> {
+public class IndirectDrawManager extends DrawManager> {
private final IndirectPrograms programs;
private final StagingBuffer stagingBuffer;
private final MeshPool meshPool;
@@ -49,6 +49,7 @@ public class IndirectDrawManager extends InstancerStorage>
public IndirectDrawManager(IndirectPrograms programs) {
this.programs = programs;
+ programs.acquire();
stagingBuffer = new StagingBuffer(this.programs);
meshPool = new MeshPool();
@@ -81,17 +82,23 @@ public class IndirectDrawManager extends InstancerStorage>
}
public void renderStage(RenderStage stage) {
- TextureBinder.bindLightAndOverlay();
-
- vertexArray.bindForDraw();
- Uniforms.bindForDraw();
-
- for (var group : cullingGroups.values()) {
- group.submit(stage);
+ if (!hasStage(stage)) {
+ return;
}
- MaterialRenderState.reset();
- TextureBinder.resetLightAndOverlay();
+ try (var restoreState = GlStateTracker.getRestoreState()) {
+ TextureBinder.bindLightAndOverlay();
+
+ vertexArray.bindForDraw();
+ Uniforms.bindForDraw();
+
+ for (var group : cullingGroups.values()) {
+ group.submit(stage);
+ }
+
+ MaterialRenderState.reset();
+ TextureBinder.resetLightAndOverlay();
+ }
}
@Override
@@ -136,6 +143,8 @@ public class IndirectDrawManager extends InstancerStorage>
meshPool.delete();
crumblingDrawBuffer.delete();
+
+ programs.release();
}
public void renderCrumbling(List crumblingBlocks) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java
deleted file mode 100644
index 22385b430..000000000
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.jozufozu.flywheel.backend.engine.indirect;
-
-import java.util.List;
-
-import com.jozufozu.flywheel.api.event.RenderContext;
-import com.jozufozu.flywheel.api.event.RenderStage;
-import com.jozufozu.flywheel.api.task.Plan;
-import com.jozufozu.flywheel.api.task.TaskExecutor;
-import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
-import com.jozufozu.flywheel.backend.engine.AbstractEngine;
-import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
-import com.jozufozu.flywheel.backend.engine.InstancerStorage;
-import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
-import com.jozufozu.flywheel.backend.gl.GlStateTracker;
-import com.jozufozu.flywheel.lib.task.Flag;
-import com.jozufozu.flywheel.lib.task.NamedFlag;
-import com.jozufozu.flywheel.lib.task.SyncedPlan;
-
-public class IndirectEngine extends AbstractEngine {
- private final IndirectPrograms programs;
- private final IndirectDrawManager drawManager;
- private final Flag flushFlag = new NamedFlag("flushed");
-
- public IndirectEngine(IndirectPrograms programs, int maxOriginDistance) {
- super(maxOriginDistance);
- programs.acquire();
- this.programs = programs;
- drawManager = new IndirectDrawManager(this.programs);
- }
-
- @Override
- public Plan createFramePlan() {
- return SyncedPlan.of(this::flushDrawManager);
- }
-
- private void flushDrawManager(RenderContext ctx) {
- try (var state = GlStateTracker.getRestoreState()) {
- Uniforms.updateContext(ctx);
- drawManager.flush();
- }
- flushFlag.raise();
- }
-
- @Override
- public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
- executor.syncUntil(flushFlag::isRaised);
- if (stage.isLast()) {
- flushFlag.lower();
- }
-
- if (!drawManager.hasStage(stage)) {
- return;
- }
-
- try (var restoreState = GlStateTracker.getRestoreState()) {
- drawManager.renderStage(stage);
- }
- }
-
- @Override
- public void renderCrumbling(TaskExecutor executor, RenderContext context, List crumblingBlocks) {
- executor.syncUntil(flushFlag::isRaised);
-
- drawManager.renderCrumbling(crumblingBlocks);
- }
-
- @Override
- protected InstancerStorage extends AbstractInstancer>> getStorage() {
- return drawManager;
- }
-
- @Override
- public void delete() {
- drawManager.delete();
- programs.release();
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
index f2e92530a..75ce1ed43 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
@@ -101,4 +101,13 @@ public class IndirectInstancer extends AbstractInstancer
MemoryUtil.memPutInt(ptr, index);
writer.write(ptr + IndirectBuffers.INT_SIZE, instance);
}
+
+ @Override
+ public void delete() {
+ super.delete();
+
+ for (IndirectDraw draw : draws()) {
+ draw.delete();
+ }
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
index a2e029fc0..44d7b9f35 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
@@ -23,9 +23,9 @@ import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
+import com.jozufozu.flywheel.backend.engine.DrawManager;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.InstancerKey;
-import com.jozufozu.flywheel.backend.engine.InstancerStorage;
import com.jozufozu.flywheel.backend.engine.MaterialEncoder;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.MeshPool;
@@ -41,7 +41,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.resources.model.ModelBakery;
-public class InstancedDrawManager extends InstancerStorage> {
+public class InstancedDrawManager extends DrawManager> {
/**
* The set of draw calls to make in each {@link RenderStage}.
*/
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
index 6ff46fe46..da7481f60 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
@@ -107,6 +107,8 @@ public class InstancedInstancer extends AbstractInstancer
}
public void delete() {
+ super.delete();
+
if (vbo == null) {
return;
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java
deleted file mode 100644
index ad8964712..000000000
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.jozufozu.flywheel.backend.engine.instancing;
-
-import java.util.List;
-
-import com.jozufozu.flywheel.api.event.RenderContext;
-import com.jozufozu.flywheel.api.event.RenderStage;
-import com.jozufozu.flywheel.api.task.Plan;
-import com.jozufozu.flywheel.api.task.TaskExecutor;
-import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
-import com.jozufozu.flywheel.backend.engine.AbstractEngine;
-import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
-import com.jozufozu.flywheel.backend.engine.InstancerStorage;
-import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
-import com.jozufozu.flywheel.backend.gl.GlStateTracker;
-import com.jozufozu.flywheel.lib.task.Flag;
-import com.jozufozu.flywheel.lib.task.NamedFlag;
-import com.jozufozu.flywheel.lib.task.SyncedPlan;
-
-public class InstancingEngine extends AbstractEngine {
- private final InstancedDrawManager drawManager;
- private final Flag flushFlag = new NamedFlag("flushed");
-
- public InstancingEngine(InstancingPrograms programs, int maxOriginDistance) {
- super(maxOriginDistance);
- drawManager = new InstancedDrawManager(programs);
- }
-
- @Override
- public Plan createFramePlan() {
- return SyncedPlan.of(this::flushDrawManager);
- }
-
- private void flushDrawManager(RenderContext ctx) {
- try (var restoreState = GlStateTracker.getRestoreState()) {
- Uniforms.updateContext(ctx);
- drawManager.flush();
- }
- flushFlag.raise();
- }
-
- @Override
- public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
- executor.syncUntil(flushFlag::isRaised);
- if (stage.isLast()) {
- flushFlag.lower();
- }
-
- drawManager.renderStage(stage);
- }
-
- @Override
- public void renderCrumbling(TaskExecutor executor, RenderContext context, List crumblingBlocks) {
- // Need to wait for flush before we can inspect instancer state.
- executor.syncUntil(flushFlag::isRaised);
-
- drawManager.renderCrumbling(crumblingBlocks);
- }
-
- @Override
- protected InstancerStorage extends AbstractInstancer>> getStorage() {
- return drawManager;
- }
-
- @Override
- public void delete() {
- drawManager.delete();
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/util/AtomicReferenceCounted.java b/src/main/java/com/jozufozu/flywheel/backend/util/AtomicReferenceCounted.java
index cf45d7a5d..1aa97c09e 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/util/AtomicReferenceCounted.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/util/AtomicReferenceCounted.java
@@ -30,11 +30,11 @@ public abstract class AtomicReferenceCounted {
int newCount = referenceCount.decrementAndGet();
if (newCount == 0) {
isDeleted = true;
- delete();
+ _delete();
} else if (newCount < 0) {
throw new IllegalStateException("Tried to delete instance of '" + getClass().getName() + "' more times than it was acquired!");
}
}
- protected abstract void delete();
+ protected abstract void _delete();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/util/ReferenceCounted.java b/src/main/java/com/jozufozu/flywheel/backend/util/ReferenceCounted.java
index ee3cf0786..fba534d88 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/util/ReferenceCounted.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/util/ReferenceCounted.java
@@ -28,11 +28,11 @@ public abstract class ReferenceCounted {
int newCount = --referenceCount;
if (newCount == 0) {
isDeleted = true;
- delete();
+ _delete();
} else if (newCount < 0) {
throw new IllegalStateException("Tried to delete instance of '" + getClass().getName() + "' more times than it was acquired!");
}
}
- protected abstract void delete();
+ protected abstract void _delete();
}