From 154f016a96be2db0d38dad3d22530a3ceb6f590e Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Fri, 2 Aug 2024 23:38:30 +1000 Subject: [PATCH] More work on setting up render system --- .../me/cortex/voxy/client/core/VoxelCore.java | 8 +- .../client/core/rendering/RenderService.java | 53 +++++++----- .../hierachical2/HierarchicalNodeManager.java | 36 ++++++++ .../HierarchicalOcclusionTraverser.java | 83 +++++++++++++++++++ .../HierarchicalOcclusionRenderer.java | 2 +- .../HierarchicalOcclusionTraverser.java | 25 ------ .../core/rendering/post/PostProcessing.java | 3 + .../core/rendering/section/IUsesMeshlets.java | 5 ++ .../core/rendering/util/DownloadStream.java | 1 + .../core/rendering/{ => util}/HiZBuffer.java | 2 +- 10 files changed, 170 insertions(+), 48 deletions(-) create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalNodeManager.java create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalOcclusionTraverser.java delete mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionTraverser.java create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/section/IUsesMeshlets.java rename src/main/java/me/cortex/voxy/client/core/rendering/{ => util}/HiZBuffer.java (99%) 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 1978a4b4..44b8f960 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -25,7 +25,8 @@ import org.lwjgl.opengl.GL11; import java.io.File; import java.util.*; -import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING; +import static org.lwjgl.opengl.ARBDirectStateAccess.glGetNamedFramebufferAttachmentParameteri; +import static org.lwjgl.opengl.GL30C.*; //Core class that ingests new data from sources and updates the required systems @@ -121,6 +122,11 @@ public class VoxelCore { .setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight); int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING); + if (boundFB == 0) { + throw new IllegalStateException("Cannot use the default framebuffer as cannot source from it"); + } + //TODO: use the raw depth buffer texture instead + //int boundDepthBuffer = glGetNamedFramebufferAttachmentParameteri(boundFB, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB); this.renderer.renderFarAwayOpaque(viewport); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java b/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java index e9d52aa8..affe5f60 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java @@ -4,8 +4,10 @@ import me.cortex.voxy.client.config.VoxyConfig; import me.cortex.voxy.client.core.model.ModelBakerySubsystem; import me.cortex.voxy.client.core.rendering.building.BuiltSection; import me.cortex.voxy.client.core.rendering.building.RenderGenerationService; -import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionTraverser; +import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalNodeManager; +import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser; import me.cortex.voxy.client.core.rendering.section.AbstractSectionRenderer; +import me.cortex.voxy.client.core.rendering.section.IUsesMeshlets; import me.cortex.voxy.client.core.rendering.section.MDICSectionRenderer; import me.cortex.voxy.client.core.rendering.util.DownloadStream; import me.cortex.voxy.client.core.rendering.util.UploadStream; @@ -14,40 +16,47 @@ import net.minecraft.client.render.Camera; import java.util.List; +import static org.lwjgl.opengl.ARBDirectStateAccess.glGetNamedFramebufferAttachmentParameteri; +import static org.lwjgl.opengl.GL42.*; + public class RenderService, J extends Viewport> { + private static AbstractSectionRenderer createSectionRenderer() { + return new MDICSectionRenderer(); + } + private final ViewportSelector viewportSelector; - private final T sectionRenderer; + private final AbstractSectionRenderer sectionRenderer; + + private final HierarchicalNodeManager nodeManager; private final HierarchicalOcclusionTraverser traversal; private final ModelBakerySubsystem modelService; private final RenderGenerationService renderGen; + public RenderService(WorldEngine world) { this.modelService = new ModelBakerySubsystem(world.getMapper()); + this.nodeManager = new HierarchicalNodeManager(1<<21); + this.sectionRenderer = (T) createSectionRenderer(); - this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeBuiltSection, false); - this.traversal = new HierarchicalOcclusionTraverser(this.renderGen, null); + this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport); + this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeBuiltSection, this.sectionRenderer instanceof IUsesMeshlets); + + this.traversal = new HierarchicalOcclusionTraverser(this.nodeManager, 512); world.setDirtyCallback(section -> System.out.println("Section updated!!: " + WorldEngine.pprintPos(section.key))); - this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport); - - - for(int x = -400; x<=400;x++) { - for (int z = -400; z <= 400; z++) { - for (int y = -6; y <= 6; y++) { + /* + for(int x = -200; x<=200;x++) { + for (int z = -200; z <= 200; z++) { + for (int y = -3; y <= 3; y++) { this.renderGen.enqueueTask(0, x, y, z); } } - } + }*/ } - private void consumeBuiltSection(BuiltSection section) { - this.traversal.consumeBuiltSection(section); - } - - private static AbstractSectionRenderer createSectionRenderer() { - return new MDICSectionRenderer(); - } + //Cant do a lambda in the constructor cause "this.nodeManager" could be null??? even tho this does the exact same thing, java is stupid + private void consumeBuiltSection(BuiltSection section) {this.nodeManager.processBuildResult(section);} public void setup(Camera camera) { this.modelService.tick(); @@ -62,12 +71,16 @@ public class RenderService, J extends Viewp // the section renderer is as it might have different backends, but they all accept a buffer containing the section list this.sectionRenderer.renderOpaque(viewport); + //NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable" // sections - UploadStream.INSTANCE.tick(); DownloadStream.INSTANCE.tick(); + UploadStream.INSTANCE.tick(); - this.traversal.doTraversal(viewport); + glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT|GL_PIXEL_BUFFER_BARRIER_BIT); + + int depthBuffer = glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); + this.traversal.doTraversal(viewport, depthBuffer); this.sectionRenderer.buildDrawCallsAndRenderTemporal(viewport, null); } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalNodeManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalNodeManager.java new file mode 100644 index 00000000..c596bf4a --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalNodeManager.java @@ -0,0 +1,36 @@ +package me.cortex.voxy.client.core.rendering.hierachical2; + + +import me.cortex.voxy.client.core.rendering.building.BuiltSection; +import me.jellysquid.mods.sodium.client.util.MathUtil; +import org.lwjgl.system.MemoryUtil; + +//Contains no logic to interface with the gpu, nor does it contain any gpu buffers +public class HierarchicalNodeManager { + public static final int NODE_MSK = ((1<<24)-1); + public final int maxNodeCount; + private final long[] localNodeData; + + public HierarchicalNodeManager(int maxNodeCount) { + if (!MathUtil.isPowerOfTwo(maxNodeCount)) { + throw new IllegalArgumentException("Max node count must be a power of 2"); + } + if (maxNodeCount>(1<<24)) { + throw new IllegalArgumentException("Max node count cannot exceed 2^24"); + } + this.maxNodeCount = maxNodeCount; + this.localNodeData = new long[maxNodeCount*4]; + } + + public void processRequestQueue(int count, long ptr) { + for (int i = 0; i < count; i++) { + int op = MemoryUtil.memGetInt(ptr+(i*4L)); + int node = op&NODE_MSK; + + } + } + + public void processBuildResult(BuiltSection section) { + + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalOcclusionTraverser.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalOcclusionTraverser.java new file mode 100644 index 00000000..1caa6736 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/HierarchicalOcclusionTraverser.java @@ -0,0 +1,83 @@ +package me.cortex.voxy.client.core.rendering.hierachical2; + +import me.cortex.voxy.client.core.gl.GlBuffer; +import me.cortex.voxy.client.core.rendering.util.HiZBuffer; +import me.cortex.voxy.client.core.rendering.Viewport; +import me.cortex.voxy.client.core.rendering.util.DownloadStream; +import me.cortex.voxy.client.core.rendering.util.UploadStream; +import org.lwjgl.system.MemoryUtil; + +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.GL42.glMemoryBarrier; +import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BARRIER_BIT; +import static org.lwjgl.opengl.GL43.glDispatchComputeIndirect; +import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData; + +public class HierarchicalOcclusionTraverser { + private final HierarchicalNodeManager nodeManager; + + private final int maxRequestCount; + private final GlBuffer requestBuffer; + + private final GlBuffer nodeBuffer; + + private final HiZBuffer hiZBuffer = new HiZBuffer(); + + + + public HierarchicalOcclusionTraverser(HierarchicalNodeManager nodeManager, int requestBufferCount) { + this.nodeManager = nodeManager; + this.requestBuffer = new GlBuffer(requestBufferCount*4L+1024).zero();//The 1024 is to assist with race condition issues + this.nodeBuffer = new GlBuffer(nodeManager.maxNodeCount*16L).zero(); + this.maxRequestCount = requestBufferCount; + } + + private void uploadUniform(Viewport viewport) { + + } + + public void doTraversal(Viewport viewport, int depthBuffer) { + //Compute the mip chain + this.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height); + + this.uploadUniform(viewport); + UploadStream.INSTANCE.commit(); + + //Use a chain of glDispatchComputeIndirect (5 times) with alternating read/write buffers + // TODO: swap to persistent gpu thread instead + + + this.downloadResetRequestQueue(); + } + + private void downloadResetRequestQueue() { + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + DownloadStream.INSTANCE.download(this.requestBuffer, this::forwardDownloadResult); + DownloadStream.INSTANCE.commit(); + nglClearNamedBufferSubData(this.requestBuffer.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0); + } + + private void forwardDownloadResult(long ptr, long size) { + int count = MemoryUtil.memGetInt(ptr); + if (count < 0 || count > 50000) { + throw new IllegalStateException("Count unexpected extreme value: " + count); + } + if (count > (this.requestBuffer.size()>>2)-1) { + throw new IllegalStateException("Count over max buffer size, desync expected, aborting"); + } + if (count > this.maxRequestCount) { + System.err.println("Count larger than 'maxRequestCount', overflow captured. Overflowed by " + (count-this.maxRequestCount)); + } + if (count != 0) { + this.nodeManager.processRequestQueue(count, ptr + 4); + } + } + + public void free() { + this.requestBuffer.free(); + this.hiZBuffer.free(); + this.nodeBuffer.free(); + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java index 14b73494..5dcbc9ea 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java @@ -5,7 +5,7 @@ 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.geometry.OLD.Gl46HierarchicalViewport; -import me.cortex.voxy.client.core.rendering.HiZBuffer; +import me.cortex.voxy.client.core.rendering.util.HiZBuffer; import me.cortex.voxy.client.core.rendering.util.UploadStream; import net.minecraft.util.math.MathHelper; import org.joml.Matrix4f; diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionTraverser.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionTraverser.java deleted file mode 100644 index 5924e3e0..00000000 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionTraverser.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.cortex.voxy.client.core.rendering.hierarchical; - -import me.cortex.voxy.client.core.rendering.Viewport; -import me.cortex.voxy.client.core.rendering.building.BuiltSection; -import me.cortex.voxy.client.core.rendering.building.RenderGenerationService; -import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager; - -public class HierarchicalOcclusionTraverser { - public HierarchicalOcclusionTraverser(RenderGenerationService renderGenerationService, AbstractSectionGeometryManager sectionGeometryManager) { - - } - - public void doTraversal(Viewport viewport) { - - } - - public void free() { - - } - - - public void consumeBuiltSection(BuiltSection section) { - section.free(); - } -} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java b/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java index 8aaab9bf..3c777b87 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/post/PostProcessing.java @@ -98,6 +98,9 @@ public class PostProcessing { } public void setup(int width, int height, int sourceFB) { + //TODO: use the raw depth texture instead + //TODO: when blitting, also set the depth value of where the mask is created to 0 (I.E. closest to the camera) + // cause of hiz computing, it makes alot of sections visible this.didSSAO = false; this.glStateCapture.capture(); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/section/IUsesMeshlets.java b/src/main/java/me/cortex/voxy/client/core/rendering/section/IUsesMeshlets.java new file mode 100644 index 00000000..36f42128 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/section/IUsesMeshlets.java @@ -0,0 +1,5 @@ +package me.cortex.voxy.client.core.rendering.section; + +//A dummy empty interface to mark that the class uses meshlets +public interface IUsesMeshlets { +} 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 54e973ab..95378927 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 @@ -133,6 +133,7 @@ public class DownloadStream { //Synchonize force flushes everything public void flushWaitClear() { + glFinish(); this.tick(); var fence = new GlFence(); glFinish(); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/HiZBuffer.java b/src/main/java/me/cortex/voxy/client/core/rendering/util/HiZBuffer.java similarity index 99% rename from src/main/java/me/cortex/voxy/client/core/rendering/HiZBuffer.java rename to src/main/java/me/cortex/voxy/client/core/rendering/util/HiZBuffer.java index 5a24587b..2bb0cb58 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/HiZBuffer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/util/HiZBuffer.java @@ -1,4 +1,4 @@ -package me.cortex.voxy.client.core.rendering; +package me.cortex.voxy.client.core.rendering.util; import me.cortex.voxy.client.core.gl.GlFramebuffer; import me.cortex.voxy.client.core.gl.GlTexture;