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 620ec94d..656a78fb 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 @@ -49,7 +49,7 @@ public class RenderService, J extends Vi //Max sections: ~500k //Max geometry: 1 gb - this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<20, (1L<<30)-1024); + this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<20, (1L<<32)-1024); //Do something incredibly hacky, we dont need to keep the reference to this around, so just connect and discard var router = new SectionUpdateRouter(); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeCleaner.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeCleaner.java index 8eb49dc2..baf2b012 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeCleaner.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeCleaner.java @@ -3,8 +3,10 @@ package me.cortex.voxy.client.core.rendering.hierachical; import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; import me.cortex.voxy.client.core.gl.GlBuffer; import me.cortex.voxy.client.core.gl.shader.AutoBindingShader; +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.PrintfDebugUtil; import me.cortex.voxy.client.core.rendering.util.DownloadStream; import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.common.world.WorldEngine; @@ -30,10 +32,11 @@ public class NodeCleaner { private static final int BATCH_SET_SIZE = 2048; - private final AutoBindingShader sorter = Shader.makeAuto() + private final AutoBindingShader sorter = Shader.makeAuto(PrintfDebugUtil.PRINTF_processor) .define("OUTPUT_SIZE", OUTPUT_COUNT) .define("VISIBILITY_BUFFER_BINDING", 1) .define("OUTPUT_BUFFER_BINDING", 2) + .define("NODE_DATA_BINDING", 3) .add(ShaderType.COMPUTE, "voxy:lod/hierarchical/cleaner/sort_visibility.comp") .compile(); @@ -75,6 +78,8 @@ public class NodeCleaner { this.sorter .ssbo("VISIBILITY_BUFFER_BINDING", this.visibilityBuffer) .ssbo("OUTPUT_BUFFER_BINDING", this.outputBuffer); + + this.nodeManager.setClearIdCallback(this::clearId); } public void clearId(int id) { @@ -90,6 +95,8 @@ public class NodeCleaner { this.outputBuffer.fill(this.nodeManager.maxNodeCount-2);//TODO: maybe dont set to zero?? this.sorter.bind(); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, nodeDataBuffer.id); + //TODO: choose whether this is in nodeSpace or section/geometryId space //this.nodeManager.getCurrentMaxNodeId() glDispatchCompute((200_000+127)/128, 1, 1); @@ -105,16 +112,12 @@ public class NodeCleaner { glDispatchCompute(1,1,1); DownloadStream.INSTANCE.download(this.outputBuffer, 4*OUTPUT_COUNT, 8*OUTPUT_COUNT, this::onDownload); - - - this.visibilityBuffer.fill(-1); - } } private boolean shouldCleanGeometry() { // if there is less than 200mb of space, clean - return this.nodeManager.getGeometryManager().getRemainingCapacity() < 200_000_000L; + return this.nodeManager.getGeometryManager().getRemainingCapacity() < 500_000_000L; } private void onDownload(long ptr, long size) { @@ -122,6 +125,10 @@ public class NodeCleaner { for (int i = 0; i < 64; i++) { long pos = Integer.toUnsignedLong(MemoryUtil.memGetInt(ptr + 8 * i))<<32; pos |= Integer.toUnsignedLong(MemoryUtil.memGetInt(ptr + 8 * i + 4)); + if (pos == 0) { + //TODO: investigate how or what this happens + continue; + } this.nodeManager.removeNodeGeometry(pos); //b.append(", ").append(WorldEngine.pprintPos(pos));//.append(((int)((pos>>32)&0xFFFFFFFFL)));// } @@ -139,7 +146,8 @@ public class NodeCleaner { MemoryUtil.memPutInt(ptr + cnt * 4, this.idsToClear.dequeueInt()); } UploadStream.INSTANCE.commit(); - glUniform1i(0, cnt); + glUniform1ui(0, cnt); + glUniform1ui(1, this.visibilityId); glDispatchCompute((cnt+127)/128, 1, 1); } } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeManager.java index e3f66fac..0b49be2d 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeManager.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeManager.java @@ -73,6 +73,11 @@ public class NodeManager { private final IntArrayList topLevelNodeIds = new IntArrayList(); private int activeNodeRequestCount; + public interface ClearIdCallback {void clearId(int id);} + private ClearIdCallback clearIdCallback; + public void setClearIdCallback(ClearIdCallback callback) {this.clearIdCallback = callback;} + private void clearId(int id) { if (this.clearIdCallback != null) this.clearIdCallback.clearId(id); } + public NodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionUpdateRouter updateRouter) { if (!MathUtil.isPowerOfTwo(maxNodeCount)) { throw new IllegalArgumentException("Max node count must be a power of 2"); @@ -222,7 +227,6 @@ public class NodeManager { } //================================================================================================================== - //TODO: cleanup this code shitshow and extract common operations to reduce code duplication public void processChildChange(long pos, byte childExistence) { int nodeId = this.activeSectionMap.get(pos); if (nodeId == -1) { @@ -460,13 +464,13 @@ public class NodeManager { Logger.error("UNFINISHED OPERATION TODO: FIXME2"); //Free geometry and related memory for this node - + this.nodeData.free(nodeId); + this.clearId(nodeId); //Unwatch geometry if (!this.updateRouter.unwatch(pos, WorldEngine.UPDATE_FLAGS)) { throw new IllegalStateException("Pos was not being watched"); } - } else { Logger.error("UNFINISHED OPERATION TODO: FIXME3"); @@ -522,6 +526,8 @@ public class NodeManager { this.nodeData.setNodeGeometry(childNodeId, request.getChildMesh(childIdx)); //Mark for update this.invalidateNode(childNodeId); + this.clearId(childNodeId);//Clear the id + //Put in map int pid = this.activeSectionMap.put(childPos, childNodeId|NODE_TYPE_LEAF); if ((pid&NODE_TYPE_MSK) != NODE_TYPE_REQUEST) { @@ -780,6 +786,9 @@ public class NodeManager { return; } + //Reset/clear the id + this.clearId(nodeId); + if (nodeType == NODE_TYPE_LEAF) { //If it is a leaf node, check that the parent has geometry, if it doesnt, request geometry for that parent // if it DOES tho, remove all the children and make the parent a leaf node @@ -791,7 +800,10 @@ public class NodeManager { if (WorldEngine.getLevel(pos) == MAX_LOD_LAYERS-1) { //Cannot remove top level nodes - Logger.info("Tried cleaning top level node " + WorldEngine.pprintPos(pos)); + + //Logger.info("Tried cleaning top level node " + WorldEngine.pprintPos(pos)); + + this.removeGeometryInternal(pos, nodeId); return; } @@ -804,15 +816,19 @@ public class NodeManager { if (this.nodeData.getNodeGeometry(pId) == NULL_GEOMETRY_ID) { //If the parent has null geometry we must first fill it before we can remove it - //Logger.error("TODO: THIS"); + Logger.error("TODO: THIS"); } else { //Else make the parent node a leaf node and remove all the children - //Logger.error("TODO: THIS 2"); + Logger.error("TODO: THIS 2"); } + //this.removeGeometryInternal(pos, nodeId); return; } + this.removeGeometryInternal(pos, nodeId); + } + private void removeGeometryInternal(long pos, int nodeId) { int geometryId = this.nodeData.getNodeGeometry(nodeId); if (geometryId != NULL_GEOMETRY_ID && geometryId != EMPTY_GEOMETRY_ID) { //Unwatch geometry updates @@ -826,7 +842,6 @@ public class NodeManager { //this.cleaner } this.invalidateNode(nodeId); - } //================================================================================================================== diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeStore.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeStore.java index e48492cf..0bf33213 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeStore.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/NodeStore.java @@ -66,7 +66,7 @@ public final class NodeStore { } } - private void free(int nodeId) { + public void free(int nodeId) { this.free(nodeId, 1); } diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/batch_visibility_set.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/batch_visibility_set.comp index c0fb8599..90bc8ae4 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/batch_visibility_set.comp +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/batch_visibility_set.comp @@ -11,11 +11,11 @@ layout(binding = LIST_BUFFER_BINDING, std430) restrict readonly buffer SetListBu }; layout(location=0) uniform uint count; -#define SET_TO uint(-1) +layout(location=1) uniform uint setTo; void main() { uint id = gl_GlobalInvocationID.x; if (count <= id) { return; } - visiblity[ids[id]] = SET_TO; + visiblity[ids[id]] = setTo; } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/sort_visibility.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/sort_visibility.comp index 7980751d..9de4206d 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/sort_visibility.comp +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/cleaner/sort_visibility.comp @@ -7,6 +7,7 @@ layout(local_size_x=128, local_size_y=1) in; //256 workgroup +#import layout(binding = VISIBILITY_BUFFER_BINDING, std430) restrict readonly buffer VisibilityDataBuffer { uint[] visiblity; @@ -54,5 +55,10 @@ void main() { if (visiblity[minVisIds[OUTPUT_SIZE-1]] <= vis) { return; } + UnpackedNode node; + unpackNode(node, gl_GlobalInvocationID.x); + if (isEmptyMesh(node) || !hasMesh(node)) { + return; + } bubbleSort(0, gl_GlobalInvocationID.x, vis); } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal_dev.comp b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal_dev.comp index c8420a74..fc7c8029 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal_dev.comp +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/traversal_dev.comp @@ -61,15 +61,14 @@ void enqueueChildren(in UnpackedNode node) { void enqueueSelfForRender(in UnpackedNode node) { //printf("render %d@[%d,%d,%d]", node.lodLevel, node.pos.x, node.pos.y, node.pos.z); - if ((!isEmptyMesh(node)) && renderQueueIndex < renderQueueMaxSize) { - renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node); - #ifdef IS_DEBUG - debugRenderNodeQueue[atomicAdd(debugRenderNodeQueueIndex, 1)] = node.nodeId; - #endif - - //TODO: decide if it should be this node id, or the mesh id - // for now do node id... think + if (renderQueueIndex < renderQueueMaxSize) { lastRenderFrame[getId(node)] = frameId; + if (!isEmptyMesh(node)) { + renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node); + #ifdef IS_DEBUG + debugRenderNodeQueue[atomicAdd(debugRenderNodeQueueIndex, 1)] = node.nodeId; + #endif + } } }