diff --git a/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java index 0160ca30e..2878e6f73 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java @@ -62,7 +62,7 @@ import net.minecraft.util.math.ChunkPos; * This object is used to create NearFarBuffer objects. * * @author James Seibel - * @version 10-7-2021 + * @version 10-9-2021 */ public class LodBufferBuilder { @@ -71,6 +71,13 @@ public class LodBufferBuilder /** The threads used to generate buffers. */ public static ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new ThreadFactoryBuilder().setNameFormat("Buffer-Builder-%d").build()); + /** + * When uploading to a buffer that is too small, + * recreate it this many times bigger than the upload payload + */ + public static final double BUFFER_EXPANSION_MULTIPLIER = 1.5; + + /** This boolean matrix indicate the buffer builder in that position has to be regenerated */ public volatile boolean[][] regenPos; @@ -88,6 +95,14 @@ public class LodBufferBuilder /** The OpenGL IDs of the storage buffers used by the drawableVbos */ public int[][] drawableStorageBufferIds; + /** used to debug how the buildableStorageBuffers are growing */ + public int[][] bufferPreviousCapacity; + /** + * This is toggled when the buffers are swapped so we only + * display content related to one set of buffers + */ + public boolean printExpansionLog = true; + /** Used when building new VBOs */ public volatile VertexBuffer[][][] buildableVbos; /** VBOs that are sent over to the LodNodeRenderer */ @@ -450,7 +465,7 @@ public class LodBufferBuilder if (regionMemoryRequired > LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY) { numberOfBuffers = (int) Math.ceil(regionMemoryRequired / LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY) + 1; - regionMemoryRequired = LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY; // TODO this should be determined with regionMemoryRequired? + regionMemoryRequired = LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY; // TODO should this be determined with regionMemoryRequired? bufferSize[x][z] = numberOfBuffers; buildableBuffers[x][z] = new BufferBuilder[numberOfBuffers]; buildableVbos[x][z] = new VertexBuffer[numberOfBuffers]; @@ -490,13 +505,12 @@ public class LodBufferBuilder buildableStorageBufferIds[x][z] = GL45.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z]); - // TODO get a better max size, BufferStorage's can't be resized after they are created - GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY, 0); // the 0 flag means to create the storage in the GPU's memory + GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); // the 0 flag means to create the storage in the GPU's memory GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); drawableStorageBufferIds[x][z] = GL45.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableStorageBufferIds[x][z]); - GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY, 0); + GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } } @@ -505,8 +519,6 @@ public class LodBufferBuilder bufferLock.unlock(); } - public int[][] bufferPreviousCapacity; - /** * Sets the buffers and Vbos to null, forcing them to be recreated
* and destroys any bound OpenGL objects.

@@ -649,7 +661,7 @@ public class LodBufferBuilder for (int i = 0; i < buildableBuffers[x][z].length; i++) { ByteBuffer builderBuffer = buildableBuffers[x][z][i].popNextBuffer().getSecond(); - vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z], builderBuffer, x,z); + vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z], builderBuffer, x,z, true); lodDim.setRegenRegionBufferByArrayIndex(x, z, false); } } @@ -673,7 +685,7 @@ public class LodBufferBuilder /** Uploads the uploadBuffer into the VBO and then into GPU memory. */ private void vboUpload(VertexBuffer vbo, int storageBufferId, ByteBuffer uploadBuffer, - int xVboIndex, int zVboIndex) + int xVboIndex, int zVboIndex, boolean allowBufferExpansion) // x/zVboIndex are just used for the debugging console logging // and should be removed when the logger is removed. { @@ -693,25 +705,42 @@ public class LodBufferBuilder { int previousCapacity = uploadBuffer.capacity(); - // only change the system buffer if the uploadBuffer actually - // has something in it - if (previousCapacity != 0) + // only expand the buffers if the uploadBuffer actually + // has something in it and expansion is allowed + if (previousCapacity != 0 && allowBufferExpansion) { - // the buffer in system memory isn't big enough, - // expand it so next time hopefully it will be big enough. + // the buffer(s) aren't big enough, expand them. // This does cause lag/stuttering so it should be avoided! - GL45.glBufferData(GL45.GL_ARRAY_BUFFER, uploadBuffer.capacity() * 4, GL45.GL_DYNAMIC_DRAW); + + // expand the buffer in system memory + GL45.glBufferData(GL45.GL_ARRAY_BUFFER, (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER), GL45.GL_DYNAMIC_DRAW); GL45.glBufferSubData(GL45.GL_ARRAY_BUFFER, 0, uploadBuffer); - // NOTE: this will display twice because we are double buffering - // (using 1 buffer to generate into and one to draw) - ClientProxy.LOGGER.info("vbo (" + xVboIndex + "," + zVboIndex + ") expanded: " + bufferPreviousCapacity[xVboIndex][zVboIndex] + " -> " + (previousCapacity * 4)); + // un-bind the system memory buffer + GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); - // could be used if you wanted to create a CSV file - //ClientProxy.LOGGER.info(xVboIndex + "," + zVboIndex + "," + bufferPreviousCapacity[xVboIndex][zVboIndex] + "," + uploadBuffer.capacity()); + // expand the buffer storage + GL45.glDeleteBuffers(storageBufferId); + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, storageBufferId); + GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER), 0); + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); - bufferPreviousCapacity[xVboIndex][zVboIndex] = uploadBuffer.capacity() * 4; + // recursively try to upload into the newly created buffer storage + // but don't recurse again if that fails + // (we don't want an infinitely expanding buffer!) + vboUpload(vbo, storageBufferId, uploadBuffer, xVboIndex, zVboIndex, false); + + + + if (printExpansionLog) + { + // NOTE: this will display twice because we are double buffering + // (using 1 buffer to generate into and one to draw) + ClientProxy.LOGGER.info("vbo (" + xVboIndex + "," + zVboIndex + ") expanded: " + bufferPreviousCapacity[xVboIndex][zVboIndex] + " -> " + (int)(uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER)); + bufferPreviousCapacity[xVboIndex][zVboIndex] = (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER); + } } } else @@ -753,6 +782,9 @@ public class LodBufferBuilder drawableStorageBufferIds = buildableStorageBufferIds; buildableStorageBufferIds = tmpStorage; + // we only want to print the exapnsion log for + // one set of buffers, not both + printExpansionLog = !printExpansionLog; drawableCenterChunkPos = buildableCenterChunkPos;