diff --git a/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java b/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java index ff57be8d..223ce04e 100644 --- a/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java +++ b/src/main/java/me/cortex/voxy/client/core/gl/shader/PrintfInjector.java @@ -203,6 +203,9 @@ public class PrintfInjector implements IShaderProcessor { ptr += 4; cnt++; String fmt = this.idToPrintfStringMap.get(id); + if (fmt == null) { + throw new IllegalStateException("Unknown id: "+ id); + } types.clear(); parsePrintfTypes(fmt, types); Object[] args = new Object[types.size()]; diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelFactory.java b/src/main/java/me/cortex/voxy/client/core/model/ModelFactory.java index 8a40fecd..b927b60d 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelFactory.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelFactory.java @@ -206,7 +206,7 @@ public class ModelFactory { throw new IllegalStateException("Block id already added: " + blockId + " for state: " + blockState); } - if (!this.blockStatesInFlight.remove(blockId)) { + if (!this.blockStatesInFlight.contains(blockId)) { throw new IllegalStateException("processing a texture bake result but the block state was not in flight!!"); } @@ -450,6 +450,10 @@ public class ModelFactory { //Set the mapping at the very end this.idMappings[blockId] = modelId; + if (!this.blockStatesInFlight.remove(blockId)) { + throw new IllegalStateException("processing a texture bake result but the block state was not in flight!!"); + } + //Upload/commit stream //TODO maybe dont do it for every uploaded block?? try to batch it UploadStream.INSTANCE.commit(); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/PrintfDebugUtil.java b/src/main/java/me/cortex/voxy/client/core/rendering/PrintfDebugUtil.java index 05f7a58d..89f3d8b8 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/PrintfDebugUtil.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/PrintfDebugUtil.java @@ -3,6 +3,7 @@ package me.cortex.voxy.client.core.rendering; import me.cortex.voxy.client.core.gl.shader.IShaderProcessor; import me.cortex.voxy.client.core.gl.shader.PrintfInjector; import me.cortex.voxy.client.core.gl.shader.ShaderType; +import me.cortex.voxy.common.Logger; import java.util.ArrayList; import java.util.List; @@ -18,9 +19,9 @@ public final class PrintfDebugUtil { static { if (ENABLE_PRINTF_DEBUGGING) { - PRINTF_object = new PrintfInjector(50000, 10, line -> { + PRINTF_object = new PrintfInjector(50000, 20, line -> { if (line.startsWith("LOG")) { - System.err.println(line); + Logger.info(line); } printfQueue.add(line); }, printfQueue::clear); diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java index 729d68aa..a3133378 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java @@ -150,8 +150,8 @@ public class HierarchicalOcclusionTraverser { glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, this.queueMetaBuffer.id); //Bind the hiz buffer - glBindSampler(0, this.hizSampler); glBindTextureUnit(0, this.hiZBuffer.getHizTextureId()); + glBindSampler(0, this.hizSampler); } public void doTraversal(Viewport viewport, int depthBuffer) { 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 d9499603..204c00bb 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 @@ -470,6 +470,7 @@ public class NodeManager { //TODO: make new SENTINAL value for this!!! NodeStore.NODE_ID_MSK-1 // check in shader aswell!!! + this.nodeData.setAllChildrenAreLeaf(nodeId, false);//Children dont exist, therefor set them to false this.nodeData.setChildPtr(nodeId, SENTINEL_EMPTY_CHILD_PTR); this.nodeData.setChildPtrCount(nodeId, 8); for (int i = 0; i < 8; i++) { @@ -587,7 +588,7 @@ public class NodeManager { this.nodeData.setChildPtr(nodeId, -1); int old = this.activeSectionMap.put(pos, NODE_TYPE_LEAF|nodeId); - + this.nodeData.setAllChildrenAreLeaf(nodeId, false);//Node is leaf so is not all child leaf this.invalidateNode(nodeId); } } @@ -873,16 +874,14 @@ public class NodeManager { this.nodeData.unmarkRequestInFlight(parentNodeId); //Change it from a leaf to an inner node - { - int pid = this.activeSectionMap.remove(request.getPosition()); - if (pid == -1 || (pid & NODE_TYPE_MSK) != NODE_TYPE_LEAF) { - throw new IllegalStateException("Unexpected node mapping: " + pid); - } + //Set the type from leaf to inner node + if ((this.activeSectionMap.put(request.getPosition(), NODE_TYPE_INNER|parentNodeId)&NODE_TYPE_MSK)!=NODE_TYPE_LEAF) { + throw new IllegalStateException(); } - //_this is why it hasnt been working, grrr, wasnt doing this_ - this.activeSectionMap.put(request.getPosition(), NODE_TYPE_INNER|parentNodeId);//Set the type from leaf to inner node - this.invalidateNode(parentNodeId); + this.nodeData.setAllChildrenAreLeaf(parentNodeId, true); + + //TODO: Need to set AllChildrenAreLeaf of the parent of the parent to false } else if (parentNodeType==NODE_TYPE_INNER) { //For this, only need to add the nodes to the existing child set thing (shuffle around whatever) dont ever have to remove nodes @@ -1238,11 +1237,15 @@ public class NodeManager { this.recurseRemoveChildNodes(pPos);//TODO: make this download/fetch the data instead of just deleting it //this.clearId(pId); + //Make node a leaf int old = this.activeSectionMap.put(pPos, NODE_TYPE_LEAF|pId); if (old == -1) throw new IllegalStateException(); if ((old&NODE_TYPE_MSK)!=NODE_TYPE_INNER || (old&NODE_ID_MSK)!=pId) throw new IllegalStateException(); + + //Mark all children as not leaf (as this is a leaf node) + this.nodeData.setAllChildrenAreLeaf(pId, false); } } @@ -1271,87 +1274,6 @@ public class NodeManager { } } } - /* - public void removeNodeGeometryOld(long pos) { - int nodeId = this.activeSectionMap.get(pos); - if (nodeId == -1) { - Logger.error("Got geometry removal for pos " + WorldEngine.pprintPos(pos) + " but it was not in active map, ignoring!"); - return; - } - int nodeType = nodeId&NODE_TYPE_MSK; - nodeId &= NODE_ID_MSK; - if (nodeType == NODE_TYPE_REQUEST) { - Logger.error("Tried removing geometry for pos: " + WorldEngine.pprintPos(pos) + " but its type was a request, ignoring!"); - 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 - // by requesting the geometry of the parent, it means that the system will automatically handle itself - // (if only a bit slow as needs to go roundabout in the pipeline) - // but what it means is the parent then gets geometry, and the child still has the clear request from this - // which means magically everything might maybe should work tm? - //Logger.warn("Tried removing geometry for leaf node: " + WorldEngine.pprintPos(pos) + " but this is not yet supported, ignoring!"); - - if (WorldEngine.getLevel(pos) == MAX_LOD_LAYERS-1) { - //Cannot remove top level nodes - - //Logger.info("Tried cleaning top level node " + WorldEngine.pprintPos(pos)); - - this.removeGeometryInternal(pos, nodeId); - return; - } - - long pPos = makeParentPos(pos); - int pId = this.activeSectionMap.get(pPos); - if (pId == -1) throw new IllegalStateException("Parent node must exist"); - if ((pId&NODE_TYPE_MSK)!=NODE_TYPE_INNER) throw new IllegalStateException("Parent node must be an inner node"); - pId &= NODE_ID_MSK; - - 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"); - - this.processRequest(pPos);//Assume we can do this, TODO: maybe dont? - } else { - //Else make the parent node a leaf node and remove all the children - - //THIS IS MOST IMPORTANT - //Logger.error("TODO: THIS 2"); - - //TODO: cancel any requests with the parent node - // update the parent nodes child existance with respect to the request if it had - // recurseRemoveNode(); on all the children (which will include us) - // update the type of the parent node - Logger.error("TODO: FINISH THIS"); - } - //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 - if (this.watcher.unwatch(pos, WorldEngine.UPDATE_TYPE_BLOCK_BIT)) { - throw new IllegalStateException("Unwatching position for geometry removal at: " + WorldEngine.pprintPos(pos) + " resulted in full removal"); - } - //Remove geometry and set to null - //TODO: download and remove instead of just removing, and store in ram cache for later!! - this.geometryManager.removeSection(geometryId); - this.nodeData.setNodeGeometry(nodeId, NULL_GEOMETRY_ID); - //this.cleaner - } - this.invalidateNode(nodeId); - } - */ //================================================================================================================== public boolean writeChanges(GlBuffer nodeBuffer) { @@ -1547,6 +1469,7 @@ public class NodeManager { } //TODO: check SENTINEL_EMPTY_CHILD_PTR if (childPtr != SENTINEL_EMPTY_CHILD_PTR) { + boolean allChildrenLeaf = true; for (int i = 0; i < childCount; i++) { if (!this.nodeData.nodeExists(i + childPtr))//All children must exist throw new IllegalStateException(); @@ -1554,10 +1477,25 @@ public class NodeManager { if (makeParentPos(cPos) != pos)//Parent of child must be this position throw new IllegalStateException(); cActiveExistence |= 1 << getChildIdx(cPos); + + int cNode = this.activeSectionMap.get(cPos); + if (cNode == -1) { + throw new IllegalStateException(); + } + if ((cNode&NODE_TYPE_MSK) != NODE_TYPE_LEAF) { + allChildrenLeaf = false; + } //Recurse into child this.verifyNode(cPos, seenPositions, seenNodes); } + + if (this.nodeData.getAllChildrenAreLeaf(node) != allChildrenLeaf) { + throw new IllegalStateException(); + } } else { + if (this.nodeData.getAllChildrenAreLeaf(node)) { + throw new IllegalStateException(); + } //TODO: verify SENTINEL_EMPTY_CHILD_PTR is valid childCount = 0; } @@ -1573,9 +1511,14 @@ public class NodeManager { throw new IllegalStateException(); } } else if (type == NODE_TYPE_LEAF) { + if (this.nodeData.getAllChildrenAreLeaf(node)) { + throw new IllegalStateException(); + } + if (this.nodeData.getChildPtr(node) != -1) {//Leafs cannot have child ptrs throw new IllegalStateException(); } + if (this.nodeData.getNodeGeometry(node) == NULL_GEOMETRY_ID) {//Leafs cannot have null geometry throw new IllegalStateException(); } 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 abff2143..a06aab32 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 @@ -203,6 +203,7 @@ public final class NodeStore { this.localNodeData[id2idx(nodeId)+2] &= ~(1L<<16); this.localNodeData[id2idx(nodeId)+2] |= state?1L<<16:0; } + public boolean getAllChildrenAreLeaf(int nodeId) { return ((this.localNodeData[id2idx(nodeId)+2]>>16)&1)!=0; } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/TestNodeManager.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/TestNodeManager.java index 4f8346dd..948b6fc7 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/TestNodeManager.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/TestNodeManager.java @@ -285,7 +285,7 @@ public class TestNodeManager { Logger.SHUTUP = true; - if (false) { + if (true) { for (int q = 0; q < ITER_COUNT; q++) { //Logger.info("Iteration "+ q); if (runTest(INNER_ITER_COUNT, q, seenTraces, GEO_REM)) { diff --git a/src/main/java/me/cortex/voxy/common/config/storage/rocksdb/RocksDBStorageBackend.java b/src/main/java/me/cortex/voxy/common/config/storage/rocksdb/RocksDBStorageBackend.java index be4396a7..bac9c4c8 100644 --- a/src/main/java/me/cortex/voxy/common/config/storage/rocksdb/RocksDBStorageBackend.java +++ b/src/main/java/me/cortex/voxy/common/config/storage/rocksdb/RocksDBStorageBackend.java @@ -51,7 +51,6 @@ public class RocksDBStorageBackend extends StorageBackend { */ final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions() - .optimizeUniversalStyleCompaction() .optimizeForPointLookup(128); final List cfDescriptors = Arrays.asList( 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 c6a590db..8f3d6995 100644 --- a/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/hierarchical/screenspace.glsl @@ -24,12 +24,13 @@ vec2 size; uint BASE_IDX = gl_LocalInvocationID.x*8; shared vec2[LOCAL_SIZE*8] screenPoints; +UnpackedNode node22; //Sets up screenspace with the given node id, returns true on success false on failure/should not continue //Accesses data that is setup in the main traversal and is just shared to here void setupScreenspace(in UnpackedNode node) { //TODO: Need to do aabb size for the nodes, it must be an overesimate of all the children - + node22 = node; /* Transform transform = transforms[getTransformIndex(node)]; @@ -59,12 +60,6 @@ void setupScreenspace(in UnpackedNode node) { screenPoints[BASE_IDX+i] = point.xy*0.5f+0.5f; } - //TODO: MORE ACCURATLY DETERMIN SCREENSPACE AREA, this can be done by computing and adding - // the projected surface area of each face/quad which winding order faces the camera - // (this is just the dot product of 2 projected vectors) - - //can do a funny by not doing the perspective divide except on the output of the area - //printf("Screenspace MIN: %f, %f, %f MAX: %f, %f, %f", minBB.x,minBB.y,minBB.z, maxBB.x,maxBB.y,maxBB.z); //Convert to screenspace @@ -77,7 +72,7 @@ void setupScreenspace(in UnpackedNode node) { //Checks if the node is implicitly culled (outside frustum) bool outsideFrustum() { - return any(lessThanEqual(maxBB, vec3(0.0f))) || any(lessThanEqual(vec3(1.0f), minBB)) || maxBB.z < 0.5f;// maxBB.z > 1 is actually wrong + return any(lessThanEqual(maxBB, vec3(0.0f))) || any(lessThanEqual(vec3(1.0f), minBB));// maxBB.z > 1 is actually wrong //|| any(lessThanEqual(minBB, vec3(0.0f, 0.0f, 0.0f))) || any(lessThanEqual(vec3(1.0f, 1.0f, 1.0f), maxBB)); } @@ -87,20 +82,18 @@ bool isCulledByHiz() { // return false;//Just cull it for now cause other culling isnt working, TODO: FIXME //} - vec2 ssize = size * vec2(screenW, screenH); float miplevel = ceil(log2(max(max(ssize.x, ssize.y),1))); - miplevel = clamp(miplevel, 1, 20); + miplevel = clamp(miplevel, 0, 20); vec2 midpoint = (maxBB.xy + minBB.xy)*0.5f; //TODO: maybe get rid of clamp //Todo: replace with some rasterization, e.g. especially for request back to cpu - midpoint = clamp(midpoint, vec2(0), vec2(1)); - bool culled = textureLod(hizDepthSampler, vec3(midpoint, minBB.z), miplevel) < 0.0001f; - - if (culled) { - printf("HiZ sample point culled: (%f,%f)@%f against %f", midpoint.x, midpoint.y, miplevel, minBB.z); + vec2 midpoint2 = clamp(midpoint, vec2(0), vec2(1)); + bool culled = textureLod(hizDepthSampler, vec3(midpoint2, minBB.z), miplevel) < 0.0001f; + //printf("HiZ sample point: (%f,%f)@%f against %f", midpoint.x, midpoint.y, miplevel, minBB.z); + if (culled && node22.lodLevel != 4) { + printf("HiZ sample point: (%f,%f)@%f against %f", midpoint.x, midpoint.y, miplevel, minBB.z); } - return culled; }