From 7acf4a8aebf72614034740cf368af060f312e115 Mon Sep 17 00:00:00 2001
From: Jozufozu
Date: Thu, 30 Jun 2022 14:29:35 -0700
Subject: [PATCH] Batch 2
- Re-implement batching under new api topology
- Lots of duplicated code between instancing and batching, room for abstraction
- StructTypes now require their type argument to extend InstancedPart
- Fix crash when re-allocating drawbuffers
- Disable crumbling pending refactor
- Separate RenderDispatcher#beginFrame from RenderDispatcher#maintainOriginCoordinate
- Inline OriginShiftListener
- Refactor InstancedRenderDispatcher hooks
---
.../jozufozu/flywheel/api/MaterialGroup.java | 15 --
.../flywheel/api/struct/StructType.java | 3 +-
.../backend/instancing/AbstractInstancer.java | 4 +-
.../backend/instancing/DrawBuffer.java | 16 +-
.../backend/instancing/InstanceManager.java | 4 +-
.../backend/instancing/InstanceWorld.java | 32 +--
.../backend/instancing/RenderDispatcher.java | 10 +-
.../instancing/batching/BatchLists.java | 17 ++
.../batching/BatchedMaterialGroup.java | 81 --------
.../instancing/batching/BatchedModel.java | 38 ++++
.../instancing/batching/BatchingEngine.java | 75 ++++---
.../instancing/batching/CPUInstancer.java | 73 ++-----
.../batching/CPUInstancerFactory.java | 27 +--
.../instancing/batching/TransformSet.java | 74 +++++++
.../instancing/instancing/GPUInstancer.java | 6 +
.../instancing/GPUInstancerFactory.java | 5 +-
.../instancing/instancing/InstancedModel.java | 8 +-
.../instancing/InstancingEngine.java | 62 +++---
.../instancing/instancing/RenderLists.java | 2 +-
.../flywheel/backend/struct/BufferWriter.java | 3 +-
.../backend/struct/UnsafeBufferWriter.java | 3 +-
.../core/crumbling/CrumblingRenderer.java | 7 +-
.../mixin/LevelRendererDispatchMixin.java | 183 ++++++++++++++++++
.../LevelRendererInstanceUpdateMixin.java | 32 +++
.../flywheel/mixin/LevelRendererMixin.java | 26 +--
.../mixin/MultiBufferSourceMixin.java | 38 ----
.../com/jozufozu/flywheel/util/FlwUtil.java | 8 +
src/main/resources/flywheel.mixins.json | 3 +-
28 files changed, 522 insertions(+), 333 deletions(-)
delete mode 100644 src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java
create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java
delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java
create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java
create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java
create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/LevelRendererDispatchMixin.java
create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/LevelRendererInstanceUpdateMixin.java
delete mode 100644 src/main/java/com/jozufozu/flywheel/mixin/MultiBufferSourceMixin.java
diff --git a/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java b/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java
deleted file mode 100644
index 380e6f892..000000000
--- a/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.jozufozu.flywheel.api;
-
-import com.jozufozu.flywheel.api.struct.StructType;
-
-@Deprecated
-public interface MaterialGroup {
- /**
- * Get the material as defined by the given {@link StructType type}.
- *
- * @param spec The material you want to create instances with.
- * @param The type representing the per instance data.
- * @return A material you can use to render models.
- */
- InstancerFactory material(StructType spec);
-}
diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java
index 7c7b4bd43..cf994e2df 100644
--- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java
+++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java
@@ -2,6 +2,7 @@ package com.jozufozu.flywheel.api.struct;
import java.nio.ByteBuffer;
+import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.model.ModelTransformer;
import com.jozufozu.flywheel.core.source.FileResolution;
@@ -10,7 +11,7 @@ import com.jozufozu.flywheel.core.source.FileResolution;
* A StructType contains metadata for a specific instance struct that Flywheel can interface with.
* @param The java representation of the instance struct.
*/
-public interface StructType {
+public interface StructType {
/**
* @return A new, zeroed instance of S.
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java
index e39e3bb0d..bc656df99 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java
@@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.struct.StructType;
public abstract class AbstractInstancer implements Instancer {
- protected final StructType type;
+ public final StructType type;
protected final ArrayList data = new ArrayList<>();
protected boolean anyToRemove;
@@ -104,6 +104,8 @@ public abstract class AbstractInstancer implements Inst
return instanceData;
}
+ public abstract void delete();
+
@Override
public String toString() {
return "Instancer[" + getInstanceCount() + ']';
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java
index a9759c368..9fa6d9470 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/DrawBuffer.java
@@ -16,12 +16,11 @@ import net.minecraft.client.renderer.RenderType;
*
* The number of vertices needs to be known ahead of time.
*/
-public class DrawBuffer implements AutoCloseable {
+public class DrawBuffer {
private final RenderType parent;
private ByteBuffer backingBuffer;
private int expectedVertices;
- private Cleaner.Cleanable cleanable;
public DrawBuffer(RenderType parent) {
this.parent = parent;
@@ -46,12 +45,8 @@ public class DrawBuffer implements AutoCloseable {
if (backingBuffer == null) {
backingBuffer = MemoryTracker.create(byteSize);
- cleanable = FlywheelMemory.track(this, backingBuffer);
- }
- if (byteSize > backingBuffer.capacity()) {
- cleanable.clean();
+ } else if (byteSize > backingBuffer.capacity()) {
backingBuffer = MemoryTracker.resize(backingBuffer, byteSize);
- cleanable = FlywheelMemory.track(this, backingBuffer);
}
return new DirectVertexConsumer(backingBuffer, format, vertexCount);
@@ -80,11 +75,4 @@ public class DrawBuffer implements AutoCloseable {
public void reset() {
this.expectedVertices = 0;
}
-
- @Override
- public void close() {
- if (cleanable != null) {
- cleanable.clean();
- }
- }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java
index 5764819c6..a2364ccbe 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java
@@ -13,7 +13,6 @@ import com.jozufozu.flywheel.api.InstancerManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.Backend;
-import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter;
import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter;
import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter;
@@ -25,7 +24,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.Camera;
import net.minecraft.core.BlockPos;
-public abstract class InstanceManager implements InstancingEngine.OriginShiftListener {
+public abstract class InstanceManager {
public final InstancerManager instancerManager;
@@ -350,7 +349,6 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift
}
}
- @Override
public void onOriginShift() {
dynamicInstances.clear();
tickableInstances.clear();
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
index 82addca0c..286a3726d 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
@@ -13,6 +13,7 @@ import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.util.ClientLevelExtension;
+import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.RenderType;
@@ -36,21 +37,21 @@ public class InstanceWorld {
public static InstanceWorld create(LevelAccessor level) {
return switch (Backend.getBackendType()) {
case INSTANCING -> {
- InstancingEngine manager = new InstancingEngine<>(Contexts.WORLD);
+ InstancingEngine engine = new InstancingEngine<>(Contexts.WORLD);
- var entityInstanceManager = new EntityInstanceManager(manager);
- var blockEntityInstanceManager = new BlockEntityInstanceManager(manager);
+ var entityInstanceManager = new EntityInstanceManager(engine);
+ var blockEntityInstanceManager = new BlockEntityInstanceManager(engine);
- manager.addListener(entityInstanceManager);
- manager.addListener(blockEntityInstanceManager);
- yield new InstanceWorld(manager, entityInstanceManager, blockEntityInstanceManager);
+ engine.attachManager(entityInstanceManager);
+ engine.attachManager(blockEntityInstanceManager);
+ yield new InstanceWorld(engine, entityInstanceManager, blockEntityInstanceManager);
}
case BATCHING -> {
- var manager = new BatchingEngine();
- var entityInstanceManager = new EntityInstanceManager(manager);
- var blockEntityInstanceManager = new BlockEntityInstanceManager(manager);
+ var engine = new BatchingEngine();
+ var entityInstanceManager = new EntityInstanceManager(engine);
+ var blockEntityInstanceManager = new BlockEntityInstanceManager(engine);
- yield new InstanceWorld(manager, entityInstanceManager, blockEntityInstanceManager);
+ yield new InstanceWorld(engine, entityInstanceManager, blockEntityInstanceManager);
}
default -> throw new IllegalArgumentException("Unknown engine type");
};
@@ -89,12 +90,17 @@ public class InstanceWorld {
*
*/
public void beginFrame(BeginFrameEvent event) {
- engine.beginFrame(event.getCamera());
+ Camera camera = event.getCamera();
+ boolean shifted = engine.maintainOriginCoordinate(camera);
taskEngine.syncPoint();
- blockEntityInstanceManager.beginFrame(taskEngine, event.getCamera());
- entityInstanceManager.beginFrame(taskEngine, event.getCamera());
+ if (!shifted) {
+ blockEntityInstanceManager.beginFrame(taskEngine, camera);
+ entityInstanceManager.beginFrame(taskEngine, camera);
+ }
+
+ engine.beginFrame(taskEngine, camera);
}
/**
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java
index f3d6657f5..d53c29a58 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java
@@ -12,11 +12,13 @@ public interface RenderDispatcher {
void renderSpecificType(TaskEngine taskEngine, RenderContext context, RenderType type);
/**
- * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
- *
- * This prevents floating point precision issues at high coordinates.
+ * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions,
+ * preventing floating point precision issues at high coordinates.
+ * @return {@code true} if the origin coordinate was changed, {@code false} otherwise.
*/
- void beginFrame(Camera info);
+ boolean maintainOriginCoordinate(Camera camera);
+
+ void beginFrame(TaskEngine taskEngine, Camera info);
void delete();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java
new file mode 100644
index 000000000..c5ec268b4
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchLists.java
@@ -0,0 +1,17 @@
+package com.jozufozu.flywheel.backend.instancing.batching;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.minecraft.client.renderer.RenderType;
+
+public class BatchLists {
+
+ public final Map>> renderLists = new HashMap<>();
+
+ public void add(TransformSet> set) {
+ renderLists.computeIfAbsent(set.material.renderType(), k -> new ArrayList<>()).add(set);
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java
deleted file mode 100644
index 77b48809d..000000000
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.jozufozu.flywheel.backend.instancing.batching;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.jozufozu.flywheel.api.InstancedPart;
-import com.jozufozu.flywheel.api.MaterialGroup;
-import com.jozufozu.flywheel.api.struct.StructType;
-import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
-import com.jozufozu.flywheel.backend.instancing.TaskEngine;
-import com.mojang.blaze3d.vertex.PoseStack;
-
-import net.minecraft.client.renderer.RenderType;
-
-public class BatchedMaterialGroup implements MaterialGroup {
-
- protected final RenderType state;
-
- private final Map, CPUInstancerFactory>> materials = new HashMap<>();
- private int vertexCount;
- private int instanceCount;
-
- public BatchedMaterialGroup(RenderType state) {
- this.state = state;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public CPUInstancerFactory material(StructType type) {
- return (CPUInstancerFactory) materials.computeIfAbsent(type, CPUInstancerFactory::new);
- }
-
- public void render(PoseStack stack, BatchDrawingTracker source, TaskEngine pool) {
-
-// vertexCount = 0;
-// instanceCount = 0;
-// for (BatchedMaterial> material : materials.values()) {
-// for (CPUInstancer> instancer : material.models.values()) {
-// instancer.setup();
-// vertexCount += instancer.getVertexCount();
-// instanceCount += instancer.getInstanceCount();
-// }
-// }
-//
-// DirectVertexConsumer consumer = source.getDirectConsumer(state, vertexCount);
-//
-// // avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
-// consumer.memSetZero();
-//
-// for (BatchedMaterial> material : materials.values()) {
-// for (CPUInstancer> instancer : material.models.values()) {
-// instancer.sbb.context.outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
-// instancer.submitTasks(stack, pool, consumer);
-// }
-// }
- }
-
- public void clear() {
- materials.values().forEach(CPUInstancerFactory::clear);
- }
-
- public void delete() {
- materials.clear();
- }
-
- /**
- * Get the number of instances drawn last frame.
- * @return The instance count.
- */
- public int getInstanceCount() {
- return instanceCount;
- }
-
- /**
- * Get the number of vertices drawn last frame.
- * @return The vertex count.
- */
- public int getVertexCount() {
- return vertexCount;
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java
new file mode 100644
index 000000000..16fca800d
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedModel.java
@@ -0,0 +1,38 @@
+package com.jozufozu.flywheel.backend.instancing.batching;
+
+import java.util.List;
+
+import com.jozufozu.flywheel.api.InstancedPart;
+import com.jozufozu.flywheel.api.struct.StructType;
+import com.jozufozu.flywheel.core.model.ModelSupplier;
+
+public class BatchedModel {
+
+ CPUInstancer instancer;
+ ModelSupplier model;
+ StructType type;
+ private List> layers;
+
+ public BatchedModel(StructType type, ModelSupplier model) {
+ this.type = type;
+ this.model = model;
+ this.instancer = new CPUInstancer<>(type);
+ }
+
+ public void init(BatchLists batchLists) {
+ layers = model.get()
+ .entrySet()
+ .stream()
+ .map(entry -> new TransformSet<>(instancer, entry.getKey(), entry.getValue()))
+ .toList();
+
+ for (TransformSet layer : layers) {
+ batchLists.add(layer);
+ }
+ }
+
+ public void clear() {
+ instancer.clear();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java
index d5044f97c..5ac277a17 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java
@@ -1,32 +1,45 @@
package com.jozufozu.flywheel.backend.instancing.batching;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
+import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.core.RenderContext;
+import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.platform.Lighting;
+import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
+import net.minecraft.world.phys.Vec3;
public class BatchingEngine implements Engine {
- private final Map, CPUInstancerFactory>> factories = new HashMap<>();
+ private final Map, CPUInstancerFactory>> factories = new HashMap<>();
private final BatchDrawingTracker batchTracker = new BatchDrawingTracker();
+ private final BatchLists batchLists = new BatchLists();
+
+ protected final List> uninitializedModels = new ArrayList<>();
+
@SuppressWarnings("unchecked")
@Override
public CPUInstancerFactory factory(StructType type) {
- return (CPUInstancerFactory) factories.computeIfAbsent(type, CPUInstancerFactory::new);
+ return (CPUInstancerFactory) factories.computeIfAbsent(type, this::createFactory);
+ }
+
+ public CPUInstancerFactory createFactory(StructType type) {
+ return new CPUInstancerFactory<>(type, uninitializedModels::add);
}
@Override
@@ -34,6 +47,25 @@ public class BatchingEngine implements Engine {
return BlockPos.ZERO;
}
+ public void submitTasks(PoseStack stack, TaskEngine taskEngine) {
+ batchLists.renderLists.forEach((renderType, renderList) -> {
+ int vertices = 0;
+ for (var transformSet : renderList) {
+ vertices += transformSet.getTotalVertexCount();
+ }
+
+ var consumer = batchTracker.getDirectConsumer(renderType, vertices);
+ consumer.memSetZero();
+
+ var outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
+
+ for (var transformSet : renderList) {
+ transformSet.setOutputColorDiffuse(outputColorDiffuse);
+ transformSet.submitTasks(stack, taskEngine, consumer);
+ }
+ });
+ }
+
@Override
public void renderSpecificType(TaskEngine taskEngine, RenderContext context, RenderType type) {
@@ -41,27 +73,6 @@ public class BatchingEngine implements Engine {
@Override
public void renderAllRemaining(TaskEngine taskEngine, RenderContext context) {
-// vertexCount = 0;
-// instanceCount = 0;
-// for (BatchedMaterial> material : materials.values()) {
-// for (CPUInstancer> instancer : material.models.values()) {
-// instancer.setup();
-// vertexCount += instancer.getVertexCount();
-// instanceCount += instancer.getInstanceCount();
-// }
-// }
-//
-// DirectVertexConsumer consumer = batchTracker.getDirectConsumer(state, vertexCount);
-//
-// // avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
-// consumer.memSetZero();
-//
-// for (BatchedMaterial> material : materials.values()) {
-// for (CPUInstancer> instancer : material.models.values()) {
-// instancer.sbb.context.outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
-// instancer.submitTasks(stack, pool, consumer);
-// }
-// }
// FIXME: this probably breaks some vanilla stuff but it works much better for flywheel
Matrix4f mat = new Matrix4f();
@@ -81,8 +92,24 @@ public class BatchingEngine implements Engine {
}
@Override
- public void beginFrame(Camera info) {
+ public boolean maintainOriginCoordinate(Camera camera) {
+ // do nothing
+ return false;
+ }
+ @Override
+ public void beginFrame(TaskEngine taskEngine, Camera info) {
+ for (var model : uninitializedModels) {
+ model.init(batchLists);
+ }
+
+ uninitializedModels.clear();
+
+ Vec3 cameraPos = info.getPosition();
+ var stack = FlwUtil.copyPoseStack(RenderContext.CURRENT.stack());
+ stack.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
+
+ submitTasks(stack, taskEngine);
}
@Override
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java
index d03d5ffce..4166ef078 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java
@@ -1,74 +1,39 @@
package com.jozufozu.flywheel.backend.instancing.batching;
+import java.util.List;
+
import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
-import com.jozufozu.flywheel.backend.instancing.TaskEngine;
-import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
-import com.mojang.blaze3d.vertex.PoseStack;
-import com.mojang.blaze3d.vertex.VertexConsumer;
public class CPUInstancer extends AbstractInstancer {
-// private final Batched batchingType;
-//
-// final ModelTransformer sbb;
-
public CPUInstancer(StructType type) {
super(type);
-// batchingType = type;
-//
-// sbb = new ModelTransformer(modelData.get());
- }
-
- void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
-// int instances = getInstanceCount();
-//
-// while (instances > 0) {
-// int end = instances;
-// instances -= 512;
-// int start = Math.max(instances, 0);
-//
-// int verts = getModelVertexCount() * (end - start);
-//
-// DirectVertexConsumer sub = consumer.split(verts);
-//
-// pool.submit(() -> drawRange(stack, sub, start, end));
-// }
- }
-
- private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) {
-// ModelTransformer.Params params = new ModelTransformer.Params();
-//
-// for (D d : data.subList(from, to)) {
-// params.loadDefault();
-//
-// batchingType.transform(d, params);
-//
-// sbb.renderInto(params, stack, buffer);
-// }
- }
-
- void drawAll(PoseStack stack, VertexConsumer buffer) {
-// ModelTransformer.Params params = new ModelTransformer.Params();
-// for (D d : data) {
-// params.loadDefault();
-//
-// batchingType.transform(d, params);
-//
-// sbb.renderInto(params, stack, buffer);
-// }
}
void setup() {
-// if (anyToRemove) {
-// data.removeIf(InstanceData::isRemoved);
-// anyToRemove = false;
-// }
+ if (anyToRemove) {
+ data.removeIf(InstancedPart::isRemoved);
+ anyToRemove = false;
+ }
+ }
+
+ public List getRange(int start, int end) {
+ return data.subList(start, end);
+ }
+
+ public List getAll() {
+ return data;
}
@Override
public void notifyDirty() {
// noop
}
+
+ @Override
+ public void delete() {
+ // noop
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java
index 11965c7da..005e044f1 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java
@@ -2,36 +2,31 @@ package com.jozufozu.flywheel.backend.instancing.batching;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Consumer;
import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.InstancerFactory;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.core.model.ModelSupplier;
-import com.mojang.blaze3d.vertex.PoseStack;
-import com.mojang.blaze3d.vertex.VertexConsumer;
public class CPUInstancerFactory implements InstancerFactory {
- protected final Map> models;
+ protected final Map> models;
private final StructType type;
+ private final Consumer> creationListener;
- public CPUInstancerFactory(StructType type) {
+ public CPUInstancerFactory(StructType type, Consumer> creationListener) {
this.type = type;
+ this.creationListener = creationListener;
+
this.models = new HashMap<>();
}
@Override
public Instancer model(ModelSupplier modelKey) {
- return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type));
- }
-
- public void setupAndRenderInto(PoseStack stack, VertexConsumer buffer) {
- for (CPUInstancer instancer : models.values()) {
- instancer.setup();
- instancer.drawAll(stack, buffer);
- }
+ return models.computeIfAbsent(modelKey, this::createModel).instancer;
}
/**
@@ -39,6 +34,12 @@ public class CPUInstancerFactory implements InstancerFa
*/
public void clear() {
models.values()
- .forEach(CPUInstancer::clear);
+ .forEach(BatchedModel::clear);
+ }
+
+ private BatchedModel createModel(ModelSupplier k) {
+ var out = new BatchedModel<>(type, k);
+ creationListener.accept(out);
+ return out;
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java
new file mode 100644
index 000000000..8e4d52b7e
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java
@@ -0,0 +1,74 @@
+package com.jozufozu.flywheel.backend.instancing.batching;
+
+import java.util.List;
+
+import com.jozufozu.flywheel.api.InstancedPart;
+import com.jozufozu.flywheel.api.material.Material;
+import com.jozufozu.flywheel.backend.instancing.TaskEngine;
+import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
+import com.jozufozu.flywheel.core.model.Mesh;
+import com.jozufozu.flywheel.core.model.ModelTransformer;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+
+public class TransformSet {
+
+ public final Material material;
+ public final Mesh mesh;
+ private final CPUInstancer instancer;
+ private final ModelTransformer modelTransformer;
+
+ public TransformSet(CPUInstancer instancer, Material material, Mesh mesh) {
+ this.instancer = instancer;
+ this.material = material;
+ this.mesh = mesh;
+
+ modelTransformer = new ModelTransformer(mesh);
+ }
+
+ void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
+ instancer.setup();
+
+ int instances = instancer.getInstanceCount();
+
+ while (instances > 0) {
+ int end = instances;
+ instances -= 512;
+ int start = Math.max(instances, 0);
+
+ int verts = mesh.getVertexCount() * (end - start);
+
+ DirectVertexConsumer sub = consumer.split(verts);
+
+ pool.submit(() -> drawRange(stack, sub, start, end));
+ }
+ }
+
+ private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) {
+ drawList(stack, buffer, instancer.getRange(from, to));
+ }
+
+ void drawAll(PoseStack stack, VertexConsumer buffer) {
+ drawList(stack, buffer, instancer.getAll());
+ }
+
+ private void drawList(PoseStack stack, VertexConsumer buffer, List list) {
+ ModelTransformer.Params params = new ModelTransformer.Params();
+
+ for (D d : list) {
+ params.loadDefault();
+
+ instancer.type.transform(d, params);
+
+ modelTransformer.renderInto(params, stack, buffer);
+ }
+ }
+
+ public int getTotalVertexCount() {
+ return mesh.getVertexCount() * instancer.getInstanceCount();
+ }
+
+ public void setOutputColorDiffuse(boolean outputColorDiffuse) {
+ modelTransformer.context.outputColorDiffuse = outputColorDiffuse;
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
index d1ba46260..1b5d7425c 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
@@ -129,4 +129,10 @@ public class GPUInstancer extends AbstractInstancer
vao.setAttributeDivisor(this.attributeBaseIndex + i, 1);
}
}
+
+ @Override
+ public void delete() {
+ vbo.delete();
+ vbo = null;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java
index 843d91316..ff20915db 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java
@@ -8,6 +8,7 @@ import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.InstancerFactory;
import com.jozufozu.flywheel.api.struct.StructType;
+import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.core.model.ModelSupplier;
import net.minecraft.client.renderer.RenderType;
@@ -36,7 +37,7 @@ public class GPUInstancerFactory implements InstancerFa
return models.values()
.stream()
.map(InstancedModel::getInstancer)
- .mapToInt(GPUInstancer::getInstanceCount)
+ .mapToInt(AbstractInstancer::getInstanceCount)
.sum();
}
@@ -59,7 +60,7 @@ public class GPUInstancerFactory implements InstancerFa
models.values()
.stream()
.map(InstancedModel::getInstancer)
- .forEach(GPUInstancer::clear);
+ .forEach(AbstractInstancer::clear);
}
private InstancedModel createInstancer(ModelSupplier model) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java
index f94f345ef..bd5abab4c 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java
@@ -4,13 +4,14 @@ import java.util.List;
import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
+import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.core.model.ModelSupplier;
public class InstancedModel {
- public final GPUInstancer instancer;
- public final ModelSupplier model;
+ private final ModelSupplier model;
private final StructType type;
+ private final GPUInstancer instancer;
private List layers;
public InstancedModel(StructType type, ModelSupplier model) {
@@ -48,8 +49,7 @@ public class InstancedModel {
public void delete() {
if (instancer.vbo == null) return;
- instancer.vbo.delete();
- instancer.vbo = null;
+ instancer.delete();
for (var layer : layers) {
layer.delete();
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java
index f5b306129..706ffe3e8 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java
@@ -20,6 +20,7 @@ import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.instancing.Engine;
+import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
@@ -65,19 +66,22 @@ public class InstancingEngine implements Engine {
protected final ProgramCompiler
context;
- protected final Map, GPUInstancerFactory>> factories = new HashMap<>();
+ protected final Map, GPUInstancerFactory>> factories = new HashMap<>();
protected final List> uninitializedModels = new ArrayList<>();
protected final RenderLists renderLists = new RenderLists();
- private final WeakHashSet listeners;
+ /**
+ * The set of instance managers that are attached to this engine.
+ */
+ private final WeakHashSet> instanceManagers;
private int vertexCount;
private int instanceCount;
public InstancingEngine(ProgramCompiler context) {
this.context = context;
- this.listeners = new WeakHashSet<>();
+ this.instanceManagers = new WeakHashSet<>();
}
@SuppressWarnings("unchecked")
@@ -198,21 +202,29 @@ public class InstancingEngine
implements Engine {
return originCoordinate;
}
- public void addListener(OriginShiftListener listener) {
- listeners.add(listener);
+ public void attachManager(InstanceManager> listener) {
+ instanceManagers.add(listener);
}
- /**
- * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
- *
- * This prevents floating point precision issues at high coordinates.
- */
@Override
- public void beginFrame(Camera info) {
- checkOriginDistance(info);
+ public boolean maintainOriginCoordinate(Camera camera) {
+ Vec3 cameraPos = camera.getPosition();
- for (var factory : uninitializedModels) {
- factory.init(renderLists);
+ double distanceSqr = Vec3.atLowerCornerOf(originCoordinate)
+ .subtract(cameraPos)
+ .lengthSqr();
+
+ if (distanceSqr > MAX_ORIGIN_DISTANCE * MAX_ORIGIN_DISTANCE) {
+ shiftListeners(Mth.floor(cameraPos.x), Mth.floor(cameraPos.y), Mth.floor(cameraPos.z));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void beginFrame(TaskEngine taskEngine, Camera info) {
+ for (var model : uninitializedModels) {
+ model.init(renderLists);
}
uninitializedModels.clear();
@@ -222,26 +234,12 @@ public class InstancingEngine
implements Engine {
.flush();
}
- private void checkOriginDistance(Camera info) {
- int cX = Mth.floor(info.getPosition().x);
- int cY = Mth.floor(info.getPosition().y);
- int cZ = Mth.floor(info.getPosition().z);
-
- int dX = cX - originCoordinate.getX();
- int dY = cY - originCoordinate.getY();
- int dZ = cZ - originCoordinate.getZ();
-
- if (Math.abs(dX) > MAX_ORIGIN_DISTANCE || Math.abs(dY) > MAX_ORIGIN_DISTANCE || Math.abs(dZ) > MAX_ORIGIN_DISTANCE) {
- shiftListeners(cX, cY, cZ);
- }
- }
-
private void shiftListeners(int cX, int cY, int cZ) {
originCoordinate = new BlockPos(cX, cY, cZ);
factories.values().forEach(GPUInstancerFactory::clear);
- listeners.forEach(OriginShiftListener::onOriginShift);
+ instanceManagers.forEach(InstanceManager::onOriginShift);
}
@Override
@@ -336,7 +334,7 @@ public class InstancingEngine
implements Engine {
if (part.getOwner() instanceof GPUInstancer instancer) {
// queue the instances for copying to the crumbling instance buffer
- map.computeIfAbsent(instancer.parent.model, k -> new ArrayList<>()).add(part);
+ map.computeIfAbsent(instancer.parent.getModel(), k -> new ArrayList<>()).add(part);
}
}
}
@@ -378,8 +376,4 @@ public class InstancingEngine
implements Engine {
return dataByStage;
}
- @FunctionalInterface
- public interface OriginShiftListener {
- void onOriginShift();
- }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/RenderLists.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/RenderLists.java
index a3f003ed6..b5aa12258 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/RenderLists.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/RenderLists.java
@@ -12,7 +12,7 @@ import net.minecraft.client.renderer.RenderType;
public class RenderLists {
- private Map> renderLists = new HashMap<>();
+ private final Map> renderLists = new HashMap<>();
public final Set layersToProcess = new HashSet<>();
public ListMultimap get(RenderType type) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java b/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
index 5a0bc8fb1..943559acc 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
@@ -2,10 +2,11 @@ package com.jozufozu.flywheel.backend.struct;
import java.nio.ByteBuffer;
+import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.struct.StructWriter;
-public abstract class BufferWriter implements StructWriter {
+public abstract class BufferWriter implements StructWriter {
protected final ByteBuffer backingBuffer;
protected final int stride;
diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java b/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java
index 40d489d54..96e675bbd 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java
@@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
import org.lwjgl.system.MemoryUtil;
+import com.jozufozu.flywheel.api.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType;
/**
@@ -14,7 +15,7 @@ import com.jozufozu.flywheel.api.struct.StructType;
* better optimized code than other implementations. The implementation does not check for invalid memory accesses,
* meaning that errors can corrupt process memory.
*/
-public abstract class UnsafeBufferWriter extends BufferWriter {
+public abstract class UnsafeBufferWriter extends BufferWriter {
/**
* The write pointer into the buffer storage. This is advanced by the stride every time
* {@link UnsafeBufferWriter#advance()} is called.
diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java
index dd5b8e192..126082776 100644
--- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java
+++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java
@@ -44,7 +44,8 @@ public class CrumblingRenderer {
}
public static void renderCrumbling(LevelRenderer levelRenderer, ClientLevel level, PoseStack poseStack, Camera camera, Matrix4f projectionMatrix) {
- if (!Backend.canUseInstancing(level)) return;
+ // TODO: one pass base/crumbling
+ if (true) return;
Int2ObjectMap> activeStages = getActiveStageBlockEntities(levelRenderer, level);
if (activeStages.isEmpty()) return;
@@ -78,7 +79,7 @@ public class CrumblingRenderer {
stage.getValue().forEach(instanceManager::add);
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, camera);
- engine.beginFrame(camera);
+ engine.beginFrame(SerialTaskEngine.INSTANCE, camera);
engine.renderAllRemaining(SerialTaskEngine.INSTANCE, ctx);
@@ -143,7 +144,7 @@ public class CrumblingRenderer {
private State() {
instancerManager = new CrumblingEngine();
instanceManager = new CrumblingInstanceManager(instancerManager);
- instancerManager.addListener(instanceManager);
+ instancerManager.attachManager(instanceManager);
}
private void kill() {
diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererDispatchMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererDispatchMixin.java
new file mode 100644
index 000000000..aac392311
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererDispatchMixin.java
@@ -0,0 +1,183 @@
+package com.jozufozu.flywheel.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import com.jozufozu.flywheel.backend.Backend;
+import com.jozufozu.flywheel.backend.gl.GlStateTracker;
+import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
+import com.jozufozu.flywheel.core.RenderContext;
+import com.jozufozu.flywheel.event.RenderLayerEvent;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.math.Matrix4f;
+
+import net.minecraft.client.renderer.LevelRenderer;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.Sheets;
+import net.minecraft.client.renderer.texture.TextureAtlas;
+import net.minecraftforge.common.MinecraftForge;
+
+@Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium
+public class LevelRendererDispatchMixin {
+
+ @Inject(at = @At("TAIL"), method = "renderChunkLayer")
+ private void renderChunkLayer(RenderType pRenderType, PoseStack pPoseStack, double pCamX, double pCamY, double pCamZ, Matrix4f pProjectionMatrix, CallbackInfo ci) {
+ try (var restoreState = GlStateTracker.getRestoreState()) {
+
+ // TODO: Is this necessary?
+ InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, pRenderType);
+ MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(RenderContext.CURRENT, pRenderType));
+ }
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch()V"))
+ private void endBatch(CallbackInfo ci) {
+ if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
+ try (var restoreState = GlStateTracker.getRestoreState()) {
+ InstancedRenderDispatcher.renderAllRemaining(RenderContext.CURRENT);
+ }
+ }
+ }
+
+ @Unique
+ private void flywheel$dispatch(RenderType pRenderType) {
+ if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
+ try (var restoreState = GlStateTracker.getRestoreState()) {
+ InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, pRenderType);
+ }
+ }
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 0, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entitySolid(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entitySolid(TextureAtlas.LOCATION_BLOCKS));
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 1, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entityCutout(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entityCutout(TextureAtlas.LOCATION_BLOCKS));
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 2, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entityCutoutNoCull(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entityCutoutNoCull(TextureAtlas.LOCATION_BLOCKS));
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 3, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entitySmoothCutout(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entitySmoothCutout(TextureAtlas.LOCATION_BLOCKS));
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 4, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$solid(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.solid());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 5, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$endPortal(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.endPortal());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 6, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$endGateway(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.endGateway());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 7, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$solidBlockSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.solidBlockSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 8, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$cutoutBlockSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.cutoutBlockSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 9, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$bedSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.bedSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 10, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$shulkerBoxSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.shulkerBoxSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 11, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$signSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.signSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 12, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$chestSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.chestSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 13, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$translucentCullBlockSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.translucentCullBlockSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 14, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$bannerSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.bannerSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 15, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$shieldSheet(CallbackInfo ci) {
+ flywheel$dispatch(Sheets.shieldSheet());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 16, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$armorGlint(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.armorGlint());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 17, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$armorEntityGlint(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.armorEntityGlint());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 18, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$glint(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.glint());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 19, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$glintDirect(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.glintDirect());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 20, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$glintTranslucent(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.glintTranslucent());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 21, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entityGlint(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entityGlint());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 22, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$entityGlintDirect(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.entityGlintDirect());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 23, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$waterMask(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.waterMask());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 24, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$lines1(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.lines());
+ }
+
+ @Inject(method = "renderLevel", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 25, target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch(Lnet/minecraft/client/renderer/RenderType;)V"))
+ private void renderLayer$lines2(CallbackInfo ci) {
+ flywheel$dispatch(RenderType.lines());
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererInstanceUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererInstanceUpdateMixin.java
new file mode 100644
index 000000000..bb781b29e
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererInstanceUpdateMixin.java
@@ -0,0 +1,32 @@
+package com.jozufozu.flywheel.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import com.jozufozu.flywheel.backend.Backend;
+import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
+
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.renderer.LevelRenderer;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.block.state.BlockState;
+
+@Mixin(LevelRenderer.class)
+public class LevelRendererInstanceUpdateMixin {
+ @Shadow
+ private ClientLevel level;
+
+ /**
+ * This gets called when a block is marked for rerender by vanilla.
+ */
+ @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V")
+ private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
+ if (Backend.isOn()) {
+ InstancedRenderDispatcher.getBlockEntities(level)
+ .update(level.getBlockEntity(pos));
+ }
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java
index 93fc64158..12fa21441 100644
--- a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java
+++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java
@@ -3,6 +3,7 @@ package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -26,8 +27,6 @@ import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderBuffers;
import net.minecraft.client.renderer.RenderType;
-import net.minecraft.core.BlockPos;
-import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.MinecraftForge;
@@ -51,16 +50,6 @@ public class LevelRendererMixin {
}
}
- @Inject(at = @At("TAIL"), method = "renderChunkLayer")
- private void renderChunkLayer(RenderType pRenderType, PoseStack pPoseStack, double pCamX, double pCamY, double pCamZ, Matrix4f pProjectionMatrix, CallbackInfo ci) {
- try (var restoreState = GlStateTracker.getRestoreState()) {
-
- // TODO: Is this necessary?
- InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, pRenderType);
- MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(RenderContext.CURRENT, pRenderType));
- }
- }
-
@Inject(at = @At("TAIL"), method = "renderLevel")
private void endRender(PoseStack pPoseStack, float pPartialTick, long pFinishNanoTime, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pProjectionMatrix, CallbackInfo ci) {
RenderContext.CURRENT = null;
@@ -78,17 +67,4 @@ public class LevelRendererMixin {
private void renderBlockBreaking(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
CrumblingRenderer.renderCrumbling((LevelRenderer) (Object) this, level, poseStack, camera, projectionMatrix);
}
-
- // Instancing
-
- /**
- * This gets called when a block is marked for rerender by vanilla.
- */
- @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V")
- private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
- if (Backend.isOn()) {
- InstancedRenderDispatcher.getBlockEntities(level)
- .update(level.getBlockEntity(pos));
- }
- }
}
diff --git a/src/main/java/com/jozufozu/flywheel/mixin/MultiBufferSourceMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/MultiBufferSourceMixin.java
deleted file mode 100644
index ae7d1a77a..000000000
--- a/src/main/java/com/jozufozu/flywheel/mixin/MultiBufferSourceMixin.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.jozufozu.flywheel.mixin;
-
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import com.jozufozu.flywheel.backend.Backend;
-import com.jozufozu.flywheel.backend.gl.GlStateTracker;
-import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
-import com.jozufozu.flywheel.core.RenderContext;
-
-import net.minecraft.client.renderer.MultiBufferSource;
-import net.minecraft.client.renderer.RenderType;
-
-@Mixin(MultiBufferSource.BufferSource.class)
-public class MultiBufferSourceMixin {
-
- @Inject(method = "endBatch(Lnet/minecraft/client/renderer/RenderType;)V", at = @At("TAIL"))
- private void renderLayer(RenderType renderType, CallbackInfo ci) {
- if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
- try (var restoreState = GlStateTracker.getRestoreState()) {
-
- InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, renderType);
-
- }
- }
- }
-
- @Inject(method = "endBatch()V", at = @At("TAIL"))
- private void endBatch(CallbackInfo ci) {
- if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
- try (var restoreState = GlStateTracker.getRestoreState()) {
- InstancedRenderDispatcher.renderAllRemaining(RenderContext.CURRENT);
- }
- }
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java
index beed0590a..be55e6518 100644
--- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java
@@ -5,6 +5,7 @@ import java.util.Map;
import java.util.stream.Stream;
import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor;
+import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
@@ -29,6 +30,13 @@ public class FlwUtil {
return new String(arr);
}
+ public static PoseStack copyPoseStack(PoseStack stack) {
+ PoseStack copy = new PoseStack();
+ copy.last().pose().load(stack.last().pose());
+ copy.last().normal().load(stack.last().normal());
+ return copy;
+ }
+
public static int numDigits(int number) {
// cursed but allegedly the fastest algorithm, taken from https://www.baeldung.com/java-number-of-digits-in-int
if (number < 100000) {
diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json
index 0f9d0df2e..71f847654 100644
--- a/src/main/resources/flywheel.mixins.json
+++ b/src/main/resources/flywheel.mixins.json
@@ -19,8 +19,9 @@
"InstanceAddMixin",
"InstanceRemoveMixin",
"LevelRendererAccessor",
+ "LevelRendererDispatchMixin",
+ "LevelRendererInstanceUpdateMixin",
"LevelRendererMixin",
- "MultiBufferSourceMixin",
"PausedPartialTickAccessor",
"RenderTypeMixin",
"light.LightUpdateMixin",