Even more pain, but gpu side should fully work ™️

This commit is contained in:
mcrcortex
2024-09-17 01:00:03 +10:00
parent 0aeb0fbf21
commit df5c34c626
5 changed files with 99 additions and 9 deletions

View File

@@ -75,7 +75,9 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome); Arrays.stream(world.getMapper().getBiomeEntries()).forEach(this.modelService::addBiome);
world.getMapper().setBiomeCallback(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; final int H_WIDTH = 1;
for (int x = -H_WIDTH; x <= H_WIDTH; x++) { for (int x = -H_WIDTH; x <= H_WIDTH; x++) {
for (int y = -1; y <= 0; y++) { for (int y = -1; y <= 0; y++) {
@@ -83,7 +85,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(4, x, y, z)); this.nodeManager.insertTopLevelNode(WorldEngine.getWorldSectionId(4, x, y, z));
} }
} }
} }*/
} }
public void setup(Camera camera) { public void setup(Camera camera) {
@@ -117,6 +119,9 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
this.sectionUpdateQueue.consume(); this.sectionUpdateQueue.consume();
this.geometryUpdateQueue.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(); UploadStream.INSTANCE.tick();

View File

@@ -3,9 +3,11 @@ package me.cortex.voxy.client.core.rendering.hierachical2;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; 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.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter; 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.section.AbstractSectionGeometryManager;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList; import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList;
import me.cortex.voxy.common.Logger; import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.world.WorldEngine; import me.cortex.voxy.common.world.WorldEngine;
@@ -102,7 +104,7 @@ public class HierarchicalNodeManager {
int id = this.nodeData.allocate(); int id = this.nodeData.allocate();
this.nodeData.setNodePosition(id, position); 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); 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 //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 // 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)); this.makeLeafRequest(node, this.nodeData.getNodeChildExistence(node));
} else { } else {
//Verify that the node section is not in the section store. if it is then it is a state desynchonization //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) { private void makeLeafRequest(int node, byte childExistence) {
long pos = this.nodeData.nodePosition(node); long pos = this.nodeData.nodePosition(node);
@@ -205,6 +210,7 @@ public class HierarchicalNodeManager {
} }
long childPos = makeChildPos(pos, i); long childPos = makeChildPos(pos, i);
request.addChildRequirement(i); request.addChildRequirement(i);
//Insert all the children into the tracking map with the node id //Insert all the children into the tracking map with the node id
if (this.activeSectionMap.put(childPos, requestId|ID_TYPE_REQUEST) != NO_NODE) { 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!"); 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; if ((toAdd & (i << 1)) == 0) continue;
request.addChildRequirement(i); request.addChildRequirement(i);
long cpos = makeChildPos(position, 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) { if (prev!=-1) {
throw new IllegalStateException("Child is already mapped to a node id " + WorldEngine.pprintPos(cpos) + " " + reqId + " " + prev); 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 //Process NodeChildRequest results
private void consumeFinishedNodeChildRequest(int nodeId, NodeChildRequest request) { private void consumeFinishedNodeChildRequest(int nodeId, NodeChildRequest request) {
//TODO:!!! NOTE: DONT
int children = this.nodeData.getChildPtr(nodeId); int children = this.nodeData.getChildPtr(nodeId);
if (children != NO_NODE) { 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))); int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(nodeId)));
} else { } 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) { private static int getChildIdx(long pos) {

View File

@@ -244,6 +244,10 @@ public class HierarchicalOcclusionTraverser {
} }
} }
public GlBuffer getNodeBuffer() {
return this.nodeBuffer;
}
public void free() { public void free() {
this.traversal.free(); this.traversal.free();
this.requestBuffer.free(); this.requestBuffer.free();

View File

@@ -1,13 +1,15 @@
package me.cortex.voxy.client.core.rendering.hierachical2; package me.cortex.voxy.client.core.rendering.hierachical2;
import me.cortex.voxy.common.util.HierarchicalBitSet; import me.cortex.voxy.common.util.HierarchicalBitSet;
import org.lwjgl.system.MemoryUtil;
public final class NodeStore { public final class NodeStore {
public static final int EMPTY_GEOMETRY_ID = -1; public static final int EMPTY_GEOMETRY_ID = -1;
public static final int NODE_ID_MSK = ((1<<24)-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 REQUEST_ID_MSK = ((1<<16)-1);
public static final int GEOMETRY_ID_MSK = (1<<24)-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_EMPTY_GEOMETRY_ID = GEOMETRY_ID_MSK;
private static final int SENTINEL_NULL_NODE_ID = NODE_ID_MSK -1; private static final int SENTINEL_NULL_NODE_ID = NODE_ID_MSK -1;
private static final int SENTINEL_REQUEST_ID = REQUEST_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; return ((this.localNodeData[id2idx(nodeId)+1]>>63)&1)!=0;
} }
public boolean isLeafNode(int nodeId) { public int getNodeType(int nodeId) {
return ((this.localNodeData[id2idx(nodeId)+1]>>62)&1)!=0; 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) { public byte getNodeChildExistence(int nodeId) {
@@ -184,9 +195,48 @@ public final class NodeStore {
this.localNodeData[idx] = data; 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 //Writes out a nodes data to the ptr in the compacted/reduced format
public void writeNode(long ptr, int nodeId) { 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;
} }
} }

View File

@@ -70,6 +70,7 @@ void setupScreenspace(in UnpackedNode node) {
//Checks if the node is implicitly culled (outside frustum) //Checks if the node is implicitly culled (outside frustum)
bool outsideFrustum() { 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)); return any(lessThanEqual(maxBB, vec3(-1f, -1f, 0f))) || any(lessThanEqual(vec3(1f, 1f, 1f), minBB));
} }