diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java b/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java index de7c9dfc1..02eb42db9 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java @@ -4,7 +4,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart; public interface StorageBufferWriter { - void write(final long ptr, final T instance, final int batchID); + void write(final long ptr, final T instance); int getAlignment(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 7f923e5a3..25893bac4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -52,8 +52,7 @@ public class Loader implements ResourceManagerReloadListener { FileResolution.run(errorReporter, sources); if (errorReporter.hasErrored()) { - errorReporter.dump(); - throw new ShaderLoadingException("Failed to resolve all source files, see log for details"); + throw errorReporter.dump(); } sources.postResolve(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java index a104faf26..151fbcb03 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java @@ -5,6 +5,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.compile.CompileUtil; import com.jozufozu.flywheel.core.compile.Memoizer; import com.jozufozu.flywheel.core.compile.ProgramAssembler; import com.jozufozu.flywheel.core.compile.ShaderCompilationException; @@ -24,7 +25,7 @@ public class ComputeCullerCompiler extends Memoizer { CompilationContext context = new CompilationContext(); - var header = GLSLVersion.V460.getVersionLine(); + var header = CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE); String source = file.getFile() .generateFinalSource(context); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/FrustumUBO.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/FrustumUBO.java deleted file mode 100644 index 554d78dea..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/FrustumUBO.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.indirect; - -import static org.lwjgl.opengl.GL46.*; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.util.joml.FrustumIntersection; - -// This should be a push constant :whywheel: -public class FrustumUBO { - - public static final int BUFFER_SIZE = 96; - - private final int ubo; - private final long clientStorage; - - FrustumUBO() { - ubo = glCreateBuffers(); - glNamedBufferStorage(ubo, BUFFER_SIZE, GL_DYNAMIC_STORAGE_BIT); - clientStorage = MemoryUtil.nmemAlloc(BUFFER_SIZE); - } - - public void update(FrustumIntersection frustum) { - frustum.getJozuPackedPlanes(clientStorage); - nglNamedBufferSubData(ubo, 0, BUFFER_SIZE, clientStorage); - } - - public void bind() { - glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo); - } -} 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 ddc66f0a1..a422428cc 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 @@ -45,8 +45,6 @@ public class IndirectEngine implements Engine { protected final List> uninitializedModels = new ArrayList<>(); protected final RenderLists renderLists = new RenderLists(); - private FrustumUBO frustumUBO; - /** * The set of instance managers that are attached to this engine. */ @@ -77,7 +75,7 @@ public class IndirectEngine implements Engine { setup(); for (var group : groups) { - group.submit(frustumUBO); + group.submit(); } } @@ -146,26 +144,10 @@ public class IndirectEngine implements Engine { @Override public void beginFrame(TaskEngine taskEngine, RenderContext context) { - if (frustumUBO == null) { - frustumUBO = new FrustumUBO(); - } - for (var model : uninitializedModels) { model.init(renderLists); } uninitializedModels.clear(); - - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - - var culler = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); - - frustumUBO.update(culler); - } private void shiftListeners(int cX, int cY, int cZ) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java index 5e6642b7e..fb5874298 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java @@ -21,7 +21,8 @@ import com.jozufozu.flywheel.core.vertex.Formats; public class IndirectList { - private static final long DRAW_COMMAND_STRIDE = 20; + private static final long DRAW_COMMAND_STRIDE = 48; + private static final long DRAW_COMMAND_OFFSET = 0; final StorageBufferWriter storageBufferWriter; final GlProgram compute; @@ -31,18 +32,15 @@ public class IndirectList { private final long objectStride; private final int maxBatchCount; private final long objectClientStorage; + private final long batchIDClientStorage; private final int elementBuffer; /** * Stores raw instance data per-object. */ int objectBuffer; - int targetBuffer; - /** - * Stores bounding spheres - */ - int boundingSphereBuffer; + int batchBuffer; /** * Stores drawIndirect structs. @@ -69,7 +67,7 @@ public class IndirectList { glCreateBuffers(shaderStorageBuffers); objectBuffer = shaderStorageBuffers[0]; targetBuffer = shaderStorageBuffers[1]; - boundingSphereBuffer = shaderStorageBuffers[2]; + batchBuffer = shaderStorageBuffers[2]; drawBuffer = shaderStorageBuffers[3]; debugBuffer = shaderStorageBuffers[4]; meshPool = new IndirectMeshPool(Formats.BLOCK, 1024); @@ -78,15 +76,15 @@ public class IndirectList { maxObjectCount = 1024L; maxBatchCount = 64; - // +4 for the batch id objectStride = storageBufferWriter.getAlignment(); glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); - glNamedBufferStorage(boundingSphereBuffer, 16 * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); + glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(debugBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount); + batchIDClientStorage = MemoryUtil.nmemAlloc(4 * maxObjectCount); vertexArray = glCreateVertexArrays(); @@ -121,7 +119,7 @@ public class IndirectList { batches.add(new Batch<>(instancer, meshPool.alloc(mesh))); } - void submit(FrustumUBO frustumUBO) { + void submit() { int instanceCountThisFrame = calculateTotalInstanceCount(); if (instanceCountThisFrame == 0) { @@ -130,24 +128,22 @@ public class IndirectList { meshPool.uploadAll(); uploadInstanceData(); - uploadBoundingSpheres(); uploadIndirectCommands(); - frustumUBO.bind(); + UniformBuffer.getInstance().sync(); + dispatchCompute(instanceCountThisFrame); issueMemoryBarrier(); dispatchDraw(); } private void dispatchDraw() { - UniformBuffer.getInstance().sync(); - draw.bind(); Materials.BELL.setup(); glVertexArrayElementBuffer(vertexArray, elementBuffer); glBindVertexArray(vertexArray); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawBuffer); - glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, 0, batches.size(), 0); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, DRAW_COMMAND_OFFSET, batches.size(), (int) DRAW_COMMAND_STRIDE); Materials.BELL.clear(); } @@ -155,27 +151,11 @@ public class IndirectList { glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); } - private void uploadBoundingSpheres() { - try (var stack = MemoryStack.stackPush()) { - final int size = batches.size() * 16; - final long basePtr = stack.nmalloc(size); - - long ptr = basePtr; - for (Batch batch : batches) { - var boundingSphere = batch.mesh.mesh.getBoundingSphere(); - boundingSphere.getToAddress(ptr); - ptr += 16; - } - - nglNamedBufferSubData(boundingSphereBuffer, 0, size, basePtr); - } - } - private void dispatchCompute(int instanceCount) { compute.bind(); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, objectBuffer, 0, instanceCount * objectStride); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, targetBuffer, 0, instanceCount * 4L); - glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, boundingSphereBuffer, 0, batches.size() * 16L); + glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, batchBuffer, 0, instanceCount * 4L); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, drawBuffer, 0, batches.size() * DRAW_COMMAND_STRIDE); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 4, debugBuffer, 0, instanceCount * 4L); @@ -184,22 +164,28 @@ public class IndirectList { } private void uploadInstanceData() { - long ptr = objectClientStorage; + long objectPtr = objectClientStorage; + long batchIDPtr = batchIDClientStorage; int baseInstance = 0; int batchID = 0; for (var batch : batches) { batch.baseInstance = baseInstance; var instancer = batch.instancer; for (T t : instancer.getAll()) { - storageBufferWriter.write(ptr, t, batchID); - ptr += objectStride; + // write object + storageBufferWriter.write(objectPtr, t); + objectPtr += objectStride; + + // write batchID + MemoryUtil.memPutInt(batchIDPtr, batchID); + batchIDPtr += 4; } baseInstance += batch.instancer.instanceCount; batchID++; } - nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage); - + nglNamedBufferSubData(objectBuffer, 0, objectPtr - objectClientStorage, objectClientStorage); + nglNamedBufferSubData(batchBuffer, 0, batchIDPtr - batchIDClientStorage, batchIDClientStorage); } private void uploadIndirectCommands() { @@ -235,11 +221,15 @@ public class IndirectList { } public void writeIndirectCommand(long ptr) { - MemoryUtil.memPutInt(ptr, mesh.getVertexCount()); // count + var boundingSphere = mesh.mesh.getBoundingSphere(); + + MemoryUtil.memPutInt(ptr, mesh.getIndexCount()); // count MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be incremented by the compute shader MemoryUtil.memPutInt(ptr + 8, 0); // firstIndex - all models share the same index buffer MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance + + boundingSphere.getToAddress(ptr + 32); // boundingSphere } } } 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 ade54f176..b88fb380e 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 @@ -89,11 +89,14 @@ public class IndirectMeshPool { public class BufferedMesh { public final Mesh mesh; + private final int vertexCount; private long byteIndex; private int baseVertex; public BufferedMesh(Mesh mesh) { this.mesh = mesh; + + vertexCount = mesh.getVertexCount(); } private void buffer(ByteBuffer buffer) { @@ -103,7 +106,7 @@ public class IndirectMeshPool { } public int getByteSize() { - return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.mesh.getVertexCount(); + return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.vertexCount; } public int getBaseVertex() { @@ -111,7 +114,11 @@ public class IndirectMeshPool { } public int getVertexCount() { - return this.mesh.getVertexCount(); + return this.vertexCount; + } + + public int getIndexCount() { + return this.vertexCount * 6 / 4; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysCompiler.java index e6848c084..4a4f92779 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysCompiler.java @@ -112,6 +112,7 @@ public class InstancedArraysCompiler extends Memoizer maxLength) maxLength = length; + if (length > maxLength) { + maxLength = length; + } } StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java index 859ec71e2..90224f0e2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java @@ -3,9 +3,11 @@ package com.jozufozu.flywheel.core.source.error; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.parse.ShaderFunction; import com.jozufozu.flywheel.core.source.parse.ShaderStruct; @@ -82,10 +84,12 @@ public class ErrorReporter { return !reportedErrors.isEmpty(); } - public void dump() { - for (var error : reportedErrors) { - Backend.LOGGER.error(error.build()); - } + public ShaderLoadingException dump() { + var allErrors = reportedErrors.stream() + .map(ErrorBuilder::build) + .collect(Collectors.joining()); + + return new ShaderLoadingException(allErrors); } public static void printLines(CharSequence source) { diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java index 07c40e7e5..ffea61b53 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java @@ -13,7 +13,7 @@ public class OrientedStorageWriter implements StorageBufferWriter } @Override - public void write(final long ptr, OrientedPart d, final int batchID) { + public void write(final long ptr, OrientedPart d) { MemoryUtil.memPutFloat(ptr, d.qX); MemoryUtil.memPutFloat(ptr + 4, d.qY); MemoryUtil.memPutFloat(ptr + 8, d.qZ); @@ -27,15 +27,13 @@ public class OrientedStorageWriter implements StorageBufferWriter MemoryUtil.memPutFloat(ptr + 36, d.pivotY); MemoryUtil.memPutFloat(ptr + 40, d.pivotZ); - MemoryUtil.memPutShort(ptr + 44, d.blockLight); - MemoryUtil.memPutShort(ptr + 46, d.skyLight); + MemoryUtil.memPutShort(ptr + 44, d.skyLight); + MemoryUtil.memPutShort(ptr + 46, d.blockLight); MemoryUtil.memPutByte(ptr + 48, d.r); MemoryUtil.memPutByte(ptr + 49, d.g); MemoryUtil.memPutByte(ptr + 50, d.b); MemoryUtil.memPutByte(ptr + 51, d.a); - - MemoryUtil.memPutInt(ptr + 52, batchID); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java new file mode 100644 index 000000000..9070a7eae --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java @@ -0,0 +1,60 @@ +package com.jozufozu.flywheel.core.uniform; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.RenderContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.event.BeginFrameEvent; +import com.jozufozu.flywheel.util.extension.MatrixExtension; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Vec3i; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; + +public class FrustumProvider extends UniformProvider { + + public FrustumProvider() { + MinecraftForge.EVENT_BUS.addListener(this::beginFrame); + } + + @Override + public int getActualByteSize() { + return 96; + } + + @Override + public FileResolution getUniformShader() { + return Components.Files.FRUSTUM_UNIFORMS; + } + + public void beginFrame(BeginFrameEvent event) { + update(event.getContext()); + } + + public void update(RenderContext context) { + if (buffer == null) { + return; + } + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); + + long ptr = MemoryUtil.memAddress(buffer); + + shiftedCuller.getJozuPackedPlanes(ptr); + + notifier.signalChanged(); + } +} diff --git a/src/main/resources/assets/flywheel/flywheel/api/cull.glsl b/src/main/resources/assets/flywheel/flywheel/api/cull.glsl new file mode 100644 index 000000000..d89bebbf3 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/api/cull.glsl @@ -0,0 +1,4 @@ +#ifdef COMPUTE_SHADER +uint flw_objectID; +uint flw_batchID; +#endif diff --git a/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl b/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl index 735f7a84e..11be92a1e 100644 --- a/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl +++ b/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl @@ -1,3 +1,4 @@ +#ifdef FRAGMENT_SHADER in vec4 flw_vertexPos; in vec4 flw_vertexColor; in vec2 flw_vertexTexCoord; @@ -32,3 +33,4 @@ vec4 flw_fogFilter(vec4 color); * Guard calls with FLW_DISCARD */ bool flw_discardPredicate(vec4 finalColor); +#endif diff --git a/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl b/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl index c5d670ec3..c00b99cbd 100644 --- a/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl +++ b/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl @@ -1,3 +1,4 @@ +#ifdef VERTEX_SHADER out vec4 flw_vertexPos; out vec4 flw_vertexColor; out vec2 flw_vertexTexCoord; @@ -11,3 +12,4 @@ out vec4 flw_var0; out vec4 flw_var1; out vec4 flw_var2; out vec4 flw_var3; +#endif diff --git a/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl b/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl index 361ca6810..705b379c2 100644 --- a/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl +++ b/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl @@ -1,67 +1,60 @@ #define FLW_SUBGROUP_SIZE 32 layout(local_size_x = FLW_SUBGROUP_SIZE) in; -#use "flywheel:compute/objects.glsl" +#use "flywheel:api/cull.glsl" #use "flywheel:util/quaternion.glsl" +#use "flywheel:uniform/frustum.glsl" +#use "flywheel:instance/oriented_indirect.glsl" -uint flw_objectID; -uint flw_batchID; +struct MeshDrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + uint vertexOffset; + uint baseInstance; -layout(std140, binding = 0) uniform FrameData { - vec4 a1; // vec4(nx.x, px.x, ny.x, py.x) - vec4 a2; // vec4(nx.y, px.y, ny.y, py.y) - vec4 a3; // vec4(nx.z, px.z, ny.z, py.z) - vec4 a4; // vec4(nx.w, px.w, ny.w, py.w) - vec2 b1; // vec2(nz.x, pz.x) - vec2 b2; // vec2(nz.y, pz.y) - vec2 b3; // vec2(nz.z, pz.z) - vec2 b4; // vec2(nz.w, pz.w) -} frustum; - -// populated by instancers -layout(std430, binding = 0) readonly buffer ObjectBuffer { - Instance objects[]; + vec4 boundingSphere; }; -layout(std430, binding = 1) writeonly buffer TargetBuffer { +// populated by instancers +layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { + FLW_INSTANCE_STRUCT objects[]; +}; + +layout(std430, binding = 1) restrict writeonly buffer TargetBuffer { uint objectIDs[]; }; -layout(std430, binding = 2) readonly buffer BoundingSpheres { - vec4 boundingSpheres[]; +layout(std430, binding = 2) restrict readonly buffer BatchBuffer { + uint batchIDs[]; }; -layout(std430, binding = 3) buffer DrawCommands { +layout(std430, binding = 3) restrict buffer DrawCommands { MeshDrawCommand drawCommands[]; }; -layout(std430, binding = 4) writeonly buffer DebugVisibility { +layout(std430, binding = 4) restrict writeonly buffer DebugVisibility { uint objectVisibilityBits[]; }; // 83 - 27 = 56 spirv instruction results bool testSphere(vec3 center, float radius) { - bvec4 resultA = greaterThanEqual(fma(frustum.a1, center.xxxx, fma(frustum.a2, center.yyyy, fma(frustum.a3, center.zzzz, frustum.a4))), -radius.xxxx); - bvec2 resultB = greaterThanEqual(fma(frustum.b1, center.xx, fma(frustum.b2, center.yy, fma(frustum.b3, center.zz, frustum.b4))), -radius.xx); + bvec4 xyInside = greaterThanEqual(fma(flw_planes.xyX, center.xxxx, fma(flw_planes.xyY, center.yyyy, fma(flw_planes.xyZ, center.zzzz, flw_planes.xyW))), -radius.xxxx); + bvec2 zInside = greaterThanEqual(fma(flw_planes.zX, center.xx, fma(flw_planes.zY, center.yy, fma(flw_planes.zZ, center.zz, flw_planes.zW))), -radius.xx); - uint debug = uint(resultA.x); - debug |= uint(resultA.y) << 1; - debug |= uint(resultA.z) << 2; - debug |= uint(resultA.w) << 3; - debug |= uint(resultB.x) << 4; - debug |= uint(resultB.y) << 5; + uint debug = uint(xyInside.x); + debug |= uint(xyInside.y) << 1; + debug |= uint(xyInside.z) << 2; + debug |= uint(xyInside.w) << 3; + debug |= uint(zInside.x) << 4; + debug |= uint(zInside.y) << 5; objectVisibilityBits[flw_objectID] = debug; - return all(resultA) && all(resultB); -} - -void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) { - center = rotateVertexByQuat(center - i.pivot, i.rotation) + i.pivot + i.pos; - radius = radius; + return all(xyInside) && all(zInside); } bool isVisible() { - vec4 sphere = boundingSpheres[flw_batchID]; + vec4 sphere = drawCommands[flw_batchID].boundingSphere; vec3 center = sphere.xyz; float radius = sphere.r; @@ -77,7 +70,7 @@ void main() { return; } - flw_batchID = objects[objectID].batchID; + flw_batchID = batchIDs[flw_objectID]; if (isVisible()) { uint batchIndex = atomicAdd(drawCommands[flw_batchID].instanceCount, 1); diff --git a/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert index 030d82200..66fea9dae 100644 --- a/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert +++ b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert @@ -1,25 +1,18 @@ #use "flywheel:api/vertex.glsl" -#use "flywheel:compute/objects.glsl" #use "flywheel:layout/block.vert" #use "flywheel:context/world.vert" #use "flywheel:util/quaternion.glsl" +#use "flywheel:instance/oriented_indirect.glsl" // populated by instancers -layout(std430, binding = 0) readonly buffer ObjectBuffer { - Instance objects[]; +layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { + FLW_INSTANCE_STRUCT objects[]; }; -layout(std430, binding = 1) readonly buffer TargetBuffer { +layout(std430, binding = 1) restrict readonly buffer TargetBuffer { uint objectIDs[]; }; -void flw_instanceVertex(Instance i) { - flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.pos, 1.0); - flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation); - flw_vertexColor = unpackUnorm4x8(i.color); - flw_vertexLight = unpackUnorm2x16(i.light) / 15.0; -} - void main() { uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID]; flw_layoutVertex(); diff --git a/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl b/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl deleted file mode 100644 index 635ae39db..000000000 --- a/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl +++ /dev/null @@ -1,17 +0,0 @@ - -struct Instance { - vec4 rotation; - vec3 pos; - vec3 pivot; - uint light; - uint color; - uint batchID; -}; - -struct MeshDrawCommand { - uint indexCount; - uint instanceCount; - uint firstIndex; - uint vertexOffset; - uint baseInstance; -}; diff --git a/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl b/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl new file mode 100644 index 000000000..c02c57bfc --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl @@ -0,0 +1,24 @@ +#use "flywheel:api/vertex.glsl" +#use "flywheel:util/quaternion.glsl" +#define FLW_INSTANCE_STRUCT Instance + +struct Instance { + vec4 rotation; + vec3 pos; + vec3 pivot; + uint light; + uint color; +}; + +void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) { + center = rotateVertexByQuat(center - i.pivot, i.rotation) + i.pivot + i.pos; +} + +#ifdef VERTEX_SHADER +void flw_instanceVertex(Instance i) { + flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.pos, 1.0); + flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation); + flw_vertexColor = unpackUnorm4x8(i.color); + flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0; +} +#endif diff --git a/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl b/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl new file mode 100644 index 000000000..1ae709e24 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl @@ -0,0 +1,22 @@ +#use "flywheel:api/vertex.glsl" +#define FLW_INSTANCE_STRUCT Instance + +struct Instance { + mat4 pose; + mat3 normal; + uint color; + uint light; +}; + +void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) { + center = (i.pose * vec4(center, 1.0)).xyz; +} + +#ifdef VERTEX_SHADER +void flw_instanceVertex(Instance i) { + flw_vertexPos = i.pose * flw_vertexPos; + flw_vertexNormal = i.normal * flw_vertexNormal; + flw_vertexColor = unpackUnorm4x8(i.color); + flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0; +} +#endif diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl new file mode 100644 index 000000000..39866a922 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl @@ -0,0 +1,14 @@ +struct FLWPackedPlanes { + vec4 xyX; // + vec4 xyY; // + vec4 xyZ; // + vec4 xyW; // + vec2 zX; // + vec2 zY; // + vec2 zZ; // + vec2 zW; // +}; + +layout(std140, binding = 2) uniform FLWFrustum { + FLWPackedPlanes flw_planes; +};