Even more pain, but gpu side should fully work ™️
This commit is contained in:
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user