incremental sparcial buffer allocation, should prevent the huge lag spike on loading

This commit is contained in:
mcrcortex
2025-09-15 20:50:56 +10:00
parent 6539d67087
commit a6710c3e2e
4 changed files with 25 additions and 4 deletions

View File

@@ -12,6 +12,7 @@ import static org.lwjgl.opengl.GL45C.*;
public class GlBuffer extends TrackedObject { public class GlBuffer extends TrackedObject {
public final int id; public final int id;
private final long size; private final long size;
private final int flags;
private static int COUNT; private static int COUNT;
private static long TOTAL_SIZE; private static long TOTAL_SIZE;
@@ -28,6 +29,7 @@ public class GlBuffer extends TrackedObject {
} }
public GlBuffer(long size, int flags, boolean zero) { public GlBuffer(long size, int flags, boolean zero) {
this.flags = flags;
this.id = glCreateBuffers(); this.id = glCreateBuffers();
this.size = size; this.size = size;
glNamedBufferStorage(this.id, size, flags); glNamedBufferStorage(this.id, size, flags);
@@ -48,6 +50,10 @@ public class GlBuffer extends TrackedObject {
TOTAL_SIZE -= this.size; TOTAL_SIZE -= this.size;
} }
public boolean isSparse() {
return (this.flags&GL_SPARSE_STORAGE_BIT_ARB)!=0;
}
public long size() { public long size() {
return this.size; return this.size;
} }

View File

@@ -18,7 +18,7 @@ import java.util.Arrays;
public class RenderDataFactory { public class RenderDataFactory {
private static final boolean CHECK_NEIGHBOR_FACE_OCCLUSION = true; private static final boolean CHECK_NEIGHBOR_FACE_OCCLUSION = true;
private static final boolean DISABLE_CULL_SAME_OCCLUDES = false; private static final boolean DISABLE_CULL_SAME_OCCLUDES = false;//TODO: FIX TRANSLUCENTS (e.g. stained glass) breaking on chunk boarders with this set to false (it might be something else????)
private static final boolean VERIFY_MESHING = VoxyCommon.isVerificationFlagOn("verifyMeshing"); private static final boolean VERIFY_MESHING = VoxyCommon.isVerificationFlagOn("verifyMeshing");

View File

@@ -513,6 +513,7 @@ public class AsyncNodeManager {
var upload = results.geometryUpload; var upload = results.geometryUpload;
if (!upload.dataUploadPoints.isEmpty()) { if (!upload.dataUploadPoints.isEmpty()) {
((BasicSectionGeometryData)this.geometryData).ensureAccessable(upload.maxElementAccess);
TimingStatistics.A.start(); TimingStatistics.A.start();
int copies = upload.dataUploadPoints.size(); int copies = upload.dataUploadPoints.size();
@@ -848,6 +849,7 @@ public class AsyncNodeManager {
private static class ComputeMemoryCopy { private static class ComputeMemoryCopy {
public int currentElemCopyAmount; public int currentElemCopyAmount;
public int maxElementAccess;
private MemoryBuffer scratchHeaderBuffer = new MemoryBuffer(1<<16); private MemoryBuffer scratchHeaderBuffer = new MemoryBuffer(1<<16);
private MemoryBuffer scratchDataBuffer = new MemoryBuffer(1<<20); private MemoryBuffer scratchDataBuffer = new MemoryBuffer(1<<20);
@@ -899,6 +901,7 @@ public class AsyncNodeManager {
public void upload(int point, MemoryBuffer data) { public void upload(int point, MemoryBuffer data) {
if ((data.size%8)!=0) throw new IllegalStateException("Data must be of size multiple 8"); if ((data.size%8)!=0) throw new IllegalStateException("Data must be of size multiple 8");
int elemSize = (int) (data.size / 8); int elemSize = (int) (data.size / 8);
this.maxElementAccess = Math.max(this.maxElementAccess, point + elemSize);
int header = this.dataUploadPoints.get(point); int header = this.dataUploadPoints.get(point);
if (header != -1) { if (header != -1) {
//If we already have a header location, we just need to reallocate the data //If we already have a header location, we just need to reallocate the data
@@ -973,6 +976,7 @@ public class AsyncNodeManager {
} }
public void reset() { public void reset() {
this.maxElementAccess = 0;
this.currentElemCopyAmount = 0; this.currentElemCopyAmount = 0;
this.dataUploadPoints.clear(); this.dataUploadPoints.clear();
this.arena.reset(); this.arena.reset();

View File

@@ -49,9 +49,6 @@ public class BasicSectionGeometryData implements IGeometryData {
buffer.free(); buffer.free();
} }
buffer = new GlBuffer(geometryCapacity, GL_SPARSE_STORAGE_BIT_ARB); buffer = new GlBuffer(geometryCapacity, GL_SPARSE_STORAGE_BIT_ARB);
glBindBuffer(GL_ARRAY_BUFFER, buffer.id);
glBufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, geometryCapacity, true);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//buffer.zero(); //buffer.zero();
error = glGetError(); error = glGetError();
if (error != GL_NO_ERROR) { if (error != GL_NO_ERROR) {
@@ -67,6 +64,20 @@ public class BasicSectionGeometryData implements IGeometryData {
Logger.info("Successfully allocated the geometry buffer in " + delta + "ms"); Logger.info("Successfully allocated the geometry buffer in " + delta + "ms");
} }
private long sparseCommitment = 0;//Tracks the current range of the allocated sparse buffer
public void ensureAccessable(int maxElementAccess) {
long size = (Integer.toUnsignedLong(maxElementAccess)*8L+65535L)&~65535L;
//If we are a sparse buffer, ensure the memory upto the requested size is allocated
if (this.geometryBuffer.isSparse()) {
if (this.sparseCommitment < size) {//if we try to access memory outside the allocation range, allocate it
glBindBuffer(GL_ARRAY_BUFFER, this.geometryBuffer.id);
glBufferPageCommitmentARB(GL_ARRAY_BUFFER, this.sparseCommitment, size-this.sparseCommitment, true);
glBindBuffer(GL_ARRAY_BUFFER, 0);
this.sparseCommitment = size;
}
}
}
public GlBuffer getGeometryBuffer() { public GlBuffer getGeometryBuffer() {
return this.geometryBuffer; return this.geometryBuffer;
} }