partially add different context rendering

This commit is contained in:
James Seibel
2021-09-12 23:14:43 -05:00
parent 6ec146ba60
commit 8822e2d8a1
7 changed files with 421 additions and 139 deletions
@@ -17,6 +17,7 @@
*/
package com.seibel.lod.builders;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
@@ -26,7 +27,10 @@ import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import com.mojang.datafixers.util.Pair;
import com.seibel.lod.builders.lodTemplates.Box;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.objects.DataPoint;
@@ -36,6 +40,8 @@ import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.PosToRenderContainer;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.proxy.GlProxy;
import com.seibel.lod.proxy.GlProxy.GlProxyContext;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
@@ -45,7 +51,6 @@ import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
/**
* This object is used to create NearFarBuffer objects.
*
@@ -57,76 +62,79 @@ public class LodBufferBuilder
/**
* This holds the thread used to generate new LODs off the main thread.
*/
private ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - main"));
public static ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - main"));
/**
* This holds the threads used to generate buffers.
*/
private ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new LodThreadFactory(this.getClass().getSimpleName() + " - builder"));
public static ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - builder"));
public volatile ByteBuffer clearByteBuffer;
/**
* The buffers that are used to create LODs using far fog
*/
public volatile BufferBuilder[][] buildableBuffers;
/**
* Used when building new VBOs
*/
public volatile VertexBuffer[][] buildableVbos;
/**
* VBOs that are sent over to the LodNodeRenderer
*/
public volatile VertexBuffer[][] drawableVbos;
public GlProxyContext buildingContext = GlProxyContext.BUILDER;
public GlProxyContext renderContext = GlProxyContext.RENDER;
/**
* if this is true the LOD buffers are currently being
* regenerated.
*/
public boolean generatingBuffers = false;
/**
* if this is true new LOD buffers have been generated
* and are waiting to be swapped with the drawable buffers
*/
private boolean switchVbos = false;
/**
* Size of the buffer builders in bytes last time we created them
*/
public int previousBufferSize = 0;
/**
* Width of the dimension in regions last time we created the buffers
*/
public int previousRegionWidth = 0;
/**
* this is used to prevent multiple threads creating, destroying, or using the buffers at the same time
*/
private ReentrantLock bufferLock = new ReentrantLock();
private static final int NUMBER_OF_DIRECTION = 4;
//in order -x, +x, -z, +z
private static final int[][] ADJ_DIRECTION = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private static final int[][] ADJ_DIRECTION = new int[][] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
private volatile Box[][] boxCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
/** This is the ChunkPos the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built */
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0,0);
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0,0);
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0);
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0);
public LodBufferBuilder()
{
}
/**
* Create a thread to asynchronously generate LOD buffers
* centered around the given camera X and Z.
@@ -137,65 +145,60 @@ public class LodBufferBuilder
* swapped with the drawable buffers in the LodRenderer to be drawn.
*/
public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim,
BlockPos playerBlockPos, boolean fullRegen)
BlockPos playerBlockPos, boolean fullRegen)
{
// only allow one generation process to happen at a time
if (generatingBuffers)
return;
if (buildableBuffers == null)
// setupBuffers hasn't been called yet
return;
generatingBuffers = true;
// round the player's block position down to the nearest chunk BlockPos
ChunkPos playerChunkPos = new ChunkPos(playerBlockPos);
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
Thread thread = new Thread(() ->
{
bufferLock.lock();
try
{
long treeStart = System.currentTimeMillis();
long treeEnd = System.currentTimeMillis();
long startTime = System.currentTimeMillis();
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length);
startBuffers(fullRegen, lodDim);
// =====================//
// RENDERING PART //
// =====================//
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
if (center == null)
center = playerRegionPos;
if (setsToRender == null)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
if (setsToRender.length != lodDim.regions.length)
setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length];
if (boxCache == null)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
if (boxCache.length != lodDim.regions.length)
boxCache = new Box[lodDim.regions.length][lodDim.regions.length];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++)
{
for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++)
@@ -205,7 +208,7 @@ public class LodBufferBuilder
RegionPos regionPos = new RegionPos(
xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2),
zRegion + lodDim.getCenterZ() - Math.floorDiv(lodDim.getWidth(), 2));
// local position in the vbo and bufferBuilder arrays
BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion];
LodRegion region = lodDim.getRegion(regionPos.x, regionPos.z);
@@ -220,26 +223,26 @@ public class LodBufferBuilder
final int zR = zRegion;
Callable<Boolean> dataToRenderThread = () ->
{
//previous setToRender chache
if (setsToRender[xR][zR] == null)
{
setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z);
}
if (boxCache[xR][zR] == null)
{
boxCache[xR][zR] = new Box();
}
PosToRenderContainer posToRender = setsToRender[xR][zR];
posToRender.clear(minDetail, regionPos.x, regionPos.z);
lodDim.getDataToRender(
posToRender,
regionPos,
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
byte detailLevel;
int posX;
int posZ;
@@ -259,9 +262,9 @@ public class LodBufferBuilder
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist)
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
{
continue;
}
@@ -271,24 +274,25 @@ public class LodBufferBuilder
if (lodDim.doesDataExist(detailLevel, posX, posZ))
{
dataPoint = lodDim.getData(detailLevel, posX, posZ);
if(DataPoint.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPoint.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH)
if (DataPoint.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPoint.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH)
continue;
adjData = new long[NUMBER_OF_DIRECTION];
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
{
xAdj = posX + ADJ_DIRECTION[direction][0];
zAdj = posZ + ADJ_DIRECTION[direction][1];
chunkXdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel,zAdj) - playerChunkPos.z;
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
{
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& posToRender.contains(detailLevel, xAdj, zAdj))
&& posToRender.contains(detailLevel, xAdj, zAdj))
{
adjData[direction]= lodDim.getData(detailLevel, xAdj, zAdj);
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj);
}
} else
}
else
{
if (posToRender.contains(detailLevel, xAdj, zAdj))
{
@@ -297,22 +301,23 @@ public class LodBufferBuilder
}
}
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData,
detailLevel, posX, posZ, boxCache[xR][zR],renderer.previousDebugMode);
detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode);
}
} catch (ArrayIndexOutOfBoundsException e)
}
catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
return false;
}
}// for pos to in list to render
// the thread executed successfully
} // for pos to in list to render
// the thread executed successfully
return true;
};
nodeToRenderThreads.add(dataToRenderThread);
}
}// region z
}// region z
} // region z
} // region z
long renderStart = System.currentTimeMillis();
// wait for all threads to finish
List<Future<Boolean>> futuresBuffer = bufferBuilderThreads.invokeAll(nodeToRenderThreads);
@@ -327,8 +332,7 @@ public class LodBufferBuilder
}
}
long renderEnd = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
@SuppressWarnings("unused")
long buildTime = endTime - startTime;
@@ -343,37 +347,38 @@ public class LodBufferBuilder
// mark that the buildable buffers as ready to swap
switchVbos = true;
} catch (Exception e)
}
catch (Exception e)
{
ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: ");
e.printStackTrace();
} finally
}
finally
{
// regardless of if we successfully created the buffers
// we are done generating.
generatingBuffers = false;
// clean up any potentially open resources
if (buildableBuffers != null)
closeBuffers(fullRegen, lodDim);
// upload the new buffers
uploadBuffers(fullRegen, lodDim);
bufferLock.unlock();
}
});
mainGenThread.execute(thread);
return;
}
//===============================//
// BufferBuilder related methods //
//===============================//
/**
* Called from the LodRenderer to create the
* BufferBuilders. <br><br>
@@ -383,29 +388,41 @@ public class LodBufferBuilder
public void setupBuffers(int numbRegionsWide, int bufferMaxCapacity)
{
bufferLock.lock();
previousRegionWidth = numbRegionsWide;
previousBufferSize = bufferMaxCapacity;
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide];
buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
clearByteBuffer = new BufferBuilder(bufferMaxCapacity).buffer;
clearByteBuffer.position(clearByteBuffer.limit()-1);
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
{
buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity);
buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableVbos[x][z].id);
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, bufferMaxCapacity, GL15C.GL_DYNAMIC_DRAW);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, drawableVbos[x][z].id);
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, bufferMaxCapacity, GL15C.GL_DYNAMIC_DRAW);
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
}
bufferLock.unlock();
}
/**
* sets the buffers and Vbos to null, forcing them to be recreated. <br><br>
* <p>
@@ -414,15 +431,14 @@ public class LodBufferBuilder
public void destroyBuffers()
{
bufferLock.lock();
buildableBuffers = null;
buildableVbos = null;
drawableVbos = null;
bufferLock.unlock();
}
/**
* Calls begin on each of the buildable BufferBuilders.
*/
@@ -437,7 +453,7 @@ public class LodBufferBuilder
}
}
}
/**
* Calls end on each of the buildable BufferBuilders.
*/
@@ -445,34 +461,88 @@ public class LodBufferBuilder
{
for (int x = 0; x < buildableBuffers.length; x++)
for (int z = 0; z < buildableBuffers.length; z++)
if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.regen[x][z]))
{
buildableBuffers[x][z].end();
}
}
/**
* Called from the LodRenderer to create the
* BufferBuilders at the right size.
*/
private void uploadBuffers(boolean fullRegen, LodDimension lodDim)
{
GlProxy.getInstance().setGlContext(buildingContext);
for (int x = 0; x < buildableVbos.length; x++)
{
for (int z = 0; z < buildableVbos.length; z++)
{
if (fullRegen || lodDim.regen[x][z])
{
buildableVbos[x][z].upload(buildableBuffers[x][z]);
// if (fullRegen || lodDim.regen[x][z])
// {
vboUpload(x, z, lodDim, buildableVbos);
lodDim.regen[x][z] = false;
}
}
// }// regen region
}// z
}// x
GL11.glFlush();
GlProxy.getInstance().setGlContext(GlProxyContext.NONE);
}
public void vboUpload(int xLocal, int zLocal, LodDimension lodDim, VertexBuffer[][] buildableVbos)
{
VertexBuffer vbo = buildableVbos[xLocal][zLocal];
BufferBuilder bufferBuilder = buildableBuffers[xLocal][zLocal];
GlProxyContext test = GlProxy.getInstance().getGlContext();
long start = System.nanoTime();
long end = start;
if (vbo.id != -1)
{
Pair<BufferBuilder.DrawState, ByteBuffer> pair = bufferBuilder.popNextBuffer();
ByteBuffer bytebuffer = pair.getSecond();
vbo.vertexCount = bytebuffer.remaining() / vbo.format.getVertexSize();
if (xLocal == 0 && zLocal == 0) while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id); // 34962 = 0x8892 = GL_ARRAY_BUFFER
// ByteBuffer vboBuffer = GL15C.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, bytebuffer, GL15C.GL_STATIC_DRAW);
// clearByteBuffer.position(0);
// clearByteBuffer.position(clearByteBuffer.limit()-1);
//clearByteBuffer
// GL15C.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0L, clearByteBuffer);
GL15C.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0L, bytebuffer);
// long bufferSize = GL43C.glGetBufferParameteri64(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE);
// GL43C.glClearBufferSubData(GL15.GL_ARRAY_BUFFER, GL43., 0, bufferSize, GL11.GL_RGB, GL11.GL_FLOAT, (ByteBuffer) null);
// if (xLocal == 0 && zLocal == 0) ClientProxy.LOGGER.info("err: " + GL11.glGetError());
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
// GL15C.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
}
end = System.nanoTime();
if (xLocal == 0 && zLocal == 0)
{
double time = (end - start) * 0.000001 * lodDim.getWidth() * lodDim.getWidth();
ClientProxy.LOGGER.info("upload: " + time + "\t" + test);
}
}
/**
* Get the newly created VBOs
*/
@@ -485,16 +555,24 @@ public class LodBufferBuilder
VertexBuffer[][] tmp = drawableVbos;
drawableVbos = buildableVbos;
buildableVbos = tmp;
GlProxyContext context = renderContext;
renderContext = buildingContext;
buildingContext = context;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
switchVbos = false;
bufferLock.unlock();
// ClientProxy.LOGGER.info("Get vertex Buffers: " + GlProxy.getInstance().getGlContext());
}
return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos);
// ClientProxy.LOGGER.info("Get vbo first: " + drawableVbos[0][0].id + "\t" + GlProxy.getInstance().getGlContext());
return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos, renderContext);
}
/**
* A simple container to pass multiple objects back in the getVertexBuffers method.
*/
@@ -502,14 +580,16 @@ public class LodBufferBuilder
{
public VertexBuffer[][] vbos;
public ChunkPos drawableCenterChunkPos;
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos)
public GlProxyContext drawingContext;
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos, GlProxyContext newDrawingContext)
{
vbos = newVbos;
drawableCenterChunkPos = newDrawableCenterChunkPos;
drawingContext = newDrawingContext;
}
}
/**
* If this is true the buildable near and far
* buffers have been generated and are ready to be
@@ -519,6 +599,5 @@ public class LodBufferBuilder
{
return switchVbos;
}
}