diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/IndexPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/IndexPool.java index 3b3a35e6f..35c94541a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/IndexPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/IndexPool.java @@ -1,7 +1,6 @@ package com.jozufozu.flywheel.backend.engine; import com.jozufozu.flywheel.api.model.IndexSequence; -import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.lib.memory.MemoryBlock; @@ -60,7 +59,7 @@ public class IndexPool { totalIndexCount += count; } - final var indexBlock = MemoryBlock.malloc(totalIndexCount * GlNumericType.UINT.byteWidth()); + final var indexBlock = MemoryBlock.malloc(totalIndexCount * Integer.BYTES); final long indexPtr = indexBlock.ptr(); int firstIndex = 0; @@ -70,7 +69,7 @@ public class IndexPool { firstIndices.put(indexSequence, firstIndex); - indexSequence.fill(indexPtr + (long) firstIndex * GlNumericType.UINT.byteWidth(), indexCount); + indexSequence.fill(indexPtr + (long) firstIndex * Integer.BYTES, indexCount); firstIndex += indexCount; } 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 41ba1e382..acff38427 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/MeshPool.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL32; @@ -17,13 +16,11 @@ import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.lib.memory.MemoryBlock; -import it.unimi.dsi.fastutil.objects.ReferenceArraySet; - public class MeshPool { private final VertexView vertexView; - private final Map meshes = new HashMap<>(); - private final List meshList = new ArrayList<>(); - private final List recentlyAllocated = new ArrayList<>(); + private final Map meshes = new HashMap<>(); + private final List meshList = new ArrayList<>(); + private final List recentlyAllocated = new ArrayList<>(); private final GlBuffer vbo; private final IndexPool indexPool; @@ -46,12 +43,12 @@ public class MeshPool { * @param mesh The model to allocate. * @return A handle to the allocated model. */ - public BufferedMesh alloc(Mesh mesh) { + public PooledMesh alloc(Mesh mesh) { return meshes.computeIfAbsent(mesh, this::_alloc); } - private BufferedMesh _alloc(Mesh m) { - BufferedMesh bufferedModel = new BufferedMesh(m); + private PooledMesh _alloc(Mesh m) { + PooledMesh bufferedModel = new PooledMesh(m); meshList.add(bufferedModel); recentlyAllocated.add(bufferedModel); @@ -60,7 +57,7 @@ public class MeshPool { } @Nullable - public BufferedMesh get(Mesh mesh) { + public MeshPool.PooledMesh get(Mesh mesh) { return meshes.get(mesh); } @@ -75,14 +72,15 @@ public class MeshPool { // Might want to shrink the index pool if something was removed. indexPool.reset(); - for (BufferedMesh mesh : meshList) { + for (PooledMesh mesh : meshList) { indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount()); } } else { // Otherwise, just update the index with the new counts. - for (BufferedMesh mesh : recentlyAllocated) { + for (PooledMesh mesh : recentlyAllocated) { indexPool.updateCount(mesh.mesh.indexSequence(), mesh.indexCount()); } + recentlyAllocated.clear(); } // Always need to flush the index pool. @@ -94,10 +92,10 @@ public class MeshPool { private void processDeletions() { // remove deleted meshes - meshList.removeIf(bufferedMesh -> { - boolean deleted = bufferedMesh.deleted(); + meshList.removeIf(pooledMesh -> { + boolean deleted = pooledMesh.deleted(); if (deleted) { - meshes.remove(bufferedMesh.mesh); + meshes.remove(pooledMesh.mesh); } return deleted; }); @@ -105,7 +103,7 @@ public class MeshPool { private void uploadAll() { long neededSize = 0; - for (BufferedMesh mesh : meshList) { + for (PooledMesh mesh : meshList) { neededSize += mesh.byteSize(); } @@ -114,18 +112,15 @@ public class MeshPool { int byteIndex = 0; int baseVertex = 0; - for (BufferedMesh mesh : meshList) { - mesh.byteIndex = byteIndex; + for (PooledMesh mesh : meshList) { mesh.baseVertex = baseVertex; - vertexView.ptr(vertexPtr + mesh.byteIndex); - vertexView.vertexCount(mesh.vertexCount); + vertexView.ptr(vertexPtr + byteIndex); + vertexView.vertexCount(mesh.vertexCount()); mesh.mesh.write(vertexView); byteIndex += mesh.byteSize(); baseVertex += mesh.vertexCount(); - - mesh.boundTo.clear(); } vbo.upload(vertexBlock); @@ -146,29 +141,24 @@ public class MeshPool { meshList.clear(); } - public class BufferedMesh { + public class PooledMesh { + public static final int INVALID_BASE_VERTEX = -1; private final Mesh mesh; - private final int vertexCount; - private final int byteSize; - private long byteIndex; - private int baseVertex; + private int baseVertex = INVALID_BASE_VERTEX; private int referenceCount = 0; - private final Set boundTo = new ReferenceArraySet<>(); - private BufferedMesh(Mesh mesh) { + private PooledMesh(Mesh mesh) { this.mesh = mesh; - vertexCount = mesh.vertexCount(); - byteSize = vertexCount * InternalVertex.STRIDE; } public int vertexCount() { - return vertexCount; + return mesh.vertexCount(); } public int byteSize() { - return byteSize; + return mesh.vertexCount() * InternalVertex.STRIDE; } public int indexCount() { @@ -180,7 +170,11 @@ public class MeshPool { } public int firstIndex() { - return indexPool.firstIndex(mesh.indexSequence()); + return MeshPool.this.indexPool.firstIndex(mesh.indexSequence()); + } + + public long firstIndexByteOffset() { + return (long) firstIndex() * Integer.BYTES; } public boolean deleted() { @@ -188,31 +182,22 @@ public class MeshPool { } public boolean invalid() { - return mesh.vertexCount() == 0 || deleted() || byteIndex == -1; + return mesh.vertexCount() == 0 || baseVertex == INVALID_BASE_VERTEX || deleted(); } public void draw(int instanceCount) { if (instanceCount > 1) { - GL32.glDrawElementsInstanced(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex(), instanceCount); + GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndexByteOffset(), instanceCount, baseVertex); } else { - GL32.glDrawElements(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex()); + GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndexByteOffset(), baseVertex); } } - public void setup(GlVertexArray vao) { - if (!boundTo.add(vao)) { - return; - } - MeshPool.this.indexPool.bind(vao); - vao.bindVertexBuffer(0, MeshPool.this.vbo.handle(), byteIndex, InternalVertex.STRIDE); - vao.bindAttributes(0, 0, InternalVertex.ATTRIBUTES); - } - public void acquire() { referenceCount++; } - public void drop() { + public void release() { if (--referenceCount == 0) { MeshPool.this.dirty = true; MeshPool.this.anyToRemove = true; 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 5dc332234..6e7b555d0 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 @@ -182,8 +182,8 @@ public class IndirectCullingGroup { instancers.add(instancer); for (var entry : model.meshes()) { - MeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.mesh()); - var draw = new IndirectDraw(instancer, entry.material(), bufferedMesh, stage); + MeshPool.PooledMesh pooledMesh = meshPool.alloc(entry.mesh()); + var draw = new IndirectDraw(instancer, entry.material(), pooledMesh, stage); indirectDraws.add(draw); instancer.addDraw(draw); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDraw.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDraw.java index f9fdbbd06..84b2ccd24 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDraw.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDraw.java @@ -11,7 +11,7 @@ import com.jozufozu.flywheel.backend.engine.MeshPool; public class IndirectDraw { private final IndirectInstancer model; private final Material material; - private final MeshPool.BufferedMesh mesh; + private final MeshPool.PooledMesh mesh; private final RenderStage stage; private final int materialVertexIndex; @@ -20,7 +20,7 @@ public class IndirectDraw { private final int packedMaterialProperties; private boolean deleted; - public IndirectDraw(IndirectInstancer model, Material material, MeshPool.BufferedMesh mesh, RenderStage stage) { + public IndirectDraw(IndirectInstancer model, Material material, MeshPool.PooledMesh mesh, RenderStage stage) { this.model = model; this.material = material; this.mesh = mesh; @@ -42,7 +42,7 @@ public class IndirectDraw { return material; } - public MeshPool.BufferedMesh mesh() { + public MeshPool.PooledMesh mesh() { return mesh; } @@ -85,7 +85,7 @@ public class IndirectDraw { return; } - mesh.drop(); + mesh.release(); deleted = true; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java index 38d2824b4..4471f5b85 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java @@ -1,30 +1,22 @@ package com.jozufozu.flywheel.backend.engine.instancing; -import org.jetbrains.annotations.Nullable; - import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; import com.jozufozu.flywheel.backend.engine.MeshPool; import com.jozufozu.flywheel.backend.gl.TextureBuffer; -import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; public class DrawCall { public final ShaderState shaderState; private final InstancedInstancer instancer; - private final MeshPool.BufferedMesh mesh; + private final MeshPool.PooledMesh mesh; - private final GlVertexArray vao; - @Nullable - private GlVertexArray vaoScratch; private boolean deleted; - public DrawCall(InstancedInstancer instancer, MeshPool.BufferedMesh mesh, ShaderState shaderState) { + public DrawCall(InstancedInstancer instancer, MeshPool.PooledMesh mesh, ShaderState shaderState) { this.instancer = instancer; this.mesh = mesh; this.shaderState = shaderState; mesh.acquire(); - - vao = GlVertexArray.create(); } public boolean deleted() { @@ -37,9 +29,6 @@ public class DrawCall { } instancer.bind(buffer); - mesh.setup(vao); - - vao.bindForDraw(); mesh.draw(instancer.instanceCount()); } @@ -54,36 +43,17 @@ public class DrawCall { return; } - var vao = lazyScratchVao(); - instancer.bind(buffer); - mesh.setup(vao); - - vao.bindForDraw(); mesh.draw(1); } - private GlVertexArray lazyScratchVao() { - if (vaoScratch == null) { - vaoScratch = GlVertexArray.create(); - } - return vaoScratch; - } - public void delete() { if (deleted) { return; } - vao.delete(); - - if (vaoScratch != null) { - vaoScratch.delete(); - vaoScratch = null; - } - - mesh.drop(); + mesh.release(); deleted = true; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java deleted file mode 100644 index 547283107..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.jozufozu.flywheel.backend.engine.instancing; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -import com.jozufozu.flywheel.api.backend.Engine; -import com.jozufozu.flywheel.api.context.TextureSource; -import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.backend.compile.InstancingPrograms; -import com.jozufozu.flywheel.backend.engine.CommonCrumbling; -import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; -import com.jozufozu.flywheel.backend.engine.MaterialRenderState; -import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; -import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; -import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; -import com.jozufozu.flywheel.backend.gl.TextureBuffer; -import com.jozufozu.flywheel.lib.context.ContextShaders; -import com.jozufozu.flywheel.lib.context.Contexts; -import com.jozufozu.flywheel.lib.material.SimpleMaterial; - -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import net.minecraft.client.resources.model.ModelBakery; - -public class InstancedCrumbling { - public static void render(List crumblingBlocks, InstancingPrograms programs, TextureSource textureSource, TextureBuffer instanceTexture) { - // Sort draw calls into buckets, so we don't have to do as many shader binds. - var byShaderState = doCrumblingSort(crumblingBlocks); - - if (byShaderState.isEmpty()) { - return; - } - - var crumblingMaterial = SimpleMaterial.builder(); - - try (var state = GlStateTracker.getRestoreState()) { - TextureBinder.bindLightAndOverlay(); - - for (var shaderStateEntry : byShaderState.entrySet()) { - var byProgress = shaderStateEntry.getValue(); - - if (byProgress.isEmpty()) { - continue; - } - - ShaderState shader = shaderStateEntry.getKey(); - - CommonCrumbling.applyCrumblingProperties(crumblingMaterial, shader.material()); - - var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING); - program.bind(); - - Uniforms.bindForDraw(); - InstancingEngine.uploadMaterialUniform(program, crumblingMaterial); - - MaterialRenderState.setup(crumblingMaterial); - - for (var progressEntry : byProgress.int2ObjectEntrySet()) { - var drawCalls = progressEntry.getValue(); - - if (drawCalls.isEmpty()) { - continue; - } - - var context = Contexts.CRUMBLING.get(progressEntry.getIntKey()); - context.prepare(crumblingMaterial, program, textureSource); - - GlTextureUnit.T3.makeActive(); - program.setSamplerBinding("_flw_instances", 3); - - for (Consumer drawCall : drawCalls) { - drawCall.accept(instanceTexture); - } - - TextureBinder.resetTextureBindings(); - } - } - - MaterialRenderState.reset(); - TextureBinder.resetLightAndOverlay(); - } - } - - private static Map>>> doCrumblingSort(List instances) { - Map>>> out = new HashMap<>(); - - for (Engine.CrumblingBlock triple : instances) { - int progress = triple.progress(); - - if (progress < 0 || progress >= ModelBakery.DESTROY_TYPES.size()) { - continue; - } - - for (Instance instance : triple.instances()) { - // Filter out instances that weren't created by this engine. - // If all is well, we probably shouldn't take the `continue` - // branches but better to do checked casts. - if (!(instance.handle() instanceof InstanceHandleImpl impl)) { - continue; - } - if (!(impl.instancer instanceof InstancedInstancer instancer)) { - continue; - } - - for (DrawCall draw : instancer.drawCalls()) { - out.computeIfAbsent(draw.shaderState, $ -> new Int2ObjectArrayMap<>()) - .computeIfAbsent(progress, $ -> new ArrayList<>()) - .add(buf -> draw.renderOne(buf, impl)); - } - } - } - - return out; - } -} 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 c16da5c8b..82e08917d 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 @@ -1,31 +1,72 @@ package com.jozufozu.flywheel.backend.engine.instancing; +import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.function.Consumer; + +import org.lwjgl.opengl.GL32; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; +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.material.Material; +import com.jozufozu.flywheel.backend.ShaderIndices; +import com.jozufozu.flywheel.backend.compile.InstancingPrograms; +import com.jozufozu.flywheel.backend.engine.CommonCrumbling; +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; +import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; +import com.jozufozu.flywheel.backend.engine.textures.TextureSourceImpl; +import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; +import com.jozufozu.flywheel.backend.gl.GlStateTracker; +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; +import com.jozufozu.flywheel.backend.gl.TextureBuffer; +import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.lib.context.ContextShaders; +import com.jozufozu.flywheel.lib.context.Contexts; +import com.jozufozu.flywheel.lib.material.SimpleMaterial; + +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> { /** * The set of draw calls to make in each {@link RenderStage}. */ private final Map drawSets = new EnumMap<>(RenderStage.class); + private final InstancingPrograms programs; /** * A map of vertex types to their mesh pools. */ - private final MeshPool meshPool = new MeshPool(); + private final MeshPool meshPool; + private final GlVertexArray vao; + private final TextureSourceImpl textures; + private final TextureBuffer instanceTexture; - public DrawSet get(RenderStage stage) { - return drawSets.getOrDefault(stage, DrawSet.EMPTY); + public InstancedDrawManager(InstancingPrograms programs) { + programs.acquire(); + this.programs = programs; + + meshPool = new MeshPool(); + vao = GlVertexArray.create(); + textures = new TextureSourceImpl(); + instanceTexture = new TextureBuffer(); + + meshPool.bind(vao); } public void flush() { @@ -52,17 +93,70 @@ public class InstancedDrawManager extends InstancerStorage meshPool.flush(); } + public void renderStage(RenderStage stage) { + var drawSet = drawSets.getOrDefault(stage, DrawSet.EMPTY); + + if (drawSet.isEmpty()) { + return; + } + + try (var state = GlStateTracker.getRestoreState()) { + render(drawSet); + } + } + public void delete() { instancers.values() .forEach(InstancedInstancer::delete); - super.delete(); - - meshPool.delete(); - drawSets.values() .forEach(DrawSet::delete); drawSets.clear(); + + meshPool.delete(); + instanceTexture.delete(); + programs.release(); + vao.delete(); + + super.delete(); + } + + private void render(InstancedDrawManager.DrawSet drawSet) { + Uniforms.bindForDraw(); + vao.bindForDraw(); + TextureBinder.bindLightAndOverlay(); + + for (var entry : drawSet) { + var shader = entry.getKey(); + var drawCalls = entry.getValue(); + + if (drawCalls.isEmpty()) { + continue; + } + + var context = shader.context(); + var material = shader.material(); + + var program = programs.get(shader.instanceType(), context.contextShader()); + program.bind(); + + uploadMaterialUniform(program, material); + + context.prepare(material, program, textures); + MaterialRenderState.setup(material); + + GlTextureUnit.T3.makeActive(); + + program.setSamplerBinding("_flw_instances", 3); + + for (var drawCall : drawCalls) { + drawCall.render(instanceTexture); + } + TextureBinder.resetTextureBindings(); + } + + MaterialRenderState.reset(); + TextureBinder.resetLightAndOverlay(); } @Override @@ -89,6 +183,106 @@ public class InstancedDrawManager extends InstancerStorage } } + public void renderCrumbling(List crumblingBlocks) { + // Sort draw calls into buckets, so we don't have to do as many shader binds. + var byShaderState = doCrumblingSort(crumblingBlocks); + + if (byShaderState.isEmpty()) { + return; + } + + var crumblingMaterial = SimpleMaterial.builder(); + + try (var state = GlStateTracker.getRestoreState()) { + Uniforms.bindForDraw(); + vao.bindForDraw(); + TextureBinder.bindLightAndOverlay(); + + for (var shaderStateEntry : byShaderState.entrySet()) { + var byProgress = shaderStateEntry.getValue(); + + if (byProgress.isEmpty()) { + continue; + } + + ShaderState shader = shaderStateEntry.getKey(); + + CommonCrumbling.applyCrumblingProperties(crumblingMaterial, shader.material()); + + var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING); + program.bind(); + + uploadMaterialUniform(program, crumblingMaterial); + + MaterialRenderState.setup(crumblingMaterial); + + for (var progressEntry : byProgress.int2ObjectEntrySet()) { + var drawCalls = progressEntry.getValue(); + + if (drawCalls.isEmpty()) { + continue; + } + + var context = Contexts.CRUMBLING.get(progressEntry.getIntKey()); + context.prepare(crumblingMaterial, program, textures); + + GlTextureUnit.T3.makeActive(); + program.setSamplerBinding("_flw_instances", 3); + + for (Consumer drawCall : drawCalls) { + drawCall.accept(instanceTexture); + } + + TextureBinder.resetTextureBindings(); + } + } + + MaterialRenderState.reset(); + TextureBinder.resetLightAndOverlay(); + } + } + + private static Map>>> doCrumblingSort(List instances) { + Map>>> out = new HashMap<>(); + + for (Engine.CrumblingBlock triple : instances) { + int progress = triple.progress(); + + if (progress < 0 || progress >= ModelBakery.DESTROY_TYPES.size()) { + continue; + } + + for (Instance instance : triple.instances()) { + // Filter out instances that weren't created by this engine. + // If all is well, we probably shouldn't take the `continue` + // branches but better to do checked casts. + if (!(instance.handle() instanceof InstanceHandleImpl impl)) { + continue; + } + if (!(impl.instancer instanceof InstancedInstancer instancer)) { + continue; + } + + for (DrawCall draw : instancer.drawCalls()) { + out.computeIfAbsent(draw.shaderState, $ -> new Int2ObjectArrayMap<>()) + .computeIfAbsent(progress, $ -> new ArrayList<>()) + .add(buf -> draw.renderOne(buf, impl)); + } + } + } + + return out; + } + + public static void uploadMaterialUniform(GlProgram program, Material material) { + int uniformLocation = program.getUniformLocation("_flw_packedMaterial"); + int vertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders()); + int fragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders()); + int packedFogAndCutout = MaterialEncoder.packFogAndCutout(material); + int packedMaterialProperties = MaterialEncoder.packProperties(material); + GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties); + } + public static class DrawSet implements Iterable>> { public static final DrawSet EMPTY = new DrawSet(ImmutableListMultimap.of()); 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 index 41747eea8..ad8964712 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java @@ -2,43 +2,28 @@ package com.jozufozu.flywheel.backend.engine.instancing; import java.util.List; -import org.lwjgl.opengl.GL32; - import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; -import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.task.TaskExecutor; -import com.jozufozu.flywheel.backend.ShaderIndices; 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.MaterialEncoder; -import com.jozufozu.flywheel.backend.engine.MaterialRenderState; -import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; -import com.jozufozu.flywheel.backend.engine.textures.TextureSourceImpl; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; -import com.jozufozu.flywheel.backend.gl.TextureBuffer; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; 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 InstancingPrograms programs; - private final TextureSourceImpl textures = new TextureSourceImpl(); - private final TextureBuffer instanceTexture = new TextureBuffer(); - private final InstancedDrawManager drawManager = new InstancedDrawManager(); + private final InstancedDrawManager drawManager; private final Flag flushFlag = new NamedFlag("flushed"); public InstancingEngine(InstancingPrograms programs, int maxOriginDistance) { super(maxOriginDistance); - programs.acquire(); - this.programs = programs; - } + drawManager = new InstancedDrawManager(programs); + } @Override public Plan createFramePlan() { @@ -60,16 +45,7 @@ public class InstancingEngine extends AbstractEngine { flushFlag.lower(); } - var drawSet = drawManager.get(stage); - - if (drawSet.isEmpty()) { - return; - } - - try (var state = GlStateTracker.getRestoreState()) { - Uniforms.bindForDraw(); - render(drawSet); - } + drawManager.renderStage(stage); } @Override @@ -77,7 +53,7 @@ public class InstancingEngine extends AbstractEngine { // Need to wait for flush before we can inspect instancer state. executor.syncUntil(flushFlag::isRaised); - InstancedCrumbling.render(crumblingBlocks, programs, textures, instanceTexture); + drawManager.renderCrumbling(crumblingBlocks); } @Override @@ -88,52 +64,5 @@ public class InstancingEngine extends AbstractEngine { @Override public void delete() { drawManager.delete(); - programs.release(); - instanceTexture.delete(); - } - - private void render(InstancedDrawManager.DrawSet drawSet) { - TextureBinder.bindLightAndOverlay(); - - for (var entry : drawSet) { - var shader = entry.getKey(); - var drawCalls = entry.getValue(); - - if (drawCalls.isEmpty()) { - continue; - } - - var context = shader.context(); - var material = shader.material(); - - var program = programs.get(shader.instanceType(), context.contextShader()); - program.bind(); - - uploadMaterialUniform(program, material); - - context.prepare(material, program, textures); - MaterialRenderState.setup(material); - - GlTextureUnit.T3.makeActive(); - - program.setSamplerBinding("_flw_instances", 3); - - for (var drawCall : drawCalls) { - drawCall.render(instanceTexture); - } - TextureBinder.resetTextureBindings(); - } - - MaterialRenderState.reset(); - TextureBinder.resetLightAndOverlay(); - } - - public static void uploadMaterialUniform(GlProgram program, Material material) { - int uniformLocation = program.getUniformLocation("_flw_packedMaterial"); - int vertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders()); - int fragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders()); - int packedFogAndCutout = MaterialEncoder.packFogAndCutout(material); - int packedMaterialProperties = MaterialEncoder.packProperties(material); - GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/LineModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/LineModelBuilder.java index 85f0bdd74..b266d1e4e 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/LineModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/LineModelBuilder.java @@ -98,7 +98,7 @@ public class LineModelBuilder { public static class LineMesh implements Mesh { public static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> { - int numVertices = 4 * (count / 6); + int numVertices = 2 * count / 3; int baseVertex = 0; while (baseVertex < numVertices) { // triangle a