Continue work on adding node cleaner support

This commit is contained in:
mcrcortex
2025-05-15 20:00:46 +10:00
parent c49f5309cd
commit 48799d8ea1
5 changed files with 60 additions and 33 deletions

View File

@@ -195,6 +195,9 @@ public class ChunkBoundRenderer {
private void ensureSize1() {
if (this.chunk2idx.size() < this.idx2chunk.length) return;
//Commit any copies, ensures is synced to new buffer
UploadStream.INSTANCE.commit();
int size = (int) (this.idx2chunk.length*1.5);
Logger.info("Resizing chunk position buffer to: " + size);
//Need to resize

View File

@@ -143,7 +143,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
//Tick download stream
DownloadStream.INSTANCE.tick();
this.nodeManager.tick(this.traversal.getNodeBuffer());
this.nodeManager.tick(this.traversal.getNodeBuffer(), this.nodeCleaner);
//glFlush();
this.nodeCleaner.tick(this.traversal.getNodeBuffer());//Probably do this here??

View File

@@ -75,6 +75,9 @@ public class AsyncNodeManager {
//locals for during iteration
private final IntOpenHashSet tlnIdChange = new IntOpenHashSet();//"Encoded" add/remove id, first bit indicates if its add or remove, 1 is add
//Top bit indicates clear or reset
private final IntOpenHashSet cleanerIdResetClear = new IntOpenHashSet();//Tells the cleaner if it needs to clear the id to 0, or reset the id to the current frame
private boolean needsWaitForSync = false;
public AsyncNodeManager(int maxNodeCount, ISectionWatcher watcher, IGeometryData geometryData) {
@@ -98,20 +101,23 @@ public class AsyncNodeManager {
this.geometryManager = new BasicAsyncGeometryManager(((BasicSectionGeometryData)geometryData).getMaxSectionCount(), ((BasicSectionGeometryData)geometryData).getGeometryCapacity());
this.manager = new NodeManager(maxNodeCount, this.geometryManager, watcher);
//Dont do the move... is just to much effort
this.manager.setClear(new NodeManager.ICleaner() {
@Override
public void alloc(int id) {
AsyncNodeManager.this.cleanerIdResetClear.remove(id);//Remove clear
AsyncNodeManager.this.cleanerIdResetClear.add(id|(1<<31));//Add reset
}
@Override
public void move(int from, int to) {
//noop (sorry :( will cause some perf loss/incorrect cleaning )
}
@Override
public void free(int id) {
AsyncNodeManager.this.cleanerIdResetClear.remove(id|(1<<31));//Remove reset
AsyncNodeManager.this.cleanerIdResetClear.add(id);//Add clear
}
});
this.manager.setTLNCallbacks(id->{
@@ -353,6 +359,7 @@ public class AsyncNodeManager {
results.geometryUploads.putAll(this.geometryManager.getUploads());
this.geometryManager.getUploads().clear();//Put in new data into sync set
this.geometryManager.getHeapRemovals().clear();//We dont do removals on new data (as there is "none")
results.cleanerOperations.addAll(this.cleanerIdResetClear); this.cleanerIdResetClear.clear();
} else {
results = prev;
// merge with the previous result set
@@ -368,6 +375,16 @@ public class AsyncNodeManager {
this.tlnIdChange.clear();
}
if (!this.cleanerIdResetClear.isEmpty()) {//Merge top level node id changes
var iter = this.cleanerIdResetClear.intIterator();
while (iter.hasNext()) {
int val = iter.nextInt();
results.cleanerOperations.remove(val^(1<<31));//Remove opposite
results.cleanerOperations.add(val);//Add this
}
this.cleanerIdResetClear.clear();
}
if (!this.geometryManager.getHeapRemovals().isEmpty()) {//Remove and free all the removed geometry uploads
var rem = this.geometryManager.getHeapRemovals();
var iter = rem.intIterator();
@@ -440,7 +457,7 @@ public class AsyncNodeManager {
private IntConsumer tlnAddCallback; private IntConsumer tlnRemoveCallback;
//Render thread synchronization
public void tick(GlBuffer nodeBuffer) {//TODO: dont pass nodeBuffer here??, do something else thats better
public void tick(GlBuffer nodeBuffer, NodeCleaner cleaner) {//TODO: dont pass nodeBuffer here??, do something else thats better
var results = (SyncResults)RESULT_HANDLE.getAndSet(this, null);//Acquire the results
if (results == null) {//There are no new results to process, return
return;
@@ -498,6 +515,12 @@ public class AsyncNodeManager {
glMemoryBarrier(GL_UNIFORM_BARRIER_BIT|GL_SHADER_STORAGE_BARRIER_BIT);
}
if (!results.cleanerOperations.isEmpty()) {
cleaner.updateIds(results.cleanerOperations);
}
this.currentMaxNodeId = results.currentMaxNodeId;
//Insert the result set into the cache
if (!RESULT_CACHE_1_HANDLE.compareAndSet(this, null, results)) {
//Failed to insert into result set 1, insert it into result set 2
@@ -513,6 +536,11 @@ public class AsyncNodeManager {
this.tlnRemoveCallback = remove;
}
private int currentMaxNodeId = 0;
public int getCurrentMaxNodeId() {
return this.currentMaxNodeId;
}
//==================================================================================================================
//Incoming events
@@ -679,11 +707,15 @@ public class AsyncNodeManager {
private MemoryBuffer scatterWriteBuffer = new MemoryBuffer(8192*2);
private final Int2IntOpenHashMap scatterWriteLocationMap = new Int2IntOpenHashMap(1024);
//Cleaner operations
private final IntOpenHashSet cleanerOperations = new IntOpenHashSet();
public SyncResults() {
this.scatterWriteLocationMap.defaultReturnValue(-1);
}
public void reset() {
this.cleanerOperations.clear();
this.scatterWriteLocationMap.clear();
this.currentMaxNodeId = 0;
this.tlnDelta.clear();

View File

@@ -32,9 +32,6 @@ public class NodeCleaner {
static final int OUTPUT_COUNT = 256;
private static final int BATCH_SET_SIZE = 2048;
private final AutoBindingShader sorter = Shader.makeAuto(PrintfDebugUtil.PRINTF_processor)
.define("WORK_SIZE", SORTING_WORKER_SIZE)
.define("ELEMS_PER_THREAD", WORK_PER_THREAD)
@@ -63,10 +60,6 @@ public class NodeCleaner {
final GlBuffer visibilityBuffer;
private final GlBuffer outputBuffer = new GlBuffer(OUTPUT_COUNT*4+OUTPUT_COUNT*8);//Scratch + output
private final GlBuffer scratchBuffer = new GlBuffer(BATCH_SET_SIZE*4);//Scratch buffer for setting ids with
private final IntOpenHashSet allocIds = new IntOpenHashSet();
private final IntOpenHashSet freeIds = new IntOpenHashSet();
private final AsyncNodeManager nodeManager;
int visibilityId = 0;
@@ -78,8 +71,7 @@ public class NodeCleaner {
this.visibilityBuffer.fill(-1);
this.batchClear
.ssbo("VISIBILITY_BUFFER_BINDING", this.visibilityBuffer)
.ssbo("LIST_BUFFER_BINDING", this.scratchBuffer);
.ssbo("VISIBILITY_BUFFER_BINDING", this.visibilityBuffer);
this.sorter
.ssbo("VISIBILITY_BUFFER_BINDING", this.visibilityBuffer)
@@ -111,10 +103,6 @@ public class NodeCleaner {
public void tick(GlBuffer nodeDataBuffer) {
this.visibilityId++;
this.setIds(this.allocIds, this.visibilityId);
this.setIds(this.freeIds, -1);
if (this.shouldCleanGeometry()) {
this.outputBuffer.fill(this.nodeManager.maxNodeCount - 2);//TODO: maybe dont set to zero??
@@ -124,7 +112,7 @@ public class NodeCleaner {
//TODO: choose whether this is in nodeSpace or section/geometryId space
//
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
//glDispatchCompute((this.nodeManager.getCurrentMaxNodeId() + (SORTING_WORKER_SIZE+WORK_PER_THREAD) - 1) / (SORTING_WORKER_SIZE+WORK_PER_THREAD), 1, 1);
glDispatchCompute((this.nodeManager.getCurrentMaxNodeId() + (SORTING_WORKER_SIZE+WORK_PER_THREAD) - 1) / (SORTING_WORKER_SIZE+WORK_PER_THREAD), 1, 1);
this.resultTransformer.bind();
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, this.outputBuffer.id, 0, 4 * OUTPUT_COUNT);
@@ -151,22 +139,26 @@ public class NodeCleaner {
return false;//return 3<((double)this.nodeManager.getGeometryManager().getUsedCapacity())/((double)this.nodeManager.getGeometryManager().getRemainingCapacity());
}
private void setIds(IntOpenHashSet collection, int setTo) {
public void updateIds(IntOpenHashSet collection) {
if (!collection.isEmpty()) {
this.batchClear.bind();
int count = collection.size();
long addr = UploadStream.INSTANCE.rawUploadAddress(count * 4 + 16);//TODO ensure alignment, create method todo alignment things
addr = (addr+15)&~15L;//Align to 16 bytes
long ptr = UploadStream.INSTANCE.getBaseAddress() + addr;
var iter = collection.iterator();
while (iter.hasNext()) {
int cnt = Math.min(collection.size(), BATCH_SET_SIZE);
long ptr = UploadStream.INSTANCE.upload(this.scratchBuffer, 0, cnt * 4L);
for (int i = 0; i < cnt; i++) {
MemoryUtil.memPutInt(ptr + i * 4, iter.nextInt());
iter.remove();
MemoryUtil.memPutInt(ptr, iter.nextInt()); ptr+=4;
}
UploadStream.INSTANCE.commit();
glUniform1ui(0, cnt);
glUniform1ui(1, setTo);
glDispatchCompute((cnt+127)/128, 1, 1);
}
this.batchClear.bind();
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, UploadStream.INSTANCE.getRawBufferId(), addr, count*4L);
glUniform1ui(0, count);
glUniform1ui(1, this.visibilityId);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glDispatchCompute((count+127)/128, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
}
}
@@ -174,7 +166,6 @@ public class NodeCleaner {
this.sorter.free();
this.visibilityBuffer.free();
this.outputBuffer.free();
this.scratchBuffer.free();
this.batchClear.free();
this.resultTransformer.free();
}

View File

@@ -17,5 +17,6 @@ void main() {
if (count <= id) {
return;
}
visiblity[ids[id]] = setTo;
uint pos = ids[id];
visiblity[pos&((1u<<31)-1)] = mix(setTo, uint(-1), (pos&(1u<<31)) == 0);
}