Added sub buffers. Greatly reducing fps stutters

This commit is contained in:
tom lee
2022-01-20 22:53:17 +08:00
parent dc0e48ae2a
commit 14e72c68cb
@@ -117,6 +117,7 @@ public class LodBufferBuilderFactory
* when need be to fit the larger sizes.
*/
public static final int DEFAULT_MEMORY_ALLOCATION = 1024;
public static final int MAX_TRIANGLES_PER_BUFFER = (1024*1024*2) / (LodUtil.LOD_VERTEX_FORMAT.getByteSize()*3);
@@ -133,7 +134,7 @@ public class LodBufferBuilderFactory
/** Stores the vertices when building the VBOs */
// FIXME: Use special warparound type of movable grid list in the future
public volatile MovableGridList<LodBufferBuilder[]> buildableBuffers;
public volatile MovableGridList<LodBufferBuilder> buildableBuffers;
/** Used when building new VBOs */
public volatile MovableGridList<LodVertexBuffer[]> buildableVbos;
@@ -264,7 +265,7 @@ public class LodBufferBuilderFactory
if (fullRegen || tooFar || buildableBuffers==null || buildableVbos==null
|| setsToRender==null || vertexOptimizerCache==null) {
renderRange = lodDim.getWidth()/2; //get lodDim half width
buildableBuffers = new MovableGridList<LodBufferBuilder[]>(renderRange, playerRegionX, playerRegionZ);
buildableBuffers = new MovableGridList<LodBufferBuilder>(renderRange, playerRegionX, playerRegionZ);
buildableVbos = new MovableGridList<LodVertexBuffer[]>(renderRange, playerRegionX, playerRegionZ);
setsToRender = new MovableGridList<PosToRenderContainer>(renderRange, playerRegionX, playerRegionZ);
vertexOptimizerCache = new MovableGridList<VertexOptimizer>(renderRange, playerRegionX, playerRegionZ);
@@ -318,23 +319,13 @@ public class LodBufferBuilderFactory
RegionPos regionPos = new RegionPos(regionX, regionZ);
posToUpload.add(regionPos);
LodBufferBuilder[] builder = buildableBuffers.get(regionX, regionZ);
LodVertexBuffer[] vbo = buildableVbos.get(regionX, regionZ);
if (vbo == null) {
setupBuffers(regionX, regionZ);
vbo = buildableVbos.get(regionX, regionZ);
}
LodBufferBuilder builder = buildableBuffers.get(regionX, regionZ);
if (builder == null) {
builder = buildableBuffers.setAndGet(regionX, regionZ, new LodBufferBuilder[vbo.length]);
}
for (int i=0; i<builder.length; i++) {
if (builder[i] == null)
builder[i] = new LodBufferBuilder(DEFAULT_MEMORY_ALLOCATION);
else {
builder[i].discard();
}
builder[i].begin(GL32.GL_QUADS, LodUtil.LOD_VERTEX_FORMAT);
builder = buildableBuffers.setAndGet(regionX, regionZ, new LodBufferBuilder(DEFAULT_MEMORY_ALLOCATION));
} else {
builder.discard();
}
builder.begin(GL32.GL_QUADS, LodUtil.LOD_VERTEX_FORMAT);
byte minDetail = region.getMinDetailLevel();
final int pX = playerX;
final int pZ = playerZ;
@@ -384,15 +375,13 @@ public class LodBufferBuilderFactory
long startUploadTime = System.currentTimeMillis();
// clean up any potentially open resources
for (RegionPos regPos : posToUpload) {
LodBufferBuilder[] buffers = buildableBuffers.get(regPos.x, regPos.z);
if (buffers == null) continue;
for (LodBufferBuilder buffer : buffers) {
try {
buffer.end();
} catch (Exception e) {
ClientApi.LOGGER.error("\"LodNodeBufferBuilder\" was unable to close buildable buffer: " + e.getMessage());
e.printStackTrace();
}
LodBufferBuilder buffer = buildableBuffers.get(regPos.x, regPos.z);
if (buffer == null) continue;
try {
buffer.end();
} catch (Exception e) {
ClientApi.LOGGER.error("\"LodNodeBufferBuilder\" was unable to close buildable buffer: " + e.getMessage());
e.printStackTrace();
}
}
@@ -434,7 +423,7 @@ public class LodBufferBuilderFactory
DebugMode debugMode = CONFIG.client().advanced().debugging().getDebugMode();
VertexOptimizer vertexOptimizer = ThreadMapUtil.getBox();
boolean[] adjShadeDisabled = ThreadMapUtil.getAdjShadeDisabledArray();
LodBufferBuilder[] currentBuffers = buildableBuffers.get(regPos.x, regPos.z);
LodBufferBuilder currentBuffer = buildableBuffers.get(regPos.x, regPos.z);
// determine how many LODs we can stack vertically
int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0);
@@ -453,7 +442,7 @@ public class LodBufferBuilderFactory
for (int index = 0; index < posToRender.getNumberOfPos(); index++)
{
int bufferIndex = index % currentBuffers.length;
int bufferIndex = index;
byte detailLevel = posToRender.getNthDetailLevel(index);
int posX = posToRender.getNthPosX(index);
int posZ = posToRender.getNthPosZ(index);
@@ -550,7 +539,7 @@ public class LodBufferBuilderFactory
break;
//We send the call to create the vertices
CubicLodTemplate.addLodToBuffer(currentBuffers[bufferIndex], vboX, vboZ, data, adjData,
CubicLodTemplate.addLodToBuffer(currentBuffer, vboX, vboZ, data, adjData,
detailLevel, posX, posZ, vertexOptimizer, debugMode, adjShadeDisabled, cullingRangeX, cullingRangeZ);
}
@@ -590,7 +579,8 @@ public class LodBufferBuilderFactory
* <p>
* May have to wait for the bufferLock to open.
*/
private void setupBuffers(int regionX, int regionZ) {
private void setupBuffersTOBEREMOVED(int regionX, int regionZ) {
//TODO: Impl actual multibuffers
//int regionMemoryRequired = DEFAULT_MEMORY_ALLOCATION;
//int numberOfBuffers;
@@ -608,6 +598,7 @@ public class LodBufferBuilderFactory
} else {
numberOfBuffers = 1;
}*/
vbos = buildableVbos.setAndGet(regionX, regionZ, new LodVertexBuffer[1]);
}
@@ -668,34 +659,68 @@ public class LodBufferBuilderFactory
long BPerNS = CONFIG.client().advanced().buffers().getGpuUploadPerMegabyteInMilliseconds(); // MB -> B = 1/1,000,000. MS -> NS = 1,000,000. So, MBPerMS = BPerNS.
long remainingNS = 0; // We don't want to pause for like 0.1 ms... so we store those tiny MS.
long bytesUploaded = 0;
long totalBuffers = 0;
// actually upload the buffers
for (RegionPos p : toBeUploaded) {
LodBufferBuilder[] buffers = buildableBuffers.get(p.x, p.z);
for (int i = 0; i < buffers.length; i++)
{
ByteBuffer uploadBuffer = null;
//FIXME: The sonme Buffers aren't closed/end() and causing errors!
try {
LagSpikeCatcher b = new LagSpikeCatcher();
uploadBuffer = buffers[i].getCleanedByteBuffer();
b.end("getCleanedByteBuffer");
} catch (IndexOutOfBoundsException e) {
// NOTE: Temp try/catch for above FIXME.
e.printStackTrace();
} catch (RuntimeException e) {
ClientApi.LOGGER.error(LodBufferBuilderFactory.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage());
e.printStackTrace();
}
if (uploadBuffer == null) continue;
LagSpikeCatcher vboU = new LagSpikeCatcher();
vboUpload(p, i, uploadBuffer, uploadMethod);
vboU.end("vboUpload");
LodBufferBuilder buffer = buildableBuffers.get(p.x, p.z);
ByteBuffer uploadBuffer = null;
//FIXME: The sonme Buffers aren't closed/end() and causing errors!
try {
LagSpikeCatcher b = new LagSpikeCatcher();
uploadBuffer = buffer.getCleanedByteBuffer();
b.end("getCleanedByteBuffer");
} catch (IndexOutOfBoundsException e) {
// NOTE: Temp try/catch for above FIXME.
e.printStackTrace();
} catch (RuntimeException e) {
ClientApi.LOGGER.error(LodBufferBuilderFactory.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage());
e.printStackTrace();
}
if (uploadBuffer == null) continue;
int maxLength = MAX_TRIANGLES_PER_BUFFER*(LodUtil.LOD_VERTEX_FORMAT.getByteSize()*3);
LagSpikeCatcher vboSetup = new LagSpikeCatcher();
LodVertexBuffer[] vbos = buildableVbos.get(p.x, p.z);
int requiredFullBuffers = Math.floorDiv(uploadBuffer.capacity(),maxLength);
int additionalBuffer = Math.floorMod(uploadBuffer.capacity(),maxLength);
if (vbos == null) {
vbos = new LodVertexBuffer[requiredFullBuffers+1];
buildableVbos.set(p.x, p.z, vbos);
} else if (vbos.length != requiredFullBuffers+1) {
LodVertexBuffer[] newVbos = new LodVertexBuffer[requiredFullBuffers+1];
if (vbos.length > requiredFullBuffers+1) {
for (int i=requiredFullBuffers+1; i<vbos.length; i++) {
vbos[i].close();
vbos[i] = null;
}
}
for (int i=0; i<newVbos.length && i<vbos.length; i++) {
newVbos[i] = vbos[i];
}
buildableVbos.set(p.x, p.z, newVbos);
vbos = newVbos;
}
vboSetup.end("vboSetup");
for (int i=0; i<=requiredFullBuffers; i++) {
ByteBuffer subBuffer;
if (i==requiredFullBuffers) {
subBuffer = uploadBuffer.slice(i*maxLength, additionalBuffer);
} else {
subBuffer = uploadBuffer.slice(i*maxLength, maxLength);
}
LagSpikeCatcher vboU = new LagSpikeCatcher();
vboUpload(p, i, subBuffer, uploadMethod);
vboU.end("vboUpload");
// upload buffers over an extended period of time
// to hopefully prevent stuttering.
remainingNS += uploadBuffer.capacity()*BPerNS;
bytesUploaded += uploadBuffer.capacity();
remainingNS += subBuffer.capacity()*BPerNS;
bytesUploaded += subBuffer.capacity();
if (remainingNS >= TimeUnit.NANOSECONDS.convert(1000/60, TimeUnit.MILLISECONDS)) {
if (remainingNS > MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS) remainingNS = MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS;
try {
@@ -704,8 +729,10 @@ public class LodBufferBuilderFactory
remainingNS = 0;
}
}
totalBuffers += (requiredFullBuffers+1);
ClientApi.LOGGER.info("Uploaded {} sub buffers for {}", (requiredFullBuffers+1), p);
}
ClientApi.LOGGER.info("UploadBuffers uploaded "+bytesUploaded+" bytes.");
ClientApi.LOGGER.info("UploadBuffers uploaded "+bytesUploaded+" bytes, with {} sub buffers", totalBuffers);
}
/** Uploads the uploadBuffer so the GPU can use it. */