From 79464361d28a089d1f5cc875ff0ee790fbb477a0 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:03:20 -0700 Subject: [PATCH] Consists of inconsistency - Make architecture of indirect engine and draw manager match that of other engines and draw managers --- .../flywheel/backend/gl/GlStateTracker.java | 20 +-- .../indirect/IndirectDrawManager.java | 55 +++++++- .../instancing/indirect/IndirectEngine.java | 118 ++++++++---------- .../instancing/indirect/IndirectFactory.java | 50 -------- .../indirect/IndirectInstancerFactory.java | 34 +++++ .../instancing/indirect/IndirectMeshPool.java | 40 +++--- .../instancing/indirect/IndirectModel.java | 43 ------- .../instancing/InstancingEngine.java | 2 +- .../jozufozu/flywheel/core/BackendTypes.java | 2 +- 9 files changed, 169 insertions(+), 195 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectFactory.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancerFactory.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectModel.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java index 0dc4f4076..fc978eb90 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java @@ -23,28 +23,24 @@ public class GlStateTracker { return program; } - public static void _setBuffer(GlBufferType type, int buffer) { - BUFFERS[type.ordinal()] = buffer; - } - - public static void _setProgram(int id) { - program = id; + public static void _setBuffer(GlBufferType type, int id) { + BUFFERS[type.ordinal()] = id; } public static void _setVertexArray(int id) { vao = id; } + public static void _setProgram(int id) { + program = id; + } + public static State getRestoreState() { return new State(BUFFERS.clone(), vao, program); } public record State(int[] buffers, int vao, int program) implements AutoCloseable { public void restore() { - if (program != GlStateTracker.program) { - GlStateManager._glUseProgram(program); - } - if (vao != GlStateTracker.vao) { GlStateManager._glBindVertexArray(vao); } @@ -56,6 +52,10 @@ public class GlStateTracker { GlStateManager._glBindBuffer(values[i].glEnum, buffers[i]); } } + + if (program != GlStateTracker.program) { + GlStateManager._glUseProgram(program); + } } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawManager.java index 956694f59..18519271f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawManager.java @@ -1,23 +1,66 @@ package com.jozufozu.flywheel.backend.instancing.indirect; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.util.Pair; public class IndirectDrawManager { - public final Map, VertexType>, IndirectCullingGroup> lists = new HashMap<>(); + private final List uninitializedModels = new ArrayList<>(); + private final List> allInstancers = new ArrayList<>(); + public final Map, VertexType>, IndirectCullingGroup> renderLists = new HashMap<>(); + + public void create(IndirectInstancer instancer, Model model) { + uninitializedModels.add(new UninitializedModel(instancer, model)); + } + + public void flush() { + for (var model : uninitializedModels) { + add(model.instancer(), model.model()); + } + uninitializedModels.clear(); + + for (IndirectCullingGroup value : renderLists.values()) { + value.beginFrame(); + } + } + + public void delete() { + renderLists.values() + .forEach(IndirectCullingGroup::delete); + renderLists.clear(); + + allInstancers.forEach(IndirectInstancer::delete); + allInstancers.clear(); + } + + public void clearInstancers() { + allInstancers.forEach(IndirectInstancer::clear); + } @SuppressWarnings("unchecked") - public void add(IndirectInstancer instancer, Material material, Mesh mesh) { - var indirectList = (IndirectCullingGroup) lists.computeIfAbsent(Pair.of(instancer.type, mesh.getVertexType()), p -> new IndirectCullingGroup<>(p.first(), p.second())); + private void add(IndirectInstancer instancer, Model model) { + var meshes = model.getMeshes(); + for (var entry : meshes.entrySet()) { + var material = entry.getKey(); + var mesh = entry.getValue(); - indirectList.drawSet.add(instancer, material, indirectList.meshPool.alloc(mesh)); + var indirectList = (IndirectCullingGroup) renderLists.computeIfAbsent(Pair.of(instancer.type, mesh.getVertexType()), p -> new IndirectCullingGroup<>(p.first(), p.second())); + + indirectList.drawSet.add(instancer, material, indirectList.meshPool.alloc(mesh)); + + break; // TODO: support multiple meshes per model + } + allInstancers.add(instancer); + } + + private record UninitializedModel(IndirectInstancer instancer, Model model) { } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java index 5cbe78050..53bf9baba 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.backend.instancing.indirect; -import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,52 +30,55 @@ import net.minecraft.world.phys.Vec3; public class IndirectEngine implements Engine { - public static int MAX_ORIGIN_DISTANCE = 100; - - protected BlockPos originCoordinate = BlockPos.ZERO; - - protected final ContextShader context; - - protected final Map, IndirectFactory> factories = new HashMap<>(); - - protected final List> uninitializedModels = new ArrayList<>(); - protected final IndirectDrawManager indirectDrawManager = new IndirectDrawManager(); + protected final IndirectDrawManager drawManager = new IndirectDrawManager(); + protected final Map, IndirectInstancerFactory> factories = new HashMap<>(); /** * The set of instance managers that are attached to this engine. */ - private final WeakHashSet> instanceManagers; + private final WeakHashSet> instanceManagers = new WeakHashSet<>(); - public IndirectEngine(ContextShader context) { + protected final ContextShader context; + protected final int sqrMaxOriginDistance; + + protected BlockPos originCoordinate = BlockPos.ZERO; + + public IndirectEngine(ContextShader context, int sqrMaxOriginDistance) { this.context = context; - - this.instanceManagers = new WeakHashSet<>(); + this.sqrMaxOriginDistance = sqrMaxOriginDistance; } @SuppressWarnings("unchecked") @NotNull @Override - public IndirectFactory factory(StructType type) { - return (IndirectFactory) factories.computeIfAbsent(type, this::createFactory); + public IndirectInstancerFactory factory(StructType type) { + return (IndirectInstancerFactory) factories.computeIfAbsent(type, this::createFactory); } @NotNull - private IndirectFactory createFactory(StructType type) { - return new IndirectFactory<>(type, uninitializedModels::add); + private IndirectInstancerFactory createFactory(StructType type) { + return new IndirectInstancerFactory<>(type, drawManager::create); + } + + @Override + public void beginFrame(TaskEngine taskEngine, RenderContext context) { + try (var restoreState = GlStateTracker.getRestoreState()) { + drawManager.flush(); + } } @Override public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) { try (var restoreState = GlStateTracker.getRestoreState()) { setup(); - - for (var list : indirectDrawManager.lists.values()) { + + for (var list : drawManager.renderLists.values()) { list.submit(stage); } } } - private void setup() { + protected void setup() { GlTextureUnit.T2.makeActive(); Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); @@ -87,14 +90,31 @@ public class IndirectEngine implements Engine { } @Override - public void delete() { - factories.values() - .forEach(IndirectFactory::delete); + public boolean maintainOriginCoordinate(Camera camera) { + Vec3 cameraPos = camera.getPosition(); - indirectDrawManager.lists.values() - .forEach(IndirectCullingGroup::delete); + double distanceSqr = Vec3.atLowerCornerOf(originCoordinate) + .subtract(cameraPos) + .lengthSqr(); - factories.clear(); + if (distanceSqr > sqrMaxOriginDistance) { + shiftListeners(Mth.floor(cameraPos.x), Mth.floor(cameraPos.y), Mth.floor(cameraPos.z)); + return true; + } + return false; + } + + private void shiftListeners(int cX, int cY, int cZ) { + originCoordinate = new BlockPos(cX, cY, cZ); + + drawManager.clearInstancers(); + + instanceManagers.forEach(InstanceManager::onOriginShift); + } + + @Override + public void attachManagers(InstanceManager... listener) { + Collections.addAll(instanceManagers, listener); } @Override @@ -103,45 +123,9 @@ public class IndirectEngine implements Engine { } @Override - public void attachManagers(InstanceManager... listener) { - instanceManagers.addAll(List.of(listener)); - } - - @Override - public boolean maintainOriginCoordinate(Camera camera) { - Vec3 cameraPos = camera.getPosition(); - - 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, RenderContext context) { - try (var restoreState = GlStateTracker.getRestoreState()) { - for (var model : uninitializedModels) { - model.init(indirectDrawManager); - } - uninitializedModels.clear(); - - for (IndirectCullingGroup value : indirectDrawManager.lists.values()) { - value.beginFrame(); - } - } - } - - private void shiftListeners(int cX, int cY, int cZ) { - originCoordinate = new BlockPos(cX, cY, cZ); - - factories.values().forEach(IndirectFactory::clear); - - instanceManagers.forEach(InstanceManager::onOriginShift); + public void delete() { + factories.clear(); + drawManager.delete(); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectFactory.java deleted file mode 100644 index d0bfaa3b8..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.indirect; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - -import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.instancer.Instancer; -import com.jozufozu.flywheel.api.instancer.InstancerFactory; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; -import com.jozufozu.flywheel.core.model.Model; - -public class IndirectFactory implements InstancerFactory { - - protected final Map> models = new HashMap<>(); - protected final StructType type; - private final Consumer> creationListener; - - public IndirectFactory(StructType type, Consumer> creationListener) { - this.type = type; - this.creationListener = creationListener; - } - - @Override - public Instancer model(Model modelKey) { - return models.computeIfAbsent(modelKey, this::createInstancer).getInstancer(); - } - - public void delete() { - models.values().forEach(IndirectModel::delete); - models.clear(); - } - - /** - * Clear all instance data without freeing resources. - */ - public void clear() { - models.values() - .stream() - .map(IndirectModel::getInstancer) - .forEach(AbstractInstancer::clear); - } - - private IndirectModel createInstancer(Model model) { - var instancer = new IndirectModel<>(type, model); - this.creationListener.accept(instancer); - return instancer; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancerFactory.java new file mode 100644 index 000000000..286d3bc10 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancerFactory.java @@ -0,0 +1,34 @@ +package com.jozufozu.flywheel.backend.instancing.indirect; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +import com.jozufozu.flywheel.api.instancer.InstancedPart; +import com.jozufozu.flywheel.api.instancer.Instancer; +import com.jozufozu.flywheel.api.instancer.InstancerFactory; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.core.model.Model; + +public class IndirectInstancerFactory implements InstancerFactory { + + protected final StructType type; + private final BiConsumer, Model> creationListener; + protected final Map> models = new HashMap<>(); + + public IndirectInstancerFactory(StructType type, BiConsumer, Model> creationListener) { + this.type = type; + this.creationListener = creationListener; + } + + @Override + public Instancer model(Model modelKey) { + return models.computeIfAbsent(modelKey, this::createInstancer); + } + + private IndirectInstancer createInstancer(Model model) { + var instancer = new IndirectInstancer<>(type); + creationListener.accept(instancer, model); + return instancer; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java index 367e4ffdb..4868a8427 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java @@ -1,28 +1,28 @@ package com.jozufozu.flywheel.backend.instancing.indirect; -import static org.lwjgl.opengl.GL46.*; +import static org.lwjgl.opengl.GL15.glDeleteBuffers; +import static org.lwjgl.opengl.GL44.GL_DYNAMIC_STORAGE_BIT; +import static org.lwjgl.opengl.GL45.glCreateBuffers; +import static org.lwjgl.opengl.GL45.glNamedBufferStorage; +import static org.lwjgl.opengl.GL45.nglNamedBufferSubData; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; public class IndirectMeshPool { + private final VertexType vertexType; private final Map meshes = new HashMap<>(); private final List meshList = new ArrayList<>(); - final VertexType vertexType; - final int vbo; private final MemoryBlock clientStorage; @@ -76,7 +76,7 @@ public class IndirectMeshPool { model.buffer(ptr); - byteIndex += model.getByteSize(); + byteIndex += model.size(); baseVertex += model.mesh.getVertexCount(); } @@ -90,38 +90,44 @@ public class IndirectMeshPool { meshList.clear(); } - public class BufferedMesh { + public VertexType getVertexType() { + return vertexType; + } + public class BufferedMesh { public final Mesh mesh; private final int vertexCount; private long byteIndex; private int baseVertex; - public BufferedMesh(Mesh mesh) { + private BufferedMesh(Mesh mesh) { this.mesh = mesh; vertexCount = mesh.getVertexCount(); } private void buffer(long ptr) { - this.mesh.write(ptr + byteIndex); + mesh.write(ptr + byteIndex); } - public int getByteSize() { - return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.vertexCount; + public Mesh getMesh() { + return mesh; + } + + public int size() { + return mesh.size(); } public int getBaseVertex() { return baseVertex; } - public int getVertexCount() { - return this.vertexCount; + public int getIndexCount() { + return vertexCount * 6 / 4; } - public int getIndexCount() { - return this.vertexCount * 6 / 4; + public VertexType getVertexType() { + return vertexType; } } - } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectModel.java deleted file mode 100644 index 40492ab39..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectModel.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.indirect; - -import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.model.Model; - -public class IndirectModel { - - private final Model model; - private final IndirectInstancer instancer; - - public IndirectModel(StructType type, Model model) { - this.model = model; - this.instancer = new IndirectInstancer<>(type); - } - - public void init(IndirectDrawManager indirectDrawManager) { - var materialMeshMap = this.model.getMeshes(); - for (var entry : materialMeshMap.entrySet()) { - var material = entry.getKey(); - var mesh = entry.getValue(); - indirectDrawManager.add(instancer, material, mesh); - - return; // TODO: support multiple meshes per model - } - } - - public IndirectInstancer getInstancer() { - return instancer; - } - - public Model getModel() { - return model; - } - - public int getVertexCount() { - return model.getVertexCount() * instancer.instanceCount; - } - - public void 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 ed5a7fe55..47096cb01 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 @@ -80,7 +80,7 @@ public class InstancingEngine implements Engine { try (var restoreState = GlStateTracker.getRestoreState()) { setup(); - + render(drawSet); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java index f9bb63411..5436279ad 100644 --- a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java @@ -64,7 +64,7 @@ public class BackendTypes { .properName("GL46 Compute Culling") .shortName("indirect") .engineMessage(new TextComponent("Using Indirect Engine").withStyle(ChatFormatting.GREEN)) - .engineSupplier(() -> new IndirectEngine(Components.WORLD)) + .engineSupplier(() -> new IndirectEngine(Components.WORLD, 100 * 100)) .fallback(() -> BackendTypes.INSTANCING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supportsIndirect())