it works!

This commit is contained in:
mcrcortex
2024-07-16 00:14:53 +10:00
parent 0ff2db1881
commit 72e35557a4
9 changed files with 175 additions and 28 deletions

View File

@@ -74,7 +74,7 @@ dependencies {
modRuntimeOnly("maven.modrinth:spark:1.10.73-fabric") modRuntimeOnly("maven.modrinth:spark:1.10.73-fabric")
modRuntimeOnly("maven.modrinth:fabric-permissions-api:0.3.1") modRuntimeOnly("maven.modrinth:fabric-permissions-api:0.3.1")
modRuntimeOnly("maven.modrinth:nsight-loader:1.2.0") //modRuntimeOnly("maven.modrinth:nsight-loader:1.2.0")
modImplementation('io.github.douira:glsl-transformer:2.0.1') modImplementation('io.github.douira:glsl-transformer:2.0.1')
} }

View File

@@ -12,6 +12,7 @@ import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionRenderer; import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionRenderer;
import me.cortex.voxy.client.core.rendering.hierarchical.INodeInteractor; import me.cortex.voxy.client.core.rendering.hierarchical.INodeInteractor;
import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager; import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
import me.cortex.voxy.client.core.rendering.util.UploadStream; import me.cortex.voxy.client.core.rendering.util.UploadStream;
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection; import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
import me.cortex.voxy.common.world.WorldEngine; import me.cortex.voxy.common.world.WorldEngine;
@@ -27,6 +28,7 @@ import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -52,7 +54,10 @@ import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData;
public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46HierarchicalViewport>, AbstractRenderWorldInteractor { public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46HierarchicalViewport>, AbstractRenderWorldInteractor {
private final HierarchicalOcclusionRenderer sectionSelector; private final HierarchicalOcclusionRenderer sectionSelector;
private final MeshManager meshManager = new MeshManager(); private final MeshManager meshManager = new MeshManager();
private final PrintfInjector printf = new PrintfInjector(100000, 10, System.out::println);
private final List<String> printfQueue = new ArrayList<>();
private final PrintfInjector printf = new PrintfInjector(100000, 10, this.printfQueue::add);
private final GlBuffer renderSections = new GlBuffer(100_000 * 4 + 4).zero(); private final GlBuffer renderSections = new GlBuffer(100_000 * 4 + 4).zero();
@@ -99,6 +104,11 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
@Override @Override
public void setupRender(Frustum frustum, Camera camera) { public void setupRender(Frustum frustum, Camera camera) {
{//Tick upload and download queues
UploadStream.INSTANCE.tick();
DownloadStream.INSTANCE.tick();
}
{ {
boolean didHaveBiomeChange = false; boolean didHaveBiomeChange = false;
@@ -153,7 +163,14 @@ public class Gl46HierarchicalRenderer implements IRenderInterface<Gl46Hierarchic
@Override @Override
public void addDebugData(List<String> debug) { public void addDebugData(List<String> debug) {
debug.add("Printf Queue: ");
debug.addAll(this.printfQueue);
for (String a : this.printfQueue) {
if (a.startsWith("LOG")) {
System.err.println(a);
}
}
this.printfQueue.clear();
} }

View File

@@ -13,12 +13,13 @@ import org.joml.Matrix4f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.ARBDirectStateAccess.nglClearNamedBufferSubData;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL30.GL_R32UI;
import static org.lwjgl.opengl.GL30.glBindBufferBase; import static org.lwjgl.opengl.GL30.glBindBufferBase;
import static org.lwjgl.opengl.GL33.glBindSampler; import static org.lwjgl.opengl.GL33.glBindSampler;
import static org.lwjgl.opengl.GL33.glGenSamplers; import static org.lwjgl.opengl.GL33.glGenSamplers;
import static org.lwjgl.opengl.GL42C.*; import static org.lwjgl.opengl.GL43.*;
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
import static org.lwjgl.opengl.GL43.glDispatchCompute;
import static org.lwjgl.opengl.GL45.glBindTextureUnit; import static org.lwjgl.opengl.GL45.glBindTextureUnit;
public class HierarchicalOcclusionRenderer { public class HierarchicalOcclusionRenderer {
@@ -30,12 +31,14 @@ public class HierarchicalOcclusionRenderer {
private final Shader hierarchicalTraversal; private final Shader hierarchicalTraversal;
private final PrintfInjector printf; private final PrintfInjector printf;
private final GlBuffer nodeQueue; private final GlBuffer nodeQueueA;
private final GlBuffer nodeQueueB;
private final GlBuffer uniformBuffer; private final GlBuffer uniformBuffer;
public HierarchicalOcclusionRenderer(INodeInteractor interactor, MeshManager mesh, PrintfInjector printf) { public HierarchicalOcclusionRenderer(INodeInteractor interactor, MeshManager mesh, PrintfInjector printf) {
this.nodeManager = new NodeManager(interactor, mesh); this.nodeManager = new NodeManager(interactor, mesh);
this.nodeQueue = new GlBuffer(1000000*4+4).zero(); this.nodeQueueA = new GlBuffer(1000000*4+4).zero();
this.nodeQueueB = new GlBuffer(1000000*4+4).zero();
this.uniformBuffer = new GlBuffer(1024).zero(); this.uniformBuffer = new GlBuffer(1024).zero();
this.printf = printf; this.printf = printf;
this.hierarchicalTraversal = Shader.make(printf) this.hierarchicalTraversal = Shader.make(printf)
@@ -63,11 +66,22 @@ public class HierarchicalOcclusionRenderer {
MemoryUtil.memPutInt(ptr, NodeManager.REQUEST_QUEUE_SIZE); ptr += 4; MemoryUtil.memPutInt(ptr, NodeManager.REQUEST_QUEUE_SIZE); ptr += 4;
MemoryUtil.memPutInt(ptr, 1000000); ptr += 4; MemoryUtil.memPutInt(ptr, 1000000); ptr += 4;
//decendSSS (decend screen space size)
MemoryUtil.memPutFloat(ptr, 128*128); ptr += 4;
} }
public void doHierarchicalTraversalSelection(Gl46HierarchicalViewport viewport, int depthBuffer, GlBuffer renderSelectionResult) { public void doHierarchicalTraversalSelection(Gl46HierarchicalViewport viewport, int depthBuffer, GlBuffer renderSelectionResult) {
this.uploadUniform(viewport); this.uploadUniform(viewport);
this.nodeManager.upload(); this.nodeManager.upload();
{
long ptr = UploadStream.INSTANCE.upload(this.nodeQueueA, 0, 8);
MemoryUtil.memPutInt(ptr, 1); ptr += 4;
MemoryUtil.memPutInt(ptr, 0);
}
UploadStream.INSTANCE.commit(); UploadStream.INSTANCE.commit();
//Make hiz //Make hiz
@@ -78,9 +92,10 @@ public class HierarchicalOcclusionRenderer {
{ {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id); glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueue.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueA.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.nodeManager.requestQueue.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.nodeManager.requestQueue.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, renderSelectionResult.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, renderSelectionResult.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueB.id);
//Bind the hiz buffer //Bind the hiz buffer
glBindSampler(0, this.hizSampler); glBindSampler(0, this.hizSampler);
@@ -89,7 +104,35 @@ public class HierarchicalOcclusionRenderer {
this.printf.bind(); this.printf.bind();
{ {
//Dispatch hierarchies //Dispatch hierarchies
nglClearNamedBufferSubData(this.nodeQueueB.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueA.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueB.id);
glDispatchCompute(1,1,1); glDispatchCompute(1,1,1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
nglClearNamedBufferSubData(this.nodeQueueA.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueB.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueA.id);
glDispatchCompute(8,1,1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
nglClearNamedBufferSubData(this.nodeQueueB.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueA.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueB.id);
glDispatchCompute(16,1,1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
nglClearNamedBufferSubData(this.nodeQueueA.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueB.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueA.id);
glDispatchCompute(32,1,1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
nglClearNamedBufferSubData(this.nodeQueueB.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueueA.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.nodeQueueB.id);
glDispatchCompute(64,1,1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
} }
glBindSampler(0, 0); glBindSampler(0, 0);
@@ -98,7 +141,8 @@ public class HierarchicalOcclusionRenderer {
} }
public void free() { public void free() {
this.nodeQueue.free(); this.nodeQueueA.free();
this.nodeQueueB.free();
this.hiz.free(); this.hiz.free();
this.nodeManager.free(); this.nodeManager.free();
glDeleteSamplers(this.hizSampler); glDeleteSamplers(this.hizSampler);

View File

@@ -128,8 +128,8 @@ public class NodeManager {
this.requestQueue = new GlBuffer(REQUEST_QUEUE_SIZE*4+4); this.requestQueue = new GlBuffer(REQUEST_QUEUE_SIZE*4+4);
Arrays.fill(this.localNodeData, 0); Arrays.fill(this.localNodeData, 0);
this.nodeAllocations.allocateNext();
this.setNodePosition(0, WorldEngine.getWorldSectionId(2, 0,0,0)); this.setNodePosition(0, WorldEngine.getWorldSectionId(4, 0,0,0));
this.setChildPtr(0, NODE_MSK, 0); this.setChildPtr(0, NODE_MSK, 0);
this.setMeshId(0, MESH_MSK); this.setMeshId(0, MESH_MSK);
this.pushNode(0); this.pushNode(0);
@@ -148,7 +148,7 @@ public class NodeManager {
//Returns the mesh offset/id for the given node or -1 if it doesnt exist //Returns the mesh offset/id for the given node or -1 if it doesnt exist
private int getNodeMesh(int node) { private int getNodeMesh(int node) {
return (int) (this.localNodeData[node*3+1]&((1<<24)-1)); return (int) (this.localNodeData[node*3+1]&MESH_MSK);
} }
private int getNodeChildPtr(int node) { private int getNodeChildPtr(int node) {
@@ -224,6 +224,7 @@ public class NodeManager {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int requestOp = MemoryUtil.memGetInt(ptr + i*4L); int requestOp = MemoryUtil.memGetInt(ptr + i*4L);
int node = requestOp&NODE_MSK; int node = requestOp&NODE_MSK;
System.out.println("Got request for node: " + node);
if (this.isLeafNode(node)) { if (this.isLeafNode(node)) {
//If its a leaf node and it has a request, it must need the children //If its a leaf node and it has a request, it must need the children
@@ -255,7 +256,7 @@ public class NodeManager {
} else { } else {
//If its not a leaf node, it must be missing the inner mesh so request it //If its not a leaf node, it must be missing the inner mesh so request it
if (this.getNodeMesh(node) != -1) { if (this.getNodeMesh(node) != MESH_MSK) {
//Node already has a mesh, ignore it, but might be a sign that an error has occured //Node already has a mesh, ignore it, but might be a sign that an error has occured
System.err.println("Requested a mesh for node, however the node already has a mesh"); System.err.println("Requested a mesh for node, however the node already has a mesh");
@@ -312,6 +313,7 @@ public class NodeManager {
//TODO: FIXME!! if we get a node that has an update and is watched but no id for it, it could be an update state from //TODO: FIXME!! if we get a node that has an update and is watched but no id for it, it could be an update state from
// an empty node to non empty node, this means we need to invalidate all the childrens positions and move them! // an empty node to non empty node, this means we need to invalidate all the childrens positions and move them!
// then also update the parent pointer // then also update the parent pointer
//TODO: Also need a way to remove sections, requires shuffling stuff around
if (id == NO_NODE) { if (id == NO_NODE) {
//The built mesh section is no longer needed, discard it //The built mesh section is no longer needed, discard it
// TODO: could probably?? cache the mesh in ram that way if its requested? it can be immediatly fetched while a newer mesh is built?? // TODO: could probably?? cache the mesh in ram that way if its requested? it can be immediatly fetched while a newer mesh is built??
@@ -360,7 +362,7 @@ public class NodeManager {
if (request.isSatisfied()) { if (request.isSatisfied()) {
//If request is now satisfied update the internal nodes, create the children and reset + release the request set //If request is now satisfied update the internal nodes, create the children and reset + release the request set
this.completeRequest(request); this.completeLeafRequest(request);
//Reset + release //Reset + release
request.clear(); request.clear();
@@ -392,20 +394,36 @@ public class NodeManager {
} }
private void completeRequest(LeafRequest request) { private void completeLeafRequest(LeafRequest request) {
//TODO: need to actually update all of the pos2meshId of the children to point to there new nodes //TODO: need to actually update all of the pos2meshId of the children to point to there new nodes
int msk = Byte.toUnsignedInt(request.nonAirMask()); int msk = Byte.toUnsignedInt(request.nonAirMask());
int baseIdx = this.nodeAllocations.allocateNextConsecutiveCounted(Integer.bitCount(msk)); int baseIdx = this.nodeAllocations.allocateNextConsecutiveCounted(Integer.bitCount(msk));
int cnt = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if ((msk&(1<<i))!=0) { if ((msk&(1<<i))!=0) {
//It means the section actually exists, so add and upload it //It means the section actually exists, so add and upload it
// aswell as add it to the mapping + push the node // aswell as add it to the mapping + push the node
int id = baseIdx+(cnt++);
long pos = request.childPositions[i];
//Put it in the mapping
this.pos2meshId.putIfAbsent(pos, id);
this.setNodePosition(id, pos);
this.setMeshId(id, request.getMeshId(i));
this.setChildPtr(id, NODE_MSK, 0);
this.pushNode(id);//request it to be uploaded
} else { } else {
//The section was empty, so just remove/skip it //The section was empty, so just remove/skip it
} }
} }
if (cnt == 0) {
throw new IllegalStateException("Should not reach here");
}
//Actually signal the update
this.setChildPtr(request.nodeId, baseIdx, cnt);
this.pushNode(request.nodeId);
} }
private final IntArrayList nodeUpdates = new IntArrayList(); private final IntArrayList nodeUpdates = new IntArrayList();
@@ -425,9 +443,9 @@ public class NodeManager {
flags |= this.isEmptyNode(id)?2:0; flags |= this.isEmptyNode(id)?2:0;
flags |= Math.max(0, this.getNodeChildCnt(id)-1)<<2; flags |= Math.max(0, this.getNodeChildCnt(id)-1)<<2;
int a = this.getNodeMesh(id)|(flags&0xFF); int a = this.getNodeMesh(id)|((flags&0xFF)<<24);
int b = this.getNodeChildPtr(id)|((flags>>8)&0xFF); int b = this.getNodeChildPtr(id)|(((flags>>8)&0xFF)<<24);
System.out.println("Setting mesh " + this.getNodeMesh(id) + " for node " + id);
MemoryUtil.memPutInt(dst, a); dst += 4; MemoryUtil.memPutInt(dst, a); dst += 4;
MemoryUtil.memPutInt(dst, b); dst += 4; MemoryUtil.memPutInt(dst, b); dst += 4;
} }
@@ -445,6 +463,7 @@ public class NodeManager {
} }
public void download() { public void download() {
//this.pushNode(0);
//Download the request queue then clear the counter (first 4 bytes) //Download the request queue then clear the counter (first 4 bytes)
DownloadStream.INSTANCE.download(this.requestQueue, this::processRequestQueue); DownloadStream.INSTANCE.download(this.requestQueue, this::processRequestQueue);
DownloadStream.INSTANCE.commit(); DownloadStream.INSTANCE.commit();

View File

@@ -33,9 +33,10 @@ public class HierarchicalBitSet {
idx = Long.numberOfTrailingZeros(~cp) + 64*idx; idx = Long.numberOfTrailingZeros(~cp) + 64*idx;
long dp = this.D[idx]; long dp = this.D[idx];
idx = Long.numberOfTrailingZeros(~dp) + 64*idx; idx = Long.numberOfTrailingZeros(~dp) + 64*idx;
int ret = idx;
dp |= 1L<<(idx&0x3f); dp |= 1L<<(idx&0x3f);
this.D[idx>>6] = dp; this.D[idx>>6] = dp;
int ret = idx;
if (dp==-1) { if (dp==-1) {
idx >>= 6; idx >>= 6;
cp |= 1L<<(idx&0x3f); cp |= 1L<<(idx&0x3f);
@@ -50,9 +51,26 @@ public class HierarchicalBitSet {
} }
} }
this.cnt++; this.cnt++;
return ret; return ret;
} }
private void set(int idx) {
long dp = this.D[idx>>6] |= 1L<<(idx&0x3f);
if (dp==-1) {
idx >>= 6;
long cp = (this.C[idx>>6] |= 1L<<(idx&0x3f));
if (cp==-1) {
idx >>= 6;
long bp = this.B[idx>>6] |= 1L<<(idx&0x3f);
if (bp==-1) {
this.A |= 1L<<(idx&0x3f);
}
}
}
this.cnt++;
}
//Returns the next free index from idx //Returns the next free index from idx
private int findNextFree(int idx) { private int findNextFree(int idx) {
int pos = Long.numberOfTrailingZeros((~this.A)|((1L<<(idx>>18))-1)); int pos = Long.numberOfTrailingZeros((~this.A)|((1L<<(idx>>18))-1));
@@ -66,9 +84,33 @@ public class HierarchicalBitSet {
if (this.cnt+count>this.limit) { if (this.cnt+count>this.limit) {
return -2;//Limit reached return -2;//Limit reached
} }
//At a minimum maybe just do a while loop for testing //TODO:FIXME DONT DO THIS, do a faster search
return 0; int i = 0;
while (true) {
boolean isFree = true;
for (int j = 0; j < count; j++) {
if (this.isSet(i+j)) {
isFree = false;
break;
}
}
if (isFree) {
for (int j = 0; j < count; j++) {
this.set(j + i);
}
return i;
} else {
i++;//THIS IS SLOW BUT WORKS
/* TODO: FIX AND FINISH OPTIMIZATION
i +=
while (this.D[i>>6] == -1) {
i++;
}
*/
}
}
} }

View File

@@ -4,6 +4,7 @@
#define REQUEST_QUEUE_INDEX 3 #define REQUEST_QUEUE_INDEX 3
#define RENDER_QUEUE_INDEX 4 #define RENDER_QUEUE_INDEX 4
#define TRANSFORM_ARRAY_INDEX 5 #define TRANSFORM_ARRAY_INDEX 5
#define NEXT_NODE_QUEUE_INDEX 6
//Samplers //Samplers
#define HIZ_BINDING_INDEX 0 #define HIZ_BINDING_INDEX 0

View File

@@ -76,6 +76,10 @@ uint getChildCount(in UnpackedNode node) {
return ((node.flags >> 2)&7U)+1; return ((node.flags >> 2)&7U)+1;
} }
uint getChildPtr(in UnpackedNode node) {
return node.childPtr;
}
uint getTransformIndex(in UnpackedNode node) { uint getTransformIndex(in UnpackedNode node) {
return (node.flags >> 5)&31u; return (node.flags >> 5)&31u;
} }

View File

@@ -47,7 +47,7 @@ void setupScreenspace(in UnpackedNode node) {
for (int i = 1; i < 8; i++) { for (int i = 1; i < 8; i++) {
//NOTE!: cant this be precomputed and put in an array?? in the scene uniform?? //NOTE!: cant this be precomputed and put in an array?? in the scene uniform??
vec4 pPoint = (VP*vec4(vec3((i&1)!=0,(i&2)!=0,(i&4)!=0)*32,1));//Size of section is 32x32x32 (need to change it to a bounding box in the future) vec4 pPoint = (VP*vec4(vec3((i&1)!=0,(i&2)!=0,(i&4)!=0),1))*(32<<node.lodLevel);//Size of section is 32x32x32 (need to change it to a bounding box in the future)
pPoint += base; pPoint += base;
vec3 point = pPoint.xyz/pPoint.w; vec3 point = pPoint.xyz/pPoint.w;
//TODO: CLIP TO VIEWPORT //TODO: CLIP TO VIEWPORT
@@ -78,5 +78,5 @@ bool isCulledByHiz() {
//Returns if we should decend into its children or not //Returns if we should decend into its children or not
bool shouldDecend() { bool shouldDecend() {
//printf("Screen area %f: %f, %f", (size.x*size.y*float(screenW)*float(screenH)), float(screenW), float(screenH)); //printf("Screen area %f: %f, %f", (size.x*size.y*float(screenW)*float(screenH)), float(screenW), float(screenH));
return (size.x*size.y*screenW*screenH) > (64*64F); return (size.x*size.y*screenW*screenH) > decendSSS;
} }

View File

@@ -23,6 +23,7 @@ layout(binding = SCENE_UNIFORM_INDEX, std140) uniform SceneUniform {
uint screenH; uint screenH;
uint requestQueueMaxSize; uint requestQueueMaxSize;
uint renderQueueMaxSize; uint renderQueueMaxSize;
float decendSSS;
}; };
layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue { layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue {
@@ -40,6 +41,11 @@ layout(binding = RENDER_QUEUE_INDEX, std430) restrict buffer RenderQueue {
uint[] renderQueue; uint[] renderQueue;
}; };
layout(binding = NEXT_NODE_QUEUE_INDEX, std430) restrict buffer NextNodeQueue {
uint nextNodeQueueIndex;
uint[] nextNodeQueue;
};
/* /*
layout(binding = 2, std430) restrict buffer QueueData { layout(binding = 2, std430) restrict buffer QueueData {
@@ -78,7 +84,7 @@ layout(binding = 2, std430) restrict buffer QueueData {
void addRequest(inout UnpackedNode node) { void addRequest(inout UnpackedNode node) {
if (!hasRequested(node)) { if (!hasRequested(node)) {
printf("requested"); printf("LOG: Request %d %d %d %d", node.nodeId, node.flags, node.meshPtr, node.childPtr);
//TODO: maybe try using only 1 variable and it being <0 being bad //TODO: maybe try using only 1 variable and it being <0 being bad
if (requestQueueIndex < requestQueueMaxSize) { if (requestQueueIndex < requestQueueMaxSize) {
//Mark node as having a request submitted to prevent duplicate submissions //Mark node as having a request submitted to prevent duplicate submissions
@@ -90,10 +96,16 @@ void addRequest(inout UnpackedNode node) {
void enqueueChildren(in UnpackedNode node) { void enqueueChildren(in UnpackedNode node) {
//printf("children"); //printf("children");
uint children = getChildCount(node);
uint ptr = getChildPtr(node);
uint widx = atomicAdd(nextNodeQueueIndex, children);
for (int i = 0; i < children; i++) {
nextNodeQueue[widx+i] = ptr+i;
}
} }
void enqueueSelfForRender(in UnpackedNode node) { void enqueueSelfForRender(in UnpackedNode node) {
//printf("render"); printf("render %d@[%d,%d,%d]", node.lodLevel, node.pos.x, node.pos.y, node.pos.z);
if (renderQueueIndex < renderQueueMaxSize) { if (renderQueueIndex < renderQueueMaxSize) {
renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node); renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node);
} }
@@ -101,15 +113,18 @@ void enqueueSelfForRender(in UnpackedNode node) {
//TODO: need to add an empty mesh, as a parent node might not have anything to render but the children do?? //TODO: need to add an empty mesh, as a parent node might not have anything to render but the children do??
void main() { void main() {
UnpackedNode node; if (gl_GlobalInvocationID.x>=nodeQueueSize) {
return;
}
UnpackedNode node;
//Setup/unpack the node //Setup/unpack the node
unpackNode(node, nodeQueue[gl_GlobalInvocationID.x]); unpackNode(node, nodeQueue[gl_GlobalInvocationID.x]);
//TODO: check the node is OK first??? maybe? //TODO: check the node is OK first??? maybe?
//Compute screenspace //Compute screenspace
setupScreenspace(node); setupScreenspace(node);
//printf("Node %d@[%d,%d,%d] - %d - %f", node.lodLevel, node.pos.x, node.pos.y, node.pos.z, node.flags, (size.x*size.y*screenW*screenH));
//debugDumpNode(node); //debugDumpNode(node);
@@ -117,14 +132,17 @@ void main() {
//printf("HizCulled"); //printf("HizCulled");
//We are done here, dont do any more, the issue is the shader barriers maybe //We are done here, dont do any more, the issue is the shader barriers maybe
// its culled, maybe just mark it as culled? // its culled, maybe just mark it as culled?
printf("Cull");
} else { } else {
//It is visible, TODO: maybe do a more detailed hiz test? (or make it so that ) //It is visible, TODO: maybe do a more detailed hiz test? (or make it so that )
//Only decend if not a root node //Only decend if not a root node
if (node.lodLevel!=0 && shouldDecend()) { if (node.lodLevel!=0 && shouldDecend()) {
if (hasChildren(node)) { if (hasChildren(node)) {
//printf("A");
enqueueChildren(node); enqueueChildren(node);
} else { } else {
//printf("B");
addRequest(node); addRequest(node);
//TODO: use self mesh (is error state if it doesnt have one since all leaf nodes should have a mesh) //TODO: use self mesh (is error state if it doesnt have one since all leaf nodes should have a mesh)
// Basicly guarenteed to have a mesh, if it doesnt it is very very bad and incorect since its a violation of the graph properties // Basicly guarenteed to have a mesh, if it doesnt it is very very bad and incorect since its a violation of the graph properties
@@ -133,8 +151,10 @@ void main() {
} }
} else { } else {
if (hasMesh(node)) { if (hasMesh(node)) {
//printf("C");
enqueueSelfForRender(node); enqueueSelfForRender(node);
} else { } else {
//printf("D");
//!! not ideal, we want to render this mesh but dont have it. If we havent sent a request //!! not ideal, we want to render this mesh but dont have it. If we havent sent a request
// then send a request for a mesh for this node. // then send a request for a mesh for this node.
addRequest(node); addRequest(node);