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 2878e6f73..b45c0e1dc 100644 --- a/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/bufferBuilding/LodBufferBuilder.java @@ -84,22 +84,27 @@ public class LodBufferBuilder /** This boolean indicates that ever buffer need to be regenerated */ public volatile boolean fullRegeneration = false; - /** the capacity of each buffer in bytes */ - public volatile int[][] bufferSize; + /** + * How many buffers there are for the given region.
+ * This is done because some regions may require more memory than + * can be directly allocated, so we split the regions into smaller sections.
+ * This keeps track of those sections. + */ + public volatile int[][] numberOfBuffersPerRegion; - /** Used when building the vbos */ + /** Stores the vertices when building the VBOs */ public volatile BufferBuilder[][][] buildableBuffers; /** The OpenGL IDs of the storage buffers used by the buildableVbos */ - public int[][] buildableStorageBufferIds; + public int[][][] buildableStorageBufferIds; /** The OpenGL IDs of the storage buffers used by the drawableVbos */ - public int[][] drawableStorageBufferIds; + public int[][][] drawableStorageBufferIds; /** used to debug how the buildableStorageBuffers are growing */ - public int[][] bufferPreviousCapacity; + public int[][][] bufferPreviousCapacity; /** * This is toggled when the buffers are swapped so we only - * display content related to one set of buffers + * display the expansion log for one set of buffers */ public boolean printExpansionLog = true; @@ -444,16 +449,16 @@ public class LodBufferBuilder int numberOfBuffers; previousRegionWidth = numbRegionsWide; - bufferSize = new int[numbRegionsWide][numbRegionsWide]; + numberOfBuffersPerRegion = new int[numbRegionsWide][numbRegionsWide]; buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide][]; buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide][]; drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide][]; - buildableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide]; - drawableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide]; + buildableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][]; + drawableStorageBufferIds = new int[numbRegionsWide][numbRegionsWide][]; - bufferPreviousCapacity = new int[numbRegionsWide][numbRegionsWide]; + bufferPreviousCapacity = new int[numbRegionsWide][numbRegionsWide][]; for (int x = 0; x < numbRegionsWide; x++) { @@ -461,29 +466,41 @@ public class LodBufferBuilder { regionMemoryRequired = LodUtil.calculateMaximumRegionGpuMemoryUse(x, z, LodConfig.CLIENT.graphics.lodTemplate.get()); - // if the memory required is greater than the max buffer capacity divide the memory across multiple buffers + // if the memory required is greater than the max buffer + // capacity, divide the memory across multiple buffers 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 should this be determined with regionMemoryRequired? - bufferSize[x][z] = numberOfBuffers; + + // TODO shouldn't this be determined with regionMemoryRequired? + // always allocating the max memory is a bit expensive isn't it? + regionMemoryRequired = LodUtil.MAX_ALOCATEABLE_DIRECT_MEMORY; + numberOfBuffersPerRegion[x][z] = numberOfBuffers; buildableBuffers[x][z] = new BufferBuilder[numberOfBuffers]; buildableVbos[x][z] = new VertexBuffer[numberOfBuffers]; drawableVbos[x][z] = new VertexBuffer[numberOfBuffers]; + + buildableStorageBufferIds[x][z] = new int[numberOfBuffers]; + drawableStorageBufferIds[x][z] = new int[numberOfBuffers]; + bufferPreviousCapacity[x][z] = new int[numberOfBuffers]; } else { // we only need one buffer for this region - bufferSize[x][z] = 1; + numberOfBuffersPerRegion[x][z] = 1; buildableBuffers[x][z] = new BufferBuilder[1]; buildableVbos[x][z] = new VertexBuffer[1]; drawableVbos[x][z] = new VertexBuffer[1]; + + buildableStorageBufferIds[x][z] = new int[1]; + drawableStorageBufferIds[x][z] = new int[1]; + bufferPreviousCapacity[x][z] = new int[1]; } - for (int i = 0; i < bufferSize[x][z]; i++) + for (int i = 0; i < numberOfBuffersPerRegion[x][z]; i++) { - bufferPreviousCapacity[x][z] = (int) regionMemoryRequired; + bufferPreviousCapacity[x][z][i] = (int) regionMemoryRequired; buildableBuffers[x][z][i] = new BufferBuilder((int) regionMemoryRequired); @@ -503,13 +520,13 @@ public class LodBufferBuilder // create the buffer storage (GPU memory) - buildableStorageBufferIds[x][z] = GL45.glGenBuffers(); - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z]); + buildableStorageBufferIds[x][z][i] = GL45.glGenBuffers(); + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z][i]); 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]); + drawableStorageBufferIds[x][z][i] = GL45.glGenBuffers(); + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableStorageBufferIds[x][z][i]); GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } @@ -533,21 +550,24 @@ public class LodBufferBuilder // destroy the buffer storages if they aren't already if (buildableStorageBufferIds != null) { - for (int i = 0; i < buildableStorageBufferIds.length; i++) + for (int x = 0; x < buildableStorageBufferIds.length; x++) { - for (int j = 0; j < buildableStorageBufferIds.length; j++) + for (int z = 0; z < buildableStorageBufferIds.length; z++) { - int buildableId = buildableStorageBufferIds[i][j]; - int drawableId = drawableStorageBufferIds[i][j]; - - // Send this over to the render thread, if this is being - // called we aren't worried about stuttering anyway. - // This way we don't have to worry about what context this - // was called from (if any). - RenderSystem.recordRenderCall(() -> { - GL45.glDeleteBuffers(buildableId); - GL45.glDeleteBuffers(drawableId); - }); + for (int i = 0; i < buildableStorageBufferIds[x][z].length; i++) + { + int buildableId = buildableStorageBufferIds[x][z][i]; + int drawableId = drawableStorageBufferIds[x][z][i]; + + // Send this over to the render thread, if this is being + // called we aren't worried about stuttering anyway. + // This way we don't have to worry about what context this + // was called from (if any). + RenderSystem.recordRenderCall(() -> { + GL45.glDeleteBuffers(buildableId); + GL45.glDeleteBuffers(drawableId); + }); + } } } } @@ -661,7 +681,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, true); + vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z][i], builderBuffer, x,z,i, true); lodDim.setRegenRegionBufferByArrayIndex(x, z, false); } } @@ -685,7 +705,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, boolean allowBufferExpansion) + int xVboIndex, int zVboIndex, int iVboIndex, boolean allowBufferExpansion) // x/zVboIndex are just used for the debugging console logging // and should be removed when the logger is removed. { @@ -693,7 +713,7 @@ public class LodBufferBuilder if (vbo.id != -1 && GlProxy.getInstance().getGlContext() == GlProxyContext.LOD_BUILDER) { // this is how many points will be rendered - vbo.vertexCount = (uploadBuffer.remaining() / vbo.format.getVertexSize()); + vbo.vertexCount = (uploadBuffer.capacity() / vbo.format.getVertexSize()); GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, vbo.id); @@ -730,7 +750,7 @@ public class LodBufferBuilder // 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); + vboUpload(vbo, storageBufferId, uploadBuffer, xVboIndex, zVboIndex, iVboIndex, false); @@ -738,19 +758,20 @@ public class LodBufferBuilder { // 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); + ClientProxy.LOGGER.info("vbo (" + xVboIndex + "," + zVboIndex + ") expanded: " + bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] + " -> " + (int)(uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER)); + bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] = (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER); } } } else { // upload the buffer into system memory... - vboBuffer.put(uploadBuffer); + vboBuffer.put(uploadBuffer); GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); // ...then upload into GPU memory - // (uploading into GPU memory can only be done through ) + // (uploading into GPU memory directly can only be done + // through the glCopyBufferSubData/glCopyNamed... methods) GL45.glCopyNamedBufferSubData(vbo.id, storageBufferId, 0, 0, uploadBuffer.capacity()); } } @@ -761,7 +782,7 @@ public class LodBufferBuilder } finally { - GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } } @@ -778,7 +799,7 @@ public class LodBufferBuilder drawableVbos = buildableVbos; buildableVbos = tmpVbo; - int[][] tmpStorage = drawableStorageBufferIds; + int[][][] tmpStorage = drawableStorageBufferIds; drawableStorageBufferIds = buildableStorageBufferIds; buildableStorageBufferIds = tmpStorage; @@ -800,10 +821,10 @@ public class LodBufferBuilder public class VertexBuffersAndOffset { public VertexBuffer[][][] vbos; - public int[][] storageBufferIds; + public int[][][] storageBufferIds; public ChunkPos drawableCenterChunkPos; - public VertexBuffersAndOffset(VertexBuffer[][][] newVbos, int[][] newStorageBufferIds, ChunkPos newDrawableCenterChunkPos) + public VertexBuffersAndOffset(VertexBuffer[][][] newVbos, int[][][] newStorageBufferIds, ChunkPos newDrawableCenterChunkPos) { vbos = newVbos; storageBufferIds = newStorageBufferIds; diff --git a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java index e6d9b1e59..b0ca2a457 100644 --- a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java @@ -18,6 +18,14 @@ package com.seibel.lod.builders.lodBuilding; +import java.awt.Color; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import com.seibel.lod.config.LodConfig; import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.enums.HorizontalResolution; @@ -25,9 +33,26 @@ import com.seibel.lod.enums.VerticalQuality; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.LodRegion; import com.seibel.lod.objects.LodWorld; -import com.seibel.lod.util.*; +import com.seibel.lod.util.ColorUtil; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.DetailDistanceUtil; +import com.seibel.lod.util.LevelPosUtil; +import com.seibel.lod.util.LodThreadFactory; +import com.seibel.lod.util.LodUtil; +import com.seibel.lod.util.ThreadMapUtil; import com.seibel.lod.wrappers.MinecraftWrapper; -import net.minecraft.block.*; + +import net.minecraft.block.AbstractPlantBlock; +import net.minecraft.block.AbstractTopPlantBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.BushBlock; +import net.minecraft.block.FlowerBlock; +import net.minecraft.block.GrassBlock; +import net.minecraft.block.IGrowable; +import net.minecraft.block.LeavesBlock; +import net.minecraft.block.TallGrassBlock; import net.minecraft.block.material.MaterialColor; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -47,21 +72,13 @@ import net.minecraft.world.chunk.IChunk; import net.minecraft.world.gen.Heightmap; import net.minecraftforge.client.model.data.ModelDataMap; -import java.awt.*; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - /** * This object is in charge of creating Lod related objects. (specifically: Lod * World, Dimension, and Region objects) * * @author Leonardo Amato * @author James Seibel - * @version 9-25-2021 + * @version 10-9-2021 */ public class LodBuilder { @@ -91,8 +108,11 @@ public class LodBuilder /** TODO is this needed / used? */ public static final boolean avoidSmallBlock = false; - /** How wide LodDimensions should be in regions */ - public int defaultDimensionWidthInRegions = 5; + /** + * How wide LodDimensions should be in regions
+ * Is automatically set before the first frame in ClientProxy. + */ + public int defaultDimensionWidthInRegions = 0; diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index 8ba1b9ab2..3c25a1832 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -63,7 +63,7 @@ import net.minecraft.util.math.vector.Vector3d; * This is where LODs are draw to the world. * * @author James Seibel - * @version 10-7-2021 + * @version 10-9-2021 */ public class LodRenderer { @@ -95,7 +95,7 @@ public class LodRenderer * These have to be separate because we can't override the * buffers in the VBOs (and we don't want too) */ - private int[][] storageBufferIds; + private int[][][] storageBufferIds; private ChunkPos vbosCenter = new ChunkPos(0, 0); @@ -291,9 +291,9 @@ public class LodRenderer setupFog(fogSettings.far.distance, fogSettings.far.quality); - for (int i = 0; i < lodBufferBuilder.bufferSize[x][z]; i++) + for (int i = 0; i < lodBufferBuilder.numberOfBuffersPerRegion[x][z]; i++) { - sendLodsToGpuAndDraw(vbos[x][z][i], storageBufferIds[x][z], modelViewMatrix); + drawBuffer(vbos[x][z][i], storageBufferIds[x][z][i], modelViewMatrix); } } } @@ -334,10 +334,8 @@ public class LodRenderer } - /** - * This is where the actual drawing happens. - */ - private void sendLodsToGpuAndDraw(VertexBuffer vbo, int bufferStorageId, Matrix4f modelViewMatrix) + /** This is where the actual drawing happens. */ + private void drawBuffer(VertexBuffer vbo, int bufferStorageId, Matrix4f modelViewMatrix) { if (vbo == null) return; @@ -353,6 +351,8 @@ public class LodRenderer } + + //=================// // Setup Functions // //=================// @@ -556,9 +556,7 @@ public class LodRenderer } - /** - * setup the lighting to be used for the LODs - */ + /** setup the lighting to be used for the LODs */ /*private void setupLighting(LodDimension lodDimension, float partialTicks) { // Determine if the player has night vision @@ -599,9 +597,7 @@ public class LodRenderer RenderSystem.enableLighting(); }*/ - /** - * Create all buffers that will be used. - */ + /** Create all buffers that will be used. */ public void setupBuffers(LodDimension lodDim) { lodBufferBuilder.setupBuffers(lodDim);