From d5045731ad3499243fe9559d57ce31e2a546c8d9 Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:08:48 +1000 Subject: [PATCH] Prepare --- .../client/core/rendering/RenderService.java | 6 +- .../hierachical2/HierarchicalNodeManager.java | 26 +++++--- .../HierarchicalOcclusionTraverser.java | 63 +++++++++++++++++-- .../rendering/hierachical2/NodeStore.java | 2 +- .../section/BasicSectionGeometryManager.java | 2 +- .../cortex/voxy/common/util/MemoryBuffer.java | 4 ++ .../voxy/shaders/lod/hierarchical/node.glsl | 5 +- .../voxy/shaders/lod/hierarchical/queue.glsl | 7 +++ .../shaders/lod/hierarchical/screenspace.glsl | 5 +- .../lod/hierarchical/traversal_dev.comp | 20 +++++- 10 files changed, 117 insertions(+), 23 deletions(-) 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 e2f3e49e..d72d16a3 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 @@ -72,8 +72,7 @@ public class RenderService, J extends Vi Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome); world.getMapper().setBiomeCallback(this.modelService::addBiome); - - /* + final int H_WIDTH = 1; for (int x = -H_WIDTH; x <= H_WIDTH; x++) { for (int y = -1; y <= 0; y++) { @@ -81,8 +80,7 @@ public class RenderService, J extends Vi this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(4, x, y, z)); } } - }*/ - router.watch(WorldEngine.getWorldSectionId(4, 0,0,0), 3); + } } public void setup(Camera camera) { 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 index ce74b078..843afffa 100644 --- 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 @@ -65,9 +65,9 @@ public class HierarchicalNodeManager { private static final int ID_TYPE_MSK = (3<<30); private static final int ID_TYPE_LEAF = (3<<30); - private static final int ID_TYPE_NONE = 0; + private static final int ID_TYPE_INNER = 0; private static final int ID_TYPE_REQUEST = (2<<30); - private static final int ID_TYPE_TOP = (1<<30); + //private static final int ID_TYPE_TOP = (1<<30); public final int maxNodeCount; private final IntOpenHashSet nodeUpdates = new IntOpenHashSet(); @@ -102,7 +102,7 @@ public class HierarchicalNodeManager { int id = this.nodeData.allocate(); this.nodeData.setNodePosition(id, position); - this.activeSectionMap.put(position, id|ID_TYPE_TOP); + this.activeSectionMap.put(position, id|ID_TYPE_LEAF);//ID_TYPE_TOP this.updateRouter.watch(position, WorldEngine.UPDATE_FLAGS); } @@ -123,7 +123,7 @@ public class HierarchicalNodeManager { if (type == ID_TYPE_REQUEST) { //TODO: THIS - } else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP) { + } else if (type == ID_TYPE_INNER) {// || type == ID_TYPE_TOP if (!this.nodeData.nodeExists(node)) { throw new IllegalStateException("Section in active map but not in node data"); } @@ -235,14 +235,24 @@ public class HierarchicalNodeManager { if (type == ID_TYPE_REQUEST) { //Doesnt result in an invalidation as we must wait for geometry to create a child this.requests.get(nodeId).putChildResult(getChildIdx(position), childExistence); - } else if (type == ID_TYPE_LEAF || type == ID_TYPE_NONE || type == ID_TYPE_TOP) { + } else if (type == ID_TYPE_LEAF || type == ID_TYPE_INNER) {// || type == ID_TYPE_TOP + if (this.nodeData.getNodeChildExistence(nodeId) == childExistence) { + //Dont need to update the internal state since it is the same + return; + } + //ALSO: TODO: HERE: if a child is removed, need to remove it and all children accociated //If its an inner node and doesnt have an inflight request, create an empty request, this will get autofilled by the following part - if (type == ID_TYPE_NONE) { + if (type == ID_TYPE_INNER) { } - //If its a top level node, it needs a request? aswell + //If its a top level node, it needs a request? aswell, no no it doesnt :tm: what could do tho, is if it has a request in progress, update it (already handled) + // _or_ if the top level node has a child ptr then also handle it?? + // the issue is that top nodes probably need an extra state like "shouldMakeChildren" or something + // cause if a top level node, that has no children, requests a decent from the gpu + // but there are no children so no decent is made, if a child update is added to that section, + // the update will be ignored since the cpu doesnt know the gpu still wants it //If its a leaf node, its fine, dont need to create a request, only need to update the node msk @@ -336,7 +346,7 @@ public class HierarchicalNodeManager { if (request.isSatisfied()) { this.consumeFinishedNodeChildRequest(nodeId, request); } - } else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP || type == ID_TYPE_LEAF) { + } else if (type == ID_TYPE_INNER || type == ID_TYPE_LEAF) {//type == ID_TYPE_TOP || //Update the node geometry, and enqueue if it changed if (this.updateNodeGeometry(nodeId, section) != 0) {//TODO: might need to mark the node as empty geometry or something this.nodeUpdates.add(nodeId); 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 index c0e7ea8c..27f36162 100644 --- 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 @@ -5,10 +5,14 @@ import me.cortex.voxy.client.core.gl.GlBuffer; 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.PrintfDebugUtil; +import me.cortex.voxy.client.core.rendering.hierarchical.NodeManager; 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 net.minecraft.util.math.MathHelper; +import org.joml.Matrix4f; +import org.joml.Vector3f; import org.lwjgl.system.MemoryUtil; import static me.cortex.voxy.client.core.rendering.PrintfDebugUtil.PRINTF_object; @@ -39,18 +43,31 @@ public class HierarchicalOcclusionTraverser { private static final int LOCAL_WORK_SIZE_BITS = 5; private static final int MAX_ITERATIONS = 5; - private static final int NODE_QUEUE_INDEX_BINDING = 1; - private static final int NODE_QUEUE_META_BINDING = 2; - private static final int NODE_QUEUE_SOURCE_BINDING = 3; - private static final int NODE_QUEUE_SINK_BINDING = 4; + private static int BINDING_COUNTER = 1; + private static final int SCENE_UNIFORM_BINDING = BINDING_COUNTER++; + private static final int REQUEST_QUEUE_BINDING = BINDING_COUNTER++; + private static final int RENDER_QUEUE_BINDING = BINDING_COUNTER++; + private static final int NODE_DATA_BINDING = BINDING_COUNTER++; + private static final int NODE_QUEUE_INDEX_BINDING = BINDING_COUNTER++; + private static final int NODE_QUEUE_META_BINDING = BINDING_COUNTER++; + private static final int NODE_QUEUE_SOURCE_BINDING = BINDING_COUNTER++; + private static final int NODE_QUEUE_SINK_BINDING = BINDING_COUNTER++; private final HiZBuffer hiZBuffer = new HiZBuffer(); + private final int hizSampler = glGenSamplers(); private final Shader traversal = Shader.make(PRINTF_object) .defineIf("DEBUG", Voxy.SHADER_DEBUG) .define("MAX_ITERATIONS", MAX_ITERATIONS) .define("LOCAL_SIZE_BITS", LOCAL_WORK_SIZE_BITS) + .define("HIZ_BINDING", 0) + + .define("SCENE_UNIFORM_BINDING", SCENE_UNIFORM_BINDING) + .define("REQUEST_QUEUE_BINDING", REQUEST_QUEUE_BINDING) + .define("RENDER_QUEUE_BINDING", RENDER_QUEUE_BINDING) + .define("NODE_DATA_BINDING", NODE_DATA_BINDING) + .define("NODE_QUEUE_INDEX_BINDING", NODE_QUEUE_INDEX_BINDING) .define("NODE_QUEUE_META_BINDING", NODE_QUEUE_META_BINDING) .define("NODE_QUEUE_SOURCE_BINDING", NODE_QUEUE_SOURCE_BINDING) @@ -65,15 +82,52 @@ public class HierarchicalOcclusionTraverser { 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; + + + glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glSamplerParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(this.hizSampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(this.hizSampler, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } private void uploadUniform(Viewport viewport) { + long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 1024); + int sx = MathHelper.floor(viewport.cameraX)>>5; + int sy = MathHelper.floor(viewport.cameraY)>>5; + int sz = MathHelper.floor(viewport.cameraZ)>>5; + new Matrix4f(viewport.projection).mul(viewport.modelView).getToAddress(ptr); ptr += 4*4*4; + + MemoryUtil.memPutInt(ptr, sx); ptr += 4; + MemoryUtil.memPutInt(ptr, sy); ptr += 4; + MemoryUtil.memPutInt(ptr, sz); ptr += 4; + MemoryUtil.memPutInt(ptr, viewport.width); ptr += 4; + + var innerTranslation = new Vector3f((float) (viewport.cameraX-(sx<<5)), (float) (viewport.cameraY-(sy<<5)), (float) (viewport.cameraZ-(sz<<5))); + innerTranslation.getToAddress(ptr); ptr += 4*3; + + MemoryUtil.memPutInt(ptr, viewport.height); ptr += 4; + + MemoryUtil.memPutInt(ptr, NodeManager.REQUEST_QUEUE_SIZE); ptr += 4; + MemoryUtil.memPutInt(ptr, 1000000); ptr += 4; + + //Screen space size for descending + MemoryUtil.memPutFloat(ptr, 64*64); ptr += 4; } private void bindings() { + glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_UNIFORM_BINDING, this.uniformBuffer.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, REQUEST_QUEUE_BINDING, this.requestBuffer.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, RENDER_QUEUE_BINDING, this.renderList.id); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, NODE_DATA_BINDING, this.nodeBuffer.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, NODE_QUEUE_META_BINDING, this.queueMetaBuffer.id); glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, this.queueMetaBuffer.id); + + //Bind the hiz buffer + glBindSampler(0, this.hizSampler); + glBindTextureUnit(0, this.hiZBuffer.getHizTextureId()); } public void doTraversal(Viewport viewport, int depthBuffer) { @@ -190,5 +244,6 @@ public class HierarchicalOcclusionTraverser { this.queueMetaBuffer.free(); this.scratchQueueA.free(); this.scratchQueueB.free(); + glDeleteSamplers(this.hizSampler); } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/NodeStore.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/NodeStore.java index 1998d545..4b89e2f2 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/NodeStore.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical2/NodeStore.java @@ -82,7 +82,7 @@ public final class NodeStore { private void clear(int nodeId) { int idx = id2idx(nodeId); this.localNodeData[idx] = -1;//Position - this.localNodeData[idx+1] = 0; + this.localNodeData[idx+1] = GEOMETRY_ID_MSK|(((long)NODE_ID_MSK)<<24); this.localNodeData[idx+2] = 0; this.localNodeData[idx+3] = 0; } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/section/BasicSectionGeometryManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/section/BasicSectionGeometryManager.java index 26b9163d..28ba5903 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/section/BasicSectionGeometryManager.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/section/BasicSectionGeometryManager.java @@ -73,7 +73,7 @@ public class BasicSectionGeometryManager extends AbstractSectionGeometryManager @Override public void removeSection(int id) { if (!this.allocationSet.free(id)) { - throw new IllegalStateException("Id was not already allocated"); + throw new IllegalStateException("Id was not already allocated. id: " + id); } var oldMetadata = this.sectionMetadata.set(id, null); this.geometry.free(oldMetadata.geometryPtr); diff --git a/src/main/java/me/cortex/voxy/common/util/MemoryBuffer.java b/src/main/java/me/cortex/voxy/common/util/MemoryBuffer.java index eb6da7c9..7dc84378 100644 --- a/src/main/java/me/cortex/voxy/common/util/MemoryBuffer.java +++ b/src/main/java/me/cortex/voxy/common/util/MemoryBuffer.java @@ -43,4 +43,8 @@ public class MemoryBuffer extends TrackedObject { return new MemoryBuffer(this.address, size); } + + + //TODO: create like Long(offset) -> value at offset + // methods for get and set, that way can have a single unifed system to ensure memory access bounds } 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 4dac8a4c..5d80c399 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/node.glsl @@ -1,5 +1,5 @@ -layout(binding = NODE_DATA_INDEX, std430) restrict buffer NodeData { +layout(binding = NODE_DATA_BINDING, std430) restrict buffer NodeData { //Needs to be read and writeable for marking data, //(could do an evil violation, make this readonly, then have a writeonly varient, which means that writing might not be visible but will show up by the next frame) //Nodes are 16 bytes big (or 32 cant decide, 16 might _just_ be enough) @@ -84,9 +84,10 @@ uint getChildPtr(in UnpackedNode node) { return node.childPtr; } +/* uint getTransformIndex(in UnpackedNode node) { return (node.flags >> 5)&31u; -} +}*/ //----------------------------------- diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/queue.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/queue.glsl index e7317e08..7711fbb5 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/queue.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/queue.glsl @@ -48,3 +48,10 @@ void pushNode(uint nodeId) { #endif nodeQueueSink[nodePushIndex++] = nodeId; } + + + +#define SIMPLE_QUEUE(name, binding) layout(binding = binding, std430) restrict buffer name##Struct { \ + uint name##Index; \ + uint[] name; \ +}; \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl b/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl index 1277a1ab..50c0a3f9 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl @@ -12,7 +12,7 @@ // substantually for performance (for both persistent threads and incremental) -layout(binding = HIZ_BINDING_INDEX) uniform sampler2DShadow hizDepthSampler; +layout(binding = HIZ_BINDING) uniform sampler2DShadow hizDepthSampler; //TODO: maybe do spher bounds aswell? cause they have different accuracies but are both over estimates (liberals (non conservative xD)) // so can do && @@ -27,9 +27,10 @@ vec2 size; void setupScreenspace(in UnpackedNode node) { //TODO: Need to do aabb size for the nodes, it must be an overesimate of all the children - Transform transform = transforms[getTransformIndex(node)]; /* + Transform transform = transforms[getTransformIndex(node)]; + vec3 point = VP*(((transform.transform*vec4((node.pos< +#import +#import + +SIMPLE_QUEUE(requestQueue, REQUEST_QUEUE_BINDING); +SIMPLE_QUEUE(renderQueue, RENDER_QUEUE_BINDING); + +/* +layout(binding = REQUEST_QUEUE_INDEX, std430) restrict buffer RequestQueue { + uint requestQueueIndex; + uint[] requestQueue; +}; + +layout(binding = RENDER_QUEUE_INDEX, std430) restrict buffer RenderQueue { + uint renderQueueIndex; + uint[] renderQueue; +};*/ + void main() { uint node = getCurrentNode(); - if (node != SENTINAL_OUT_OF_BOUNDS && queueIdx != 4) { + if (node != SENTINAL_OUT_OF_BOUNDS) { printf("GID:%d, NODE %d, %d, AA, %d, %d, %d, %d", gl_GlobalInvocationID.x, node, queueIdx, nodeQueueMetadata[queueIdx].x, nodeQueueMetadata[queueIdx].y, nodeQueueMetadata[queueIdx].z, nodeQueueMetadata[queueIdx].w); pushNodesInit(1); pushNode(node);