Improve Buffer uploading speed and remove buffer upload thread
This commit is contained in:
+38
-41
@@ -19,9 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
|
||||
@@ -30,7 +28,6 @@ import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.StatsMap;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
@@ -46,9 +43,6 @@ import java.util.concurrent.*;
|
||||
public class ColumnRenderBuffer implements AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
private static final long MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS = 1_000_000;
|
||||
|
||||
/** number of bytes a single quad takes */
|
||||
public static final int QUADS_BYTE_SIZE = LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 4;
|
||||
@@ -59,63 +53,81 @@ public class ColumnRenderBuffer implements AutoCloseable
|
||||
|
||||
|
||||
|
||||
|
||||
public final DhBlockPos pos;
|
||||
public final DhBlockPos blockPos;
|
||||
|
||||
public boolean buffersUploaded = false;
|
||||
|
||||
private GLVertexBuffer[] vbos;
|
||||
private GLVertexBuffer[] vbosTransparent;
|
||||
|
||||
private CompletableFuture<ColumnRenderBuffer> uploadFuture = null;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public ColumnRenderBuffer(DhBlockPos pos)
|
||||
public ColumnRenderBuffer(DhBlockPos blockPos)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.blockPos = blockPos;
|
||||
this.vbos = new GLVertexBuffer[0];
|
||||
this.vbosTransparent = new GLVertexBuffer[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// buffer uploading //
|
||||
//==================//
|
||||
|
||||
/** Should be run on a DH thread. */
|
||||
public void makeAndUploadBuffers(LodQuadBuilder builder, EDhApiGpuUploadMethod gpuUploadMethod) throws InterruptedException
|
||||
public synchronized CompletableFuture<ColumnRenderBuffer> makeAndUploadBuffersAsync(LodQuadBuilder builder, EDhApiGpuUploadMethod gpuUploadMethod)
|
||||
{
|
||||
LodUtil.assertTrue(DhApi.isDhThread(), "Buffer uploading needs to be done on a DH thread to prevent locking up any MC threads.");
|
||||
if (this.uploadFuture != null)
|
||||
{
|
||||
return this.uploadFuture;
|
||||
}
|
||||
this.uploadFuture = new CompletableFuture<>();
|
||||
|
||||
|
||||
|
||||
// make the buffers
|
||||
ArrayList<ByteBuffer> opaqueBuffers = builder.makeOpaqueVertexBuffers();
|
||||
ArrayList<ByteBuffer> transparentBuffers = builder.makeTransparentVertexBuffers();
|
||||
|
||||
vbos = resizeBuffer(vbos, opaqueBuffers.size());
|
||||
vbosTransparent = resizeBuffer(vbosTransparent, transparentBuffers.size());
|
||||
this.vbos = resizeBuffer(this.vbos, opaqueBuffers.size());
|
||||
this.vbosTransparent = resizeBuffer(this.vbosTransparent, transparentBuffers.size());
|
||||
|
||||
|
||||
// upload on MC's render thread
|
||||
CompletableFuture<Void> uploadFuture = new CompletableFuture<>();
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
uploadBuffersDirect(vbos, opaqueBuffers, gpuUploadMethod);
|
||||
uploadBuffersDirect(vbosTransparent, transparentBuffers, gpuUploadMethod);
|
||||
if (Thread.interrupted())
|
||||
{
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
uploadBuffersDirect(this.vbos, opaqueBuffers, gpuUploadMethod);
|
||||
uploadBuffersDirect(this.vbosTransparent, transparentBuffers, gpuUploadMethod);
|
||||
this.buffersUploaded = true;
|
||||
uploadFuture.complete(null);
|
||||
|
||||
this.uploadFuture.complete(this);
|
||||
this.uploadFuture = null;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
catch (InterruptedException ignore)
|
||||
{
|
||||
throw new CompletionException(e);
|
||||
this.uploadFuture.complete(this);
|
||||
this.uploadFuture = null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected issue uploading buffer ["+this.blockPos +"], error: ["+e.getMessage()+"].", e);
|
||||
|
||||
this.uploadFuture.completeExceptionally(e);
|
||||
this.uploadFuture = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -133,22 +145,7 @@ public class ColumnRenderBuffer implements AutoCloseable
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// wait for the upload to finish
|
||||
uploadFuture.get(5_000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
|
||||
}
|
||||
catch (TimeoutException e)
|
||||
{
|
||||
// timeouts can be ignored because it generally means the
|
||||
// MC Render thread executor was closed
|
||||
//LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
|
||||
}
|
||||
return this.uploadFuture;
|
||||
}
|
||||
private static GLVertexBuffer[] resizeBuffer(GLVertexBuffer[] vbos, int newSize)
|
||||
{
|
||||
@@ -224,7 +221,7 @@ public class ColumnRenderBuffer implements AutoCloseable
|
||||
public boolean renderOpaque(LodRenderer renderContext, DhApiRenderParam renderEventParam)
|
||||
{
|
||||
boolean hasRendered = false;
|
||||
renderContext.setModelViewMatrixOffset(this.pos, renderEventParam);
|
||||
renderContext.setModelViewMatrixOffset(this.blockPos, renderEventParam);
|
||||
for (GLVertexBuffer vbo : this.vbos)
|
||||
{
|
||||
if (vbo == null)
|
||||
@@ -252,7 +249,7 @@ public class ColumnRenderBuffer implements AutoCloseable
|
||||
try
|
||||
{
|
||||
// can throw an IllegalStateException if the GL program was freed before it should've been
|
||||
renderContext.setModelViewMatrixOffset(this.pos, renderEventParam);
|
||||
renderContext.setModelViewMatrixOffset(this.blockPos, renderEventParam);
|
||||
|
||||
for (GLVertexBuffer vbo : this.vbosTransparent)
|
||||
{
|
||||
@@ -273,7 +270,7 @@ public class ColumnRenderBuffer implements AutoCloseable
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOGGER.error("renderContext program doesn't exist for pos: "+this.pos, e);
|
||||
LOGGER.error("renderContext program doesn't exist for pos: "+this.blockPos, e);
|
||||
}
|
||||
|
||||
return hasRendered;
|
||||
|
||||
+10
-55
@@ -115,62 +115,17 @@ public class ColumnRenderBufferBuilder
|
||||
LodQuadBuilder quadBuilder
|
||||
)
|
||||
{
|
||||
// TODO put into a single future/thread so it can be easily canceled
|
||||
ThreadPoolExecutor bufferUploaderExecutor = ThreadPoolUtil.getBufferUploaderExecutor();
|
||||
if (bufferUploaderExecutor == null || bufferUploaderExecutor.isTerminated())
|
||||
ColumnRenderBuffer buffer = new ColumnRenderBuffer(new DhBlockPos(DhSectionPos.getMinCornerBlockX(pos), clientLevel.getMinY(), DhSectionPos.getMinCornerBlockZ(pos)));
|
||||
CompletableFuture<ColumnRenderBuffer> uploadFuture = buffer.makeAndUploadBuffersAsync(quadBuilder, GLProxy.getInstance().getGpuUploadMethod());
|
||||
uploadFuture.whenComplete((uploadedBuffer, exception) ->
|
||||
{
|
||||
// one or more of the thread pools has been shut down
|
||||
CompletableFuture<ColumnRenderBuffer> future = new CompletableFuture<>();
|
||||
future.cancel(true);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
ColumnRenderBuffer buffer = new ColumnRenderBuffer(new DhBlockPos(DhSectionPos.getMinCornerBlockX(pos), clientLevel.getMinY(), DhSectionPos.getMinCornerBlockZ(pos)));
|
||||
try
|
||||
{
|
||||
buffer.makeAndUploadBuffers(quadBuilder, GLProxy.getInstance().getGpuUploadMethod());
|
||||
if (buffer.buffersUploaded)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
buffer.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw UncheckedInterruptedException.convert(e);
|
||||
}
|
||||
catch (Throwable e3)
|
||||
{
|
||||
LOGGER.error("LodNodeBufferBuilder was unable to upload buffer for pos ["+DhSectionPos.toString(pos)+"], error: [" + e3.getMessage() + "].", e3);
|
||||
throw e3;
|
||||
}
|
||||
}, bufferUploaderExecutor);
|
||||
}
|
||||
catch (RejectedExecutionException ignore)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
|
||||
CompletableFuture<ColumnRenderBuffer> future = new CompletableFuture<>();
|
||||
future.cancel(true);
|
||||
return future;
|
||||
}
|
||||
// clean up if not uploaded
|
||||
if (!uploadedBuffer.buffersUploaded)
|
||||
{
|
||||
uploadedBuffer.close();
|
||||
}
|
||||
});
|
||||
return uploadFuture;
|
||||
}
|
||||
private static void makeLodRenderData(
|
||||
LodQuadBuilder quadBuilder, ColumnRenderSource renderSource, IDhClientLevel clientLevel,
|
||||
|
||||
+5
-1
@@ -26,7 +26,11 @@ import com.seibel.distanthorizons.api.objects.data.DhApiChunk;
|
||||
import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.*;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.InProgressWorldGenTaskGroup;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.WorldGenTask;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.WorldGenTaskGroup;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
|
||||
@@ -77,7 +77,6 @@ public class F3Screen
|
||||
ThreadPoolExecutor updatePool = ThreadPoolUtil.getUpdatePropagatorExecutor();
|
||||
ThreadPoolExecutor lodBuilderPool = ThreadPoolUtil.getChunkToLodBuilderExecutor();
|
||||
ThreadPoolExecutor bufferBuilderPool = ThreadPoolUtil.getBufferBuilderExecutor();
|
||||
ThreadPoolExecutor bufferUploaderPool = ThreadPoolUtil.getBufferUploaderExecutor();
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
Iterable<? extends IDhLevel> levelIterator = world.getAllLoadedLevels();
|
||||
@@ -96,7 +95,6 @@ public class F3Screen
|
||||
messageList.add(getThreadPoolStatString("Update Propagator", updatePool));
|
||||
messageList.add(getThreadPoolStatString("LOD Builder", lodBuilderPool));
|
||||
messageList.add(getThreadPoolStatString("Buffer Builder", bufferBuilderPool));
|
||||
messageList.add(getThreadPoolStatString("Buffer Uploader", bufferUploaderPool));
|
||||
messageList.add("");
|
||||
// chunk updates
|
||||
messageList.add(SharedApi.INSTANCE.getDebugMenuString());
|
||||
|
||||
@@ -274,10 +274,11 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
this.bufferUploadFuture = ColumnRenderBufferBuilder.uploadBuffersAsync(this.level, this.pos, lodQuadBuilder);
|
||||
return this.bufferUploadFuture.thenCompose((buffer) ->
|
||||
{
|
||||
// needed to clean up the old data
|
||||
ColumnRenderBuffer previousBuffer = this.renderBuffer;
|
||||
|
||||
// upload complete, clean up the old data if
|
||||
this.renderBuffer = buffer;
|
||||
// upload complete
|
||||
this.renderBuffer = buffer.buffersUploaded ? buffer : null;
|
||||
this.buildAndUploadRenderDataToGpuFuture = null;
|
||||
this.bufferBuildFuture = null;
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ public class GLProxy
|
||||
// only try running for 4ms at a time to (hopefully) prevent random lag spikes
|
||||
if (runDuration > 4_000_000)
|
||||
{
|
||||
//break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,11 +56,6 @@ public class ThreadPoolUtil
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getWorldGenExecutor() { return worldGenThreadPool.executor; }
|
||||
|
||||
public static final String BUFFER_UPLOADER_THREAD_NAME = "Buffer Uploader";
|
||||
private static ThreadPoolExecutor bufferUploaderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBufferUploaderExecutor() { return bufferUploaderThreadPool; }
|
||||
|
||||
public static final String CLEANUP_THREAD_NAME = "Cleanup";
|
||||
private static ThreadPoolExecutor cleanupThreadPool;
|
||||
@Nullable
|
||||
@@ -118,7 +113,6 @@ public class ThreadPoolUtil
|
||||
updatePropagatorThreadPool = new ConfigThreadPool(UPDATE_PROPAGATOR_THREAD_FACTORY, Config.Common.MultiThreading.numberOfUpdatePropagatorThreads, Config.Common.MultiThreading.runTimeRatioForUpdatePropagatorThreads, null);
|
||||
worldGenThreadPool = new ConfigThreadPool(WORLD_GEN_THREAD_FACTORY, Config.Common.MultiThreading.numberOfWorldGenerationThreads, Config.Common.MultiThreading.runTimeRatioForWorldGenerationThreads, null);
|
||||
networkCompressionThreadPool = new ConfigThreadPool(NETWORK_COMPRESSION_THREAD_FACTORY, Config.Common.MultiThreading.numberOfNetworkCompressionThreads, Config.Common.MultiThreading.runTimeRatioForNetworkCompressionThreads, null);
|
||||
bufferUploaderThreadPool = ThreadUtil.makeSingleThreadPool(BUFFER_UPLOADER_THREAD_NAME);
|
||||
cleanupThreadPool = ThreadUtil.makeSingleThreadPool(CLEANUP_THREAD_NAME);
|
||||
beaconCullingThreadPool = ThreadUtil.makeSingleThreadPool(BEACON_CULLING_THREAD_NAME);
|
||||
|
||||
@@ -160,7 +154,6 @@ public class ThreadPoolUtil
|
||||
updatePropagatorThreadPool.shutdownExecutorService();
|
||||
worldGenThreadPool.shutdownExecutorService();
|
||||
networkCompressionThreadPool.shutdownExecutorService();
|
||||
bufferUploaderThreadPool.shutdown();
|
||||
cleanupThreadPool.shutdown();
|
||||
beaconCullingThreadPool.shutdown();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user