diff --git a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java index 1dcbe934..db6dd19f 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -5,6 +5,7 @@ import me.cortex.voxy.client.Voxy; import me.cortex.voxy.client.config.VoxyConfig; import me.cortex.voxy.client.core.rendering.*; import me.cortex.voxy.client.core.rendering.building.RenderGenerationService; +import me.cortex.voxy.client.core.rendering.Test; import me.cortex.voxy.client.core.rendering.post.PostProcessing; import me.cortex.voxy.client.core.util.IrisUtil; import me.cortex.voxy.client.saver.ContextSelectionSystem; @@ -56,6 +57,7 @@ public class VoxelCore { //private final Thread shutdownThread = new Thread(this::shutdown); private WorldImporter importer; + private Test test; public VoxelCore(ContextSelectionSystem.Selection worldSelection) { this.world = worldSelection.createEngine(); var cfg = worldSelection.getConfig(); @@ -113,10 +115,11 @@ public class VoxelCore { //this.renderer.getModelManager().updateEntry(0, Blocks.GRASS_BLOCK.getDefaultState()); System.out.println("Voxy core initialized"); + this.test = new Test(); } private AbstractFarWorldRenderer createRenderBackend() { - if (true) { + if (false) { System.out.println("Using Gl46MeshletFarWorldRendering"); return new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); } else { @@ -196,6 +199,8 @@ public class VoxelCore { this.renderer.renderFarAwayOpaque(viewport); + this.test.doIt(viewport); + //Compute the SSAO of the rendered terrain this.postProcessing.computeSSAO(projection, matrices); diff --git a/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java b/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java index a6d9ec30..8217841b 100644 --- a/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java +++ b/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java @@ -17,7 +17,7 @@ import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER; import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER; import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData; -public class PrintfInjector { +public class PrintfInjector implements IShaderProcessor { private final GlBuffer textBuffer; private final HashMap printfStringMap = new HashMap<>(); private final HashMap idToPrintfStringMap = new HashMap<>(); @@ -149,19 +149,20 @@ public class PrintfInjector { //Inject the printf code StringBuilder subCode = new StringBuilder(); subCode.append(String.format("{" + - "uint printfWriteIndex = atomicAdd(printfOutputStruct.index,%s);" + - "printfOutputStruct.stream[printfWriteIndex]=%s;", types.size()+1, + "uint printfWriteIndex = atomicAdd(printfOutputStruct.index,%s);" + + "printfOutputStruct.stream[printfWriteIndex]=%s;", types.size()+1, this.printfStringMap.computeIfAbsent(fmtStr, a->{int id = this.printfStringMap.size(); this.idToPrintfStringMap.put(id, a); return id;}))); for (int i = 0; i < types.size(); i++) { subCode.append("printfOutputStruct.stream[printfWriteIndex+").append(i+1).append("]="); - if (types.get(i) == 'd' || types.get(i) == 'i' || types.get(i) == 'u') { + if (types.get(i) == 'd' || types.get(i) == 'i') { subCode.append("uint(").append(argVals.get(i)).append(")"); - } - if (types.get(i) == 'f') { + } else if (types.get(i) == 'f') { subCode.append("floatBitsToUint(").append(argVals.get(i)).append(")"); + } else { + throw new IllegalStateException("Unknown type " + types.get(i)); } subCode.append(";"); } @@ -193,7 +194,7 @@ public class PrintfInjector { parsePrintfTypes(fmt, types); Object[] args = new Object[types.size()]; for (int i = 0; i < types.size(); i++) { - if (types.get(i) == 'd' || types.get(i) == 'i' || types.get(i) == 'u') { + if (types.get(i) == 'd' || types.get(i) == 'i') { args[i] = MemoryUtil.memGetInt(ptr); ptr += 4; cnt++; @@ -209,7 +210,7 @@ public class PrintfInjector { } public void download() { - DownloadStream.INSTANCE.download(this.textBuffer, 0, this.textBuffer.size(), this::processResult); + DownloadStream.INSTANCE.download(this.textBuffer, this::processResult); DownloadStream.INSTANCE.commit(); nglClearNamedBufferSubData(this.textBuffer.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0); } @@ -217,4 +218,9 @@ public class PrintfInjector { public void free() { this.textBuffer.free(); } + + @Override + public String process(ShaderType type, String source) { + return this.transformInject(source); + } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java index a217894f..fa8161c9 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java @@ -1,20 +1,27 @@ package me.cortex.voxy.client.core.rendering; +import me.cortex.voxy.client.core.gl.shader.PrintfInjector; import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.ShaderType; import me.cortex.voxy.client.core.rendering.hierarchical.NodeManager2; -import me.cortex.voxy.client.core.rendering.hierarchical.NodeManagerOLD; +import static org.lwjgl.opengl.GL30.glBindBufferBase; +import static org.lwjgl.opengl.GL33.glBindSampler; +import static org.lwjgl.opengl.GL33.glGenSamplers; import static org.lwjgl.opengl.GL42C.*; +import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER; import static org.lwjgl.opengl.GL43C.GL_SHADER_STORAGE_BARRIER_BIT; import static org.lwjgl.opengl.GL44.GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT; +import static org.lwjgl.opengl.GL45.glBindTextureUnit; public class HierarchicalOcclusionRenderer { + private PrintfInjector printf = new PrintfInjector(100000, 10, System.out::println); + private final NodeManager2 nodeManager = new NodeManager2(null, null); private final HiZBuffer hiz = new HiZBuffer(); + private final int hizSampler = glGenSamplers(); - - private Shader hiercarchialShader = Shader.make() + private Shader hierarchicalTraversal = Shader.make(this.printf) .add(ShaderType.COMPUTE, "voxy:lod/hierarchical/traversal.comp") .compile(); @@ -27,20 +34,36 @@ public class HierarchicalOcclusionRenderer { } public void render(int depthBuffer, int width, int height) { + this.nodeManager.upload(); + //Make hiz this.hiz.buildMipChain(depthBuffer, width, height); - //Node upload phase - //this.nodeManager.uploadPhase(); - //Node download phase (pulls from previous frame (should maybe result in lower latency)) also clears and resets the queues - //this.nodeManager.downloadPhase(); - //Bind all the resources - this.bind(); - //run hierachial selection shader - this.hiercarchialShader.bind(); - //barrier - glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT|GL_UNIFORM_BARRIER_BIT|GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT|GL_FRAMEBUFFER_BARRIER_BIT); - //Emit enough work to fully populate the gpu - //glDispatchCompute(this.workgroup_dispatch_size_x, 1, 1); - glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT|GL_COMMAND_BARRIER_BIT|GL_UNIFORM_BARRIER_BIT); + glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); + this.hierarchicalTraversal.bind(); + + { + //Bind stuff here + + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeManager.requestQueue.id); + + //Bind the hiz buffer + glBindSampler(0, this.hizSampler); + glBindTextureUnit(0, this.hiz.getHizTextureId()); + } + this.printf.bind(); + { + //Dispatch hierarchies + } + + this.nodeManager.download(); + this.printf.download(); + } + + public void free() { + this.printf.free(); + this.hiz.free(); + this.nodeManager.free(); + glDeleteSamplers(this.hizSampler); } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/Test.java b/src/main/java/me/cortex/voxy/client/core/rendering/Test.java new file mode 100644 index 00000000..715ca798 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/Test.java @@ -0,0 +1,15 @@ +package me.cortex.voxy.client.core.rendering; + + +import static org.lwjgl.opengl.GL30.*; +import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; + +public class Test { + private final HierarchicalOcclusionRenderer hor = new HierarchicalOcclusionRenderer(); + + public void doIt(Viewport viewport) { + var i = new int[1]; + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, i); + this.hor.render(i[0], viewport.width, viewport.height); + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager2.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager2.java index d1dc0b3a..72bf554b 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager2.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager2.java @@ -1,6 +1,8 @@ package me.cortex.voxy.client.core.rendering.hierarchical; +import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; +import me.cortex.voxy.client.core.gl.GlBuffer; import me.cortex.voxy.client.core.rendering.building.BuiltSection; import me.cortex.voxy.client.core.rendering.util.DownloadStream; import me.cortex.voxy.client.core.rendering.util.MarkedObjectList; @@ -10,6 +12,11 @@ import org.lwjgl.system.MemoryUtil; import java.util.Arrays; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; +import static org.lwjgl.opengl.GL30.GL_R32UI; +import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER; +import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData; + //TODO:FIXME: TODO, Must fix/have some filtering for section updates based on time or something // as there can be a cursed situation where an update occures requiring expensive meshing for a section but then in the same @@ -91,6 +98,7 @@ public class NodeManager2 { } } + public static final int REQUEST_QUEUE_SIZE = 1024; public static final int MAX_NODE_COUNT = 1<<22; public static final int NODE_MSK = MAX_NODE_COUNT-1; @@ -104,11 +112,16 @@ public class NodeManager2 { private final INodeInteractor interactor; private final MeshManager meshManager; + public final GlBuffer nodeBuffer; + public final GlBuffer requestQueue; + public NodeManager2(INodeInteractor interactor, MeshManager meshManager) { this.interactor = interactor; this.pos2meshId.defaultReturnValue(NO_NODE); this.interactor.setMeshUpdateCallback(this::meshUpdate); this.meshManager = meshManager; + this.nodeBuffer = new GlBuffer(MAX_NODE_COUNT*16); + this.requestQueue = new GlBuffer(REQUEST_QUEUE_SIZE*4+4); } public void insertTopLevelNode(long position) { @@ -335,24 +348,41 @@ public class NodeManager2 { //The section was empty, so just remove/skip it } } - } + private final IntArrayList nodeUpdates = new IntArrayList(); + //Invalidates the node and tells it to be pushed to the gpu next slot, NOTE: pushing a node, clears any gpu side flags private void pushNode(int node) { - + //TODO: update the local struct with the current frame id to prevent it from being put in the queue multiple times + this.nodeUpdates.add(node); } private void writeNode(long dst, int id) { } - //2 parts upload and download + public void upload() { + for (int i = 0; i < this.nodeUpdates.size(); i++) { + int node = this.nodeUpdates.getInt(i); + //TODO: UPLOAD NODE - private void download() { + } + this.nodeUpdates.clear(); + } + + public void download() { //Download the request queue then clear the counter (first 4 bytes) - //DownloadStream.INSTANCE.download(this.); + DownloadStream.INSTANCE.download(this.requestQueue, this::processRequestQueue); + DownloadStream.INSTANCE.commit(); + nglClearNamedBufferSubData(this.requestQueue.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0); } + + public void free() { + this.requestQueue.free(); + this.nodeBuffer.free(); + } + } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/util/DownloadStream.java b/src/main/java/me/cortex/voxy/client/core/rendering/util/DownloadStream.java index 7611271b..dbdb99b7 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/util/DownloadStream.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/util/DownloadStream.java @@ -43,6 +43,12 @@ public class DownloadStream { private long caddr = -1; private long offset = 0; + + //Pulls the entire buffer from the gpu + public void download(GlBuffer buffer, DownloadResultConsumer resultConsumer) { + this.download(buffer, 0, buffer.size(), resultConsumer); + } + public void download(GlBuffer buffer, long destOffset, long size, DownloadResultConsumer resultConsumer) { if (size > Integer.MAX_VALUE) { throw new IllegalArgumentException(); diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/binding_points.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl similarity index 100% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/binding_points.glsl rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/node.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl similarity index 90% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/node.glsl rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl index f17e2fb1..ba3987e7 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchial/node.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl @@ -86,4 +86,8 @@ uint getTransformIndex(in UnpackedNode node) { void markRequested(inout UnpackedNode node) { node.flags |= 1u; nodes[node.nodeId].z |= 1u<<24; +} + +void debugDumpNode(in UnpackedNode node) { + printf("Node %d, %d@[%d,%d,%d], flags: %d, mesh: %d, ChildPtr: %d", node.nodeId, node.lodLevel, node.pos.x, node.pos.z, node.pos.z, node.flags, node.meshPtr, node.childPtr); } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/screenspace.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl similarity index 100% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/screenspace.glsl rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/selectorOLDDD.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/selectorOLDDD.comp similarity index 100% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/selectorOLDDD.comp rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/selectorOLDDD.comp diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/transform.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/transform.glsl similarity index 100% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/transform.glsl rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/transform.glsl diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchial/traversal.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp similarity index 93% rename from src/main/resources/assets/voxy/shaders/lod/hierarchial/traversal.comp rename to src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp index fb19fd31..2ec5ffc8 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchial/traversal.comp +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp @@ -3,7 +3,7 @@ //TODO: make this better than a single thread layout(local_size_x=1, local_size_y=1) in; -#import +#import #line 7 //The queue contains 3 atomics @@ -44,13 +44,13 @@ layout(binding = 2, std430) restrict buffer QueueData { } queue; */ #line 1 -#import +#import #line 1 -#import +#import #line 1 //Contains all the screenspace computation -#import +#import #line 58 //If a request is successfully added to the RequestQueue, must update NodeData to mark that the node has been put into the request queue @@ -71,6 +71,7 @@ layout(binding = 2, std430) restrict buffer QueueData { void addRequest(inout UnpackedNode node) { + printf("requested"); if (!hasRequested(node)) { //TODO: maybe try using only 1 variable and it being <0 being bad if (requestQueueIndex < requestQueueMaxSize) { @@ -82,10 +83,11 @@ void addRequest(inout UnpackedNode node) { } void enqueueChildren(in UnpackedNode node) { - + printf("children"); } void enqueueSelfForRender(in UnpackedNode node) { + printf("render"); if (renderQueueIndex < renderQueueMaxSize) { renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node); } @@ -103,7 +105,10 @@ void main() { //Compute screenspace setupScreenspace(node); + debugDumpNode(node); + if (isCulledByHiz()) { + printf("HizCulled"); //We are done here, dont do any more, the issue is the shader barriers maybe // its culled, maybe just mark it as culled? } else {