From 3cec8b281caa791913b833fb6300d7bbe683035c Mon Sep 17 00:00:00 2001 From: mcrcortex <{ID}+{username}@users.noreply.github.com> Date: Sat, 13 Jul 2024 10:47:11 +1000 Subject: [PATCH] Restructure A --- .../me/cortex/voxy/client/core/VoxelCore.java | 25 ++-- .../cortex/voxy/client/core/gl/GlBuffer.java | 9 +- .../rendering/AbstractFarWorldRenderer.java | 21 +--- .../core/rendering/Gl46FarWorldRenderer.java | 5 +- .../rendering/Gl46HierarchicalRenderer.java | 83 +++++++++++++ .../rendering/Gl46HierarchicalViewport.java | 12 ++ .../core/rendering/Gl46MeshletViewport.java | 4 +- .../Gl46MeshletsFarWorldRenderer.java | 13 +- .../client/core/rendering/Gl46Viewport.java | 4 +- .../HierarchicalOcclusionRenderer.java | 69 ----------- .../core/rendering/IRenderInterface.java | 32 +++++ .../rendering/NvMeshFarWorldRenderer.java | 5 +- .../client/core/rendering/NvMeshViewport.java | 4 +- .../voxy/client/core/rendering/Test.java | 15 --- .../voxy/client/core/rendering/Viewport.java | 5 +- .../HierarchicalOcclusionRenderer.java | 117 ++++++++++++++++++ .../rendering/hierarchical/MeshManager.java | 4 + .../{NodeManager2.java => NodeManager.java} | 93 ++++++++++++-- .../lod/hierarchical/binding_points.glsl | 7 +- .../voxy/shaders/lod/hierarchical/node.glsl | 13 +- .../shaders/lod/hierarchical/traversal.comp | 16 ++- 21 files changed, 394 insertions(+), 162 deletions(-) create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/Gl46HierarchicalRenderer.java create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/Gl46HierarchicalViewport.java delete mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/IRenderInterface.java delete mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/Test.java create mode 100644 src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java rename src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/{NodeManager2.java => NodeManager.java} (82%) 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 db6dd19f..28d4827e 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -3,9 +3,9 @@ package me.cortex.voxy.client.core; import com.mojang.blaze3d.systems.RenderSystem; import me.cortex.voxy.client.Voxy; import me.cortex.voxy.client.config.VoxyConfig; +import me.cortex.voxy.client.core.model.ModelManager; 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; @@ -46,18 +46,19 @@ import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING; //Ingest -> world engine -> raw render data -> render data public class VoxelCore { private final WorldEngine world; - private final DistanceTracker distanceTracker; private final RenderGenerationService renderGen; + private final ModelManager modelManager; + + private final DistanceTracker distanceTracker; private final RenderTracker renderTracker; - private final AbstractFarWorldRenderer renderer; + private final IRenderInterface renderer; private final ViewportSelector viewportSelector; private final PostProcessing postProcessing; //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(); @@ -66,12 +67,13 @@ public class VoxelCore { //Trigger the shared index buffer loading SharedIndexBuffer.INSTANCE.id(); Capabilities.init();//Ensure clinit is called + this.modelManager = new ModelManager(16); this.renderer = this.createRenderBackend(); this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport); System.out.println("Renderer initialized"); - this.renderTracker = new RenderTracker(this.world, this.renderer); - this.renderGen = new RenderGenerationService(this.world, this.renderer.getModelManager(), VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult, this.renderer.usesMeshlets()); + this.renderTracker = new RenderTracker(this.world, (AbstractFarWorldRenderer) this.renderer); + this.renderGen = new RenderGenerationService(this.world, this.modelManager, VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult, this.renderer.generateMeshlets()); this.world.setDirtyCallback(this.renderTracker::sectionUpdated); this.renderTracker.setRenderGen(this.renderGen); System.out.println("Render tracker and generator initialized"); @@ -115,20 +117,19 @@ 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 (false) { System.out.println("Using Gl46MeshletFarWorldRendering"); - return new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + return new Gl46MeshletsFarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); } else { if (VoxyConfig.CONFIG.useMeshShaders()) { System.out.println("Using NvMeshFarWorldRenderer"); - return new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + return new NvMeshFarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); } else { System.out.println("Using Gl46FarWorldRenderer"); - return new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + return new Gl46FarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); } } } @@ -199,8 +200,6 @@ public class VoxelCore { this.renderer.renderFarAwayOpaque(viewport); - this.test.doIt(viewport); - //Compute the SSAO of the rendered terrain this.postProcessing.computeSSAO(projection, matrices); @@ -246,7 +245,7 @@ public class VoxelCore { System.out.println("Render gen shut down"); try {this.world.shutdown();} catch (Exception e) {System.err.println(e);} System.out.println("World engine shut down"); - try {this.renderer.shutdown(); this.viewportSelector.free();} catch (Exception e) {System.err.println(e);} + try {this.renderer.shutdown(); this.viewportSelector.free(); this.modelManager.free();} catch (Exception e) {System.err.println(e);} System.out.println("Renderer shut down"); if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}} System.out.println("Voxel core shut down"); diff --git a/src/main/java/me/cortex/voxy/client/core/gl/GlBuffer.java b/src/main/java/me/cortex/voxy/client/core/gl/GlBuffer.java index 482405ac..ce422d12 100644 --- a/src/main/java/me/cortex/voxy/client/core/gl/GlBuffer.java +++ b/src/main/java/me/cortex/voxy/client/core/gl/GlBuffer.java @@ -2,10 +2,10 @@ package me.cortex.voxy.client.core.gl; import me.cortex.voxy.common.util.TrackedObject; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; import static org.lwjgl.opengl.GL15.glDeleteBuffers; import static org.lwjgl.opengl.GL44C.glBufferStorage; -import static org.lwjgl.opengl.GL45C.glCreateBuffers; -import static org.lwjgl.opengl.GL45C.glNamedBufferStorage; +import static org.lwjgl.opengl.GL45C.*; public class GlBuffer extends TrackedObject { public final int id; @@ -30,4 +30,9 @@ public class GlBuffer extends TrackedObject { public long size() { return this.size; } + + public GlBuffer zero() { + nglClearNamedBufferData(this.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0); + return this; + } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java index 44d327c4..fb2fed06 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java @@ -35,7 +35,7 @@ import static org.lwjgl.opengl.GL30.*; //Todo: tinker with having the compute shader where each thread is a position to render? maybe idk -public abstract class AbstractFarWorldRenderer { +public abstract class AbstractFarWorldRenderer implements IRenderInterface { public static final int STATIC_VAO = glGenVertexArrays(); protected final GlBuffer uniformBuffer; @@ -52,18 +52,18 @@ public abstract class AbstractFarWorldRenderer viewports = new ArrayList<>(); + //private final List viewports = new ArrayList<>(); protected IntArrayList updatedSectionIds; private final ConcurrentLinkedDeque blockStateUpdates = new ConcurrentLinkedDeque<>(); private final ConcurrentLinkedDeque biomeUpdates = new ConcurrentLinkedDeque<>(); - public AbstractFarWorldRenderer(J geometry) { + public AbstractFarWorldRenderer(ModelManager models, J geometry) { this.maxSections = geometry.getMaxSections(); this.uniformBuffer = new GlBuffer(1024); this.lightDataBuffer = new GlBuffer(256*4);//256 of uint this.geometry = geometry; - this.models = new ModelManager(16); + this.models = models; } public void setupRender(Frustum frustum, Camera camera) { @@ -148,29 +148,20 @@ public abstract class AbstractFarWorldRenderer { + public Gl46HierarchicalViewport(Gl46HierarchicalRenderer renderer) { + } + + protected void delete0() { + + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletViewport.java b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletViewport.java index 6ff23f0f..8429566a 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletViewport.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletViewport.java @@ -10,9 +10,7 @@ import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData; public class Gl46MeshletViewport extends Viewport { GlBuffer visibilityBuffer; public Gl46MeshletViewport(Gl46MeshletsFarWorldRenderer renderer) { - super(renderer); - this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L); - nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0); + this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero(); } protected void delete0() { diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletsFarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletsFarWorldRenderer.java index a1b76ca0..790316dd 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletsFarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/Gl46MeshletsFarWorldRenderer.java @@ -4,6 +4,7 @@ import me.cortex.voxy.client.core.gl.GlBuffer; 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.model.ModelManager; import me.cortex.voxy.client.core.rendering.building.RenderDataFactory; import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection; @@ -73,10 +74,10 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer { GlBuffer visibilityBuffer; public Gl46Viewport(Gl46FarWorldRenderer renderer) { - super(renderer); - this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L); - nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0); + this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero(); } protected void delete0() { 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 deleted file mode 100644 index fa8161c9..00000000 --- a/src/main/java/me/cortex/voxy/client/core/rendering/HierarchicalOcclusionRenderer.java +++ /dev/null @@ -1,69 +0,0 @@ -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 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 hierarchicalTraversal = Shader.make(this.printf) - .add(ShaderType.COMPUTE, "voxy:lod/hierarchical/traversal.comp") - .compile(); - - public HierarchicalOcclusionRenderer() { - - } - - private void bind() { - - } - - public void render(int depthBuffer, int width, int height) { - this.nodeManager.upload(); - - //Make hiz - this.hiz.buildMipChain(depthBuffer, width, height); - 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/IRenderInterface.java b/src/main/java/me/cortex/voxy/client/core/rendering/IRenderInterface.java new file mode 100644 index 00000000..d2972b6f --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/IRenderInterface.java @@ -0,0 +1,32 @@ +package me.cortex.voxy.client.core.rendering; + + +import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionRenderer; +import me.cortex.voxy.common.world.other.Mapper; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.Frustum; + +import java.util.List; + +import static org.lwjgl.opengl.GL30.*; + +public interface IRenderInterface { + + T createViewport(); + + void setupRender(Frustum frustum, Camera camera); + + void renderFarAwayOpaque(T viewport); + + void renderFarAwayTranslucent(T viewport); + + void addDebugData(List debug); + + void shutdown(); + + void addBlockState(Mapper.StateEntry stateEntry); + + void addBiome(Mapper.BiomeEntry biomeEntry); + + boolean generateMeshlets(); +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/NvMeshFarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/NvMeshFarWorldRenderer.java index 08dc482d..ee38f7b6 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/NvMeshFarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/NvMeshFarWorldRenderer.java @@ -2,6 +2,7 @@ package me.cortex.voxy.client.core.rendering; import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.ShaderType; +import me.cortex.voxy.client.core.model.ModelManager; import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection; import net.minecraft.client.render.Camera; @@ -52,8 +53,8 @@ public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer { GlBuffer visibilityBuffer; public NvMeshViewport(NvMeshFarWorldRenderer renderer) { - super(renderer); - this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L); - glClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]); + this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero(); } protected void delete0() { 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 deleted file mode 100644 index 715ca798..00000000 --- a/src/main/java/me/cortex/voxy/client/core/rendering/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -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/Viewport.java b/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java index 4371a5dd..c68b562e 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/Viewport.java @@ -3,7 +3,6 @@ package me.cortex.voxy.client.core.rendering; import org.joml.Matrix4f; public abstract class Viewport > { - private final AbstractFarWorldRenderer renderer; int width; int height; int frameId; @@ -13,13 +12,11 @@ public abstract class Viewport > { double cameraY; double cameraZ; - protected Viewport(AbstractFarWorldRenderer renderer) { - this.renderer = renderer; + protected Viewport() { } public final void delete() { this.delete0(); - this.renderer.removeViewport((A) this); } protected abstract void delete0(); 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 new file mode 100644 index 00000000..88d2d746 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/HierarchicalOcclusionRenderer.java @@ -0,0 +1,117 @@ +package me.cortex.voxy.client.core.rendering.hierarchical; + +import me.cortex.voxy.client.core.gl.GlBuffer; +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.HiZBuffer; +import me.cortex.voxy.client.core.rendering.building.BuiltSection; +import me.cortex.voxy.client.core.rendering.hierarchical.INodeInteractor; +import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager; +import me.cortex.voxy.client.core.rendering.hierarchical.NodeManager; +import me.cortex.voxy.client.core.rendering.util.UploadStream; + +import java.util.function.Consumer; + +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.GL43.glDispatchCompute; +import static org.lwjgl.opengl.GL45.glBindTextureUnit; + +public class HierarchicalOcclusionRenderer { + private PrintfInjector printf = new PrintfInjector(100000, 10, System.out::println); + + private final MeshManager meshManager = new MeshManager(); + private final NodeManager nodeManager = new NodeManager(new INodeInteractor() { + @Override + public void watchUpdates(long pos) { + + } + + @Override + public void unwatchUpdates(long pos) { + + } + + @Override + public void requestMesh(long pos) { + + } + + @Override + public void setMeshUpdateCallback(Consumer mesh) { + + } + }, this.meshManager); + + private final HiZBuffer hiz = new HiZBuffer(); + + private final int hizSampler = glGenSamplers(); + + private final Shader hierarchicalTraversal = Shader.make(this.printf) + .add(ShaderType.COMPUTE, "voxy:lod/hierarchical/traversal.comp") + .compile(); + + private final GlBuffer nodeQueue; + private final GlBuffer renderQueue; + private final GlBuffer uniformBuffer; + + public HierarchicalOcclusionRenderer() { + this.nodeQueue = new GlBuffer(1000000*4+4).zero(); + this.renderQueue = new GlBuffer(1000000*4+4).zero(); + this.uniformBuffer = new GlBuffer(1024).zero(); + } + + private void uploadUniform() { + long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 1024); + + } + + private void doHierarchicalTraversal(int depthBuffer, int width, int height) { + this.uploadUniform(); + this.nodeManager.upload(); + //Make hiz + this.hiz.buildMipChain(depthBuffer, width, height); + glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); + this.hierarchicalTraversal.bind(); + + { + glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueue.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.nodeManager.requestQueue.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.renderQueue.id); + + //Bind the hiz buffer + glBindSampler(0, this.hizSampler); + glBindTextureUnit(0, this.hiz.getHizTextureId()); + } + this.printf.bind(); + { + //Dispatch hierarchies + glDispatchCompute(1,1,1); + } + + this.nodeManager.download(); + } + + public void render(int depthBuffer, int width, int height) { + this.doHierarchicalTraversal(depthBuffer, width, height); + + + this.printf.download(); + } + + public void free() { + this.nodeQueue.free(); + this.renderQueue.free(); + this.printf.free(); + this.hiz.free(); + this.nodeManager.free(); + this.meshManager.free(); + glDeleteSamplers(this.hizSampler); + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/MeshManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/MeshManager.java index 9348fc01..71ed7897 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/MeshManager.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/MeshManager.java @@ -30,4 +30,8 @@ public class MeshManager { public void removeMesh(int mesh) { } + + public void free() { + + } } 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/NodeManager.java similarity index 82% rename from src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager2.java rename to src/main/java/me/cortex/voxy/client/core/rendering/hierarchical/NodeManager.java index 72bf554b..94cff137 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/NodeManager.java @@ -6,6 +6,7 @@ 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; +import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.common.util.HierarchicalBitSet; import me.cortex.voxy.common.world.WorldEngine; import org.lwjgl.system.MemoryUtil; @@ -25,7 +26,7 @@ import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData; //TODO: Make it an sparse voxel octree, that is if all of the children bar 1 are empty/air, remove the self node and replace it with the non empty child -public class NodeManager2 { +public class NodeManager { //A request for making a new child nodes private static final class LeafRequest { //LoD position identifier @@ -98,9 +99,12 @@ 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; + public static final int MAX_MESH_ID = 1<<24; + + public static final int REQUEST_QUEUE_SIZE = 1024; + public static final int MESH_MSK = MAX_MESH_ID-1; + public static final int NODE_MSK = (1<<24)-1;//NOTE!! IS DIFFERENT FROM MAX_NODE_COUNT as the MAX_NODE_COUNT is for the buffers, the ACTUAL MAX is NODE_MSK+1 //Local data layout // first long is position (todo! might not be needed) @@ -115,13 +119,20 @@ public class NodeManager2 { public final GlBuffer nodeBuffer; public final GlBuffer requestQueue; - public NodeManager2(INodeInteractor interactor, MeshManager meshManager) { + public NodeManager(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); + Arrays.fill(this.localNodeData, 0); + + + this.setNodePosition(0, WorldEngine.getWorldSectionId(0, 0,5,0)); + this.setChildPtr(0, NODE_MSK, 0); + this.setMeshId(0, MESH_MSK); + this.pushNode(0); } public void insertTopLevelNode(long position) { @@ -137,21 +148,63 @@ public class NodeManager2 { //Returns the mesh offset/id for the given node or -1 if it doesnt exist private int getNodeMesh(int node) { - return -1; + return (int) (this.localNodeData[node*3+1]&((1<<24)-1)); + } + + private int getNodeChildPtr(int node) { + return (int) ((this.localNodeData[node*3+1]>>>32)&NODE_MSK); + } + + private int getNodeChildCnt(int node) { + return (int) ((this.localNodeData[node*3+1]>>>61)&7)+1; } private long getNodePos(int node) { - return -1; + return this.localNodeData[node*3]; } private boolean isLeafNode(int node) { - return true; + //TODO: maybe make this flag based instead of checking the child ptr? + return this.getNodeChildPtr(node) != NODE_MSK; + } + + //Its ment to return if the node is just an empty mesh or if all the children are also empty + private boolean isEmptyNode(int node) { + return this.getNodeMesh(node)==(MESH_MSK-1);//Special case/reserved + } + + private void setNodePosition(int node, long position) { + this.localNodeData[node*3] = position; } private void setMeshId(int node, int mesh) { - + if (mesh > MESH_MSK) { + throw new IllegalArgumentException(); + } + long val = this.localNodeData[node*3+1]; + val &= ~MESH_MSK; + val |= mesh; + this.localNodeData[node*3+1] = val; } + private void setChildPtr(int node, int childPtr, int count) { + if (childPtr > NODE_MSK || (childPtr!=NODE_MSK&&count < 1)) { + throw new IllegalArgumentException(); + } + long val = this.localNodeData[node*3+1]; + //Put the count + val &= ~(0x7L<<61); + val |= Integer.toUnsignedLong(Math.max(count-1,0))<<61; + //Put the child ptr + val &= ~(Integer.toUnsignedLong(NODE_MSK)<<32); + val |= Integer.toUnsignedLong(childPtr) << 32; + this.localNodeData[node*3+1] = val; + } + + + + + private static long makeChildPos(long basePos, int addin) { int lvl = WorldEngine.getLevel(basePos); if (lvl == 0) { @@ -256,6 +309,9 @@ public class NodeManager2 { // that is, there is a request that is satisfied bar 1 section, that section is supplied as non emptpty but then becomes empty in the same tick private void meshUpdate(BuiltSection mesh) { int id = this.pos2meshId.get(mesh.position); + //TODO: FIXME!! if we get a node that has an update and is watched but no id for it, it could be an update state from + // an empty node to non empty node, this means we need to invalidate all the childrens positions and move them! + // then also update the parent pointer if (id == NO_NODE) { //The built mesh section is no longer needed, discard it // TODO: could probably?? cache the mesh in ram that way if its requested? it can be immediatly fetched while a newer mesh is built?? @@ -359,16 +415,31 @@ public class NodeManager2 { } private void writeNode(long dst, int id) { + long pos = this.localNodeData[id*3]; + MemoryUtil.memPutInt(dst, (int) (pos>>32)); dst += 4; + MemoryUtil.memPutInt(dst, (int) pos); dst += 4; + int flags = 0; + flags |= this.isEmptyNode(id)?2:0; + flags |= Math.max(0, this.getNodeChildCnt(id)-1)<<2; + + int a = this.getNodeMesh(id)|(flags&0xFF); + int b = this.getNodeChildPtr(id)|((flags>>8)&0xFF); + + MemoryUtil.memPutInt(dst, a); dst += 4; + MemoryUtil.memPutInt(dst, b); dst += 4; } public void upload() { for (int i = 0; i < this.nodeUpdates.size(); i++) { int node = this.nodeUpdates.getInt(i); - //TODO: UPLOAD NODE - + long ptr = UploadStream.INSTANCE.upload(this.nodeBuffer, node*16L, 16); + this.writeNode(ptr, node); + } + if (!this.nodeUpdates.isEmpty()) { + UploadStream.INSTANCE.commit();//Cause we actually uploaded something (do it after cause it allows batch comitting thing) + this.nodeUpdates.clear(); } - this.nodeUpdates.clear(); } public void download() { diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl index 49006100..390ebac7 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/binding_points.glsl @@ -1,8 +1,9 @@ #define SCENE_UNIFORM_INDEX 0 #define NODE_DATA_INDEX 1 -#define REQUEST_QUEUE_INDEX 2 -#define RENDER_QUEUE_INDEX 3 -#define TRANSFORM_ARRAY_INDEX 4 +#define NODE_QUEUE_INDEX 2 +#define REQUEST_QUEUE_INDEX 3 +#define RENDER_QUEUE_INDEX 4 +#define TRANSFORM_ARRAY_INDEX 5 //Samplers #define HIZ_BINDING_INDEX 0 diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl index ba3987e7..54c408cf 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl @@ -25,12 +25,12 @@ struct UnpackedNode { uint childPtr; }; -#define NULL_NODE ((1<<25)-1) +#define NULL_NODE ((1<<24)-1) #define NULL_MESH ((1<<24)-1) -void unpackNode(inout UnpackedNode node, uint nodeId) { - node.nodeId = nodeId; +void unpackNode(out UnpackedNode node, uint nodeId) { uvec4 compactedNode = nodes[nodeId]; + node.nodeId = nodeId; node.lodLevel = compactedNode.x >> 28; { @@ -40,13 +40,12 @@ void unpackNode(inout UnpackedNode node, uint nodeId) { z |= int(compactedNode.y>>28); z <<= 8; z >>= 8; - node.pos = ivec3(x, y, z); } node.meshPtr = compactedNode.z&0xFFFFFFu; - node.childPtr = compactedNode.w&0x1FFFFFFu; - node.flags = (compactedNode.z>>24) | ((compactedNode.w>>23)<<8); + node.childPtr = compactedNode.w&0xFFFFFFu; + node.flags = ((compactedNode.z>>24)&0xFFu) | (((compactedNode.w>>24)&0xFFu)<<8); } bool hasMesh(in UnpackedNode node) { @@ -89,5 +88,5 @@ void markRequested(inout UnpackedNode node) { } 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); + printf("Node %d, %d@[%d,%d,%d], flags: %d, mesh: %d, ChildPtr: %d", node.nodeId, node.lodLevel, node.pos.x, node.pos.y, 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/hierarchical/traversal.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp index 2ec5ffc8..0984eb3e 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal.comp @@ -25,6 +25,11 @@ layout(binding = SCENE_UNIFORM_INDEX, std140) uniform SceneUniform { uint renderQueueMaxSize; }; +layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue { + uint nodeQueueSize; + uint[] nodeQueue; +}; + layout(binding = REQUEST_QUEUE_INDEX, std430) restrict buffer RequestQueue { uint requestQueueIndex; uint[] requestQueue; @@ -35,6 +40,7 @@ layout(binding = RENDER_QUEUE_INDEX, std430) restrict buffer RenderQueue { uint[] renderQueue; }; + /* layout(binding = 2, std430) restrict buffer QueueData { uint tail; @@ -83,11 +89,11 @@ void addRequest(inout UnpackedNode node) { } void enqueueChildren(in UnpackedNode node) { - printf("children"); + //printf("children"); } void enqueueSelfForRender(in UnpackedNode node) { - printf("render"); + //printf("render"); if (renderQueueIndex < renderQueueMaxSize) { renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node); } @@ -98,17 +104,17 @@ void main() { UnpackedNode node; //Setup/unpack the node - unpackNode(node, gl_GlobalInvocationID.x); + unpackNode(node, nodeQueue[gl_GlobalInvocationID.x]); //TODO: check the node is OK first??? maybe? //Compute screenspace setupScreenspace(node); - debugDumpNode(node); + //debugDumpNode(node); if (isCulledByHiz()) { - printf("HizCulled"); + //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 {