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 9f8cbaf8..4cb42876 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 @@ -75,7 +75,9 @@ public class RenderService, J extends Vi Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome); world.getMapper().setBiomeCallback(this.modelService::addBiome); - + //this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(0, 0,0,0)); + this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(4, 0,0,0)); + /* final int H_WIDTH = 1; for (int x = -H_WIDTH; x <= H_WIDTH; x++) { for (int y = -1; y <= 0; y++) { @@ -83,7 +85,7 @@ public class RenderService, J extends Vi this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(4, x, y, z)); } } - } + }*/ } public void setup(Camera camera) { @@ -117,6 +119,9 @@ public class RenderService, J extends Vi this.sectionUpdateQueue.consume(); this.geometryUpdateQueue.consume(); + if (this.nodeManager.writeChanges(this.traversal.getNodeBuffer())) {//TODO: maybe move the node buffer out of the traversal class + UploadStream.INSTANCE.commit(); + } } UploadStream.INSTANCE.tick(); 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 843afffa..73640f7a 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 @@ -3,9 +3,11 @@ package me.cortex.voxy.client.core.rendering.hierachical2; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; 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.building.SectionUpdateRouter; import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager; +import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList; import me.cortex.voxy.common.Logger; import me.cortex.voxy.common.world.WorldEngine; @@ -102,7 +104,7 @@ public class HierarchicalNodeManager { int id = this.nodeData.allocate(); this.nodeData.setNodePosition(id, position); - this.activeSectionMap.put(position, id|ID_TYPE_LEAF);//ID_TYPE_TOP + this.activeSectionMap.put(position, id|ID_TYPE_LEAF); this.nodeData.setNodeType(id, ID_TYPE_LEAF); //ID_TYPE_TOP this.updateRouter.watch(position, WorldEngine.UPDATE_FLAGS); } @@ -182,7 +184,8 @@ public class HierarchicalNodeManager { //2 branches, either its a leaf node -> emit a leaf request // or the nodes geometry must be empty (i.e. culled from the graph/tree) so add to tracker and watch - if (this.nodeData.isLeafNode(node)) { + int type = this.nodeData.getNodeType(node); + if (type == ID_TYPE_LEAF) { this.makeLeafRequest(node, this.nodeData.getNodeChildExistence(node)); } else { //Verify that the node section is not in the section store. if it is then it is a state desynchonization @@ -190,6 +193,8 @@ public class HierarchicalNodeManager { } } + //TODO: FIXME: so there is a fundamental issue with this, if the gpu requests from cpu before childExistance is set + // then everything explodes cause it wont get notified or updated private void makeLeafRequest(int node, byte childExistence) { long pos = this.nodeData.nodePosition(node); @@ -205,6 +210,7 @@ public class HierarchicalNodeManager { } long childPos = makeChildPos(pos, i); request.addChildRequirement(i); + //Insert all the children into the tracking map with the node id if (this.activeSectionMap.put(childPos, requestId|ID_TYPE_REQUEST) != NO_NODE) { throw new IllegalStateException("Leaf request creation failed to insert child into map as a mapping already existed for the node!"); @@ -297,7 +303,7 @@ public class HierarchicalNodeManager { if ((toAdd & (i << 1)) == 0) continue; request.addChildRequirement(i); long cpos = makeChildPos(position, i); - int prev = this.activeSectionMap.put(cpos, ID_TYPE_REQUEST|reqId); + int prev = this.activeSectionMap.put(cpos, reqId|ID_TYPE_REQUEST); if (prev!=-1) { throw new IllegalStateException("Child is already mapped to a node id " + WorldEngine.pprintPos(cpos) + " " + reqId + " " + prev); } @@ -386,9 +392,17 @@ public class HierarchicalNodeManager { //Process NodeChildRequest results private void consumeFinishedNodeChildRequest(int nodeId, NodeChildRequest request) { + //TODO:!!! NOTE: DONT + int children = this.nodeData.getChildPtr(nodeId); if (children != NO_NODE) { - //There are children already part of this node, so need to reallocate all the children + //There are children already part of this node, so need to reallocate all the children which is _really_ bad as it can cause so many desyncs + // between gpu and cpu its not even funny + + //TODO: what will need to be done is a fence be created, and to not release the ids until the gpu is done with them?? + // that _might :tm:_ help with preventing desyncs??? + // the issue is like a request right, sends id to cpu, that id might have changed and everything then proceeds to explode + int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(nodeId))); } else { @@ -396,6 +410,22 @@ public class HierarchicalNodeManager { } } + //============================================================================================ + + public boolean writeChanges(GlBuffer nodeBuffer) { + //TODO: use like compute based copy system or something + // since microcopies are bad + if (this.nodeUpdates.isEmpty()) { + return false; + } + for (int i : this.nodeUpdates) { + this.nodeData.writeNode(UploadStream.INSTANCE.upload(nodeBuffer, i*16L, 16L), i); + } + this.nodeUpdates.clear(); + return true; + } + + //============================================================================================================================================ private static int getChildIdx(long pos) { 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 e1d5afb5..89e915f1 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 @@ -244,6 +244,10 @@ public class HierarchicalOcclusionTraverser { } } + public GlBuffer getNodeBuffer() { + return this.nodeBuffer; + } + public void free() { this.traversal.free(); this.requestBuffer.free(); 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 4b89e2f2..adda3e6b 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 @@ -1,13 +1,15 @@ package me.cortex.voxy.client.core.rendering.hierachical2; import me.cortex.voxy.common.util.HierarchicalBitSet; +import org.lwjgl.system.MemoryUtil; public final class NodeStore { public static final int EMPTY_GEOMETRY_ID = -1; public static final int NODE_ID_MSK = ((1<<24)-1); public static final int REQUEST_ID_MSK = ((1<<16)-1); public static final int GEOMETRY_ID_MSK = (1<<24)-1; - public static final int MAX_GEOMETRY_ID = GEOMETRY_ID_MSK-1; + public static final int MAX_GEOMETRY_ID = GEOMETRY_ID_MSK-2; + public static final int ABSENT_GEOMETRY_ID = GEOMETRY_ID_MSK-1;//Value for if want to clear geometry and make gpu request it if its needed private static final int SENTINEL_EMPTY_GEOMETRY_ID = GEOMETRY_ID_MSK; private static final int SENTINEL_NULL_NODE_ID = NODE_ID_MSK -1; private static final int SENTINEL_REQUEST_ID = REQUEST_ID_MSK -1; @@ -167,8 +169,17 @@ public final class NodeStore { return ((this.localNodeData[id2idx(nodeId)+1]>>63)&1)!=0; } - public boolean isLeafNode(int nodeId) { - return ((this.localNodeData[id2idx(nodeId)+1]>>62)&1)!=0; + public int getNodeType(int nodeId) { + return (int)((this.localNodeData[id2idx(nodeId)+1]>>61)&3)<<30; + } + + public void setNodeType(int nodeId, int type) { + type >>>= 30; + int idx = id2idx(nodeId)+1; + long data = this.localNodeData[idx]; + data &= ~(3L<<61); + data |= ((long)type)<<61; + this.localNodeData[idx] = data; } public byte getNodeChildExistence(int nodeId) { @@ -184,9 +195,48 @@ public final class NodeStore { this.localNodeData[idx] = data; } + public int getChildPtrCount(int nodeId) { + long data = this.localNodeData[id2idx(nodeId)+1]; + return (int) ((data>>56)&0x7); + } + + public void setChildPtrCount(int nodeId, int count) { + if (count <= 0 || count>8) throw new IllegalArgumentException("Count: " + count); + int idx = id2idx(nodeId)+1; + long data = this.localNodeData[idx]; + data &= ~(7L<<56); + data |= ((long) (count - 1)) <<56; + this.localNodeData[idx] = data; + } + //Writes out a nodes data to the ptr in the compacted/reduced format public void writeNode(long ptr, int nodeId) { + long pos = this.nodePosition(nodeId); + MemoryUtil.memPutInt(ptr, (int) (pos>>32)); ptr += 4; + MemoryUtil.memPutInt(ptr, (int) pos); ptr += 4; + int z = 0; + int w = 0; + + short flags = 0; + flags |= (short) (this.getChildPtrCount(nodeId)<<2); + + { + int geometry = this.getNodeGeometry(nodeId); + if (geometry == -1) { + z |= 0xFFFFFF-1;//This is a special case, which basically says to the renderer that the geometry is empty (not that it doesnt exist) + } else { + z |= geometry&0xFFFFFF;//TODO: check and ensure bounds + } + } + + w |= this.getChildPtr(nodeId)&0xFFFFFF;//TODO: check and ensure bounds + + z |= (flags&0xFF)<<24; + w |= ((flags>>8)&0xFF)<<24; + + MemoryUtil.memPutInt(ptr, z); ptr += 4; + MemoryUtil.memPutInt(ptr, w); ptr += 4; } } 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 aabb0d77..8b43f9c2 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl @@ -70,6 +70,7 @@ void setupScreenspace(in UnpackedNode node) { //Checks if the node is implicitly culled (outside frustum) bool outsideFrustum() { + //printf("Cull point (%f %f %f)x(%f %f %f)", maxBB.x, maxBB.y, maxBB.z, minBB.x, minBB.y, minBB.z); return any(lessThanEqual(maxBB, vec3(-1f, -1f, 0f))) || any(lessThanEqual(vec3(1f, 1f, 1f), minBB)); }