Move async GL calls to the render thread
Hopefully to fix potential crashes on non-Nvidia or less stable GPU drivers
This commit is contained in:
+1
-1
@@ -382,7 +382,7 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer
|
|||||||
{
|
{
|
||||||
this.buffersUploaded = false;
|
this.buffersUploaded = false;
|
||||||
|
|
||||||
GLProxy.getInstance().recordOpenGlCall(() ->
|
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||||
{
|
{
|
||||||
for (GLVertexBuffer buffer : this.vbos)
|
for (GLVertexBuffer buffer : this.vbos)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import java.util.Arrays;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A singleton that holds references to different openGL contexts
|
* A singleton that holds references to different openGL contexts
|
||||||
@@ -65,15 +64,11 @@ import java.util.stream.Stream;
|
|||||||
*
|
*
|
||||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br>
|
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br>
|
||||||
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
|
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
*/
|
*/
|
||||||
public class GLProxy
|
public class GLProxy
|
||||||
{
|
{
|
||||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
|
||||||
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
|
|
||||||
|
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||||
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
||||||
() -> Config.Client.Advanced.Logging.logRendererGLEvent.get());
|
() -> Config.Client.Advanced.Logging.logRendererGLEvent.get());
|
||||||
@@ -88,6 +83,17 @@ public class GLProxy
|
|||||||
private static GLProxy instance = null;
|
private static GLProxy instance = null;
|
||||||
|
|
||||||
|
|
||||||
|
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the list that items should be added to. <br>
|
||||||
|
* Two lists exist to prevent potential concurrency issues where we are reading and writing
|
||||||
|
* at the same time.
|
||||||
|
*/
|
||||||
|
private final ArrayList<Runnable> addRenderThreadRunnableList = new ArrayList<>();
|
||||||
|
/** the list that items should be read from */
|
||||||
|
private final ArrayList<Runnable> readRenderThreadRunnableList = new ArrayList<>();
|
||||||
|
|
||||||
/** Minecraft's GLFW window */
|
/** Minecraft's GLFW window */
|
||||||
public final long minecraftGlContext;
|
public final long minecraftGlContext;
|
||||||
/** Minecraft's GL capabilities */
|
/** Minecraft's GL capabilities */
|
||||||
@@ -459,9 +465,9 @@ public class GLProxy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================//
|
//=========================//
|
||||||
// MC render thread runnables //
|
// Worker Thread Runnables //
|
||||||
//============================//
|
//=========================//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously calls the given runnable on proxy's OpenGL context.
|
* Asynchronously calls the given runnable on proxy's OpenGL context.
|
||||||
@@ -472,14 +478,18 @@ public class GLProxy
|
|||||||
public void recordOpenGlCall(Runnable renderCall)
|
public void recordOpenGlCall(Runnable renderCall)
|
||||||
{
|
{
|
||||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
this.workerThread.execute(() -> this.runnableContainer(renderCall, stackTrace));
|
this.workerThread.execute(() -> this.runOpenGlCall(renderCall, stackTrace, true));
|
||||||
}
|
}
|
||||||
private void runnableContainer(Runnable renderCall, StackTraceElement[] stackTrace)
|
private void runOpenGlCall(Runnable renderCall, StackTraceElement[] stackTrace, boolean useProxyWorkerContext)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// set up the context...
|
// set up the context if requested...
|
||||||
this.setGlContext(EGLProxyContext.PROXY_WORKER);
|
if (useProxyWorkerContext)
|
||||||
|
{
|
||||||
|
this.setGlContext(EGLProxyContext.PROXY_WORKER);
|
||||||
|
}
|
||||||
|
|
||||||
// ...run the actual code...
|
// ...run the actual code...
|
||||||
renderCall.run();
|
renderCall.run();
|
||||||
}
|
}
|
||||||
@@ -492,7 +502,10 @@ public class GLProxy
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// ...and make sure the context is released when the thread finishes
|
// ...and make sure the context is released when the thread finishes
|
||||||
this.setGlContext(EGLProxyContext.NONE);
|
if (useProxyWorkerContext)
|
||||||
|
{
|
||||||
|
this.setGlContext(EGLProxyContext.NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +541,35 @@ public class GLProxy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// Render Thread Runnables //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
public void queueRunningOnRenderThread(Runnable renderCall)
|
||||||
|
{
|
||||||
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
|
this.addRenderThreadRunnableList.add(() -> this.runOpenGlCall(renderCall, stackTrace, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doesn't do any thread/GL Context validation.
|
||||||
|
* Running this outside of the render thread may cause crashes or other issues.
|
||||||
|
*/
|
||||||
|
public void runRenderThreadTasks()
|
||||||
|
{
|
||||||
|
ArrayList<Runnable> tempList = this.addRenderThreadRunnableList;
|
||||||
|
this.addRenderThreadRunnableList = this.readRenderThreadRunnableList;
|
||||||
|
this.readRenderThreadRunnableList = tempList;
|
||||||
|
|
||||||
|
for (Runnable runnable : this.readRenderThreadRunnableList)
|
||||||
|
{
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
this.readRenderThreadRunnableList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
// logging //
|
// logging //
|
||||||
//=========//
|
//=========//
|
||||||
|
|||||||
+7
-4
@@ -122,9 +122,12 @@ public class GLBuffer implements AutoCloseable
|
|||||||
}
|
}
|
||||||
private static void destroyBufferId(boolean async, int id)
|
private static void destroyBufferId(boolean async, int id)
|
||||||
{
|
{
|
||||||
if (async && GLProxy.getInstance().getGlContext() != EGLProxyContext.PROXY_WORKER)
|
EGLProxyContext glContext = GLProxy.getInstance().getGlContext();
|
||||||
|
if (async
|
||||||
|
&& glContext != EGLProxyContext.PROXY_WORKER
|
||||||
|
&& glContext != EGLProxyContext.MINECRAFT)
|
||||||
{
|
{
|
||||||
GLProxy.getInstance().recordOpenGlCall(() -> destroyBufferId(false, id));
|
GLProxy.getInstance().queueRunningOnRenderThread(() -> destroyBufferId(false, id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -200,7 +203,7 @@ public class GLBuffer implements AutoCloseable
|
|||||||
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||||
|
|
||||||
int bbSize = bb.limit() - bb.position();
|
int bbSize = bb.limit() - bb.position();
|
||||||
this.destroy(false);
|
this.destroy(true);
|
||||||
this.create(true);
|
this.create(true);
|
||||||
this.bind();
|
this.bind();
|
||||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
|
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
|
||||||
@@ -313,7 +316,7 @@ public class GLBuffer implements AutoCloseable
|
|||||||
{
|
{
|
||||||
// recreate if the buffer storage type changed
|
// recreate if the buffer storage type changed
|
||||||
this.bind();
|
this.bind();
|
||||||
this.destroy(false);
|
this.destroy(true);
|
||||||
this.create(uploadMethod.useBufferStorage);
|
this.create(uploadMethod.useBufferStorage);
|
||||||
this.bind();
|
this.bind();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -486,6 +486,9 @@ public class LodRenderer
|
|||||||
|
|
||||||
profiler.popPush("LOD cleanup");
|
profiler.popPush("LOD cleanup");
|
||||||
LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
|
LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
|
||||||
|
|
||||||
|
GLProxy.getInstance().runRenderThreadTasks();
|
||||||
|
|
||||||
lightmap.unbind();
|
lightmap.unbind();
|
||||||
if (ENABLE_IBO)
|
if (ENABLE_IBO)
|
||||||
{
|
{
|
||||||
@@ -666,7 +669,7 @@ public class LodRenderer
|
|||||||
this.setupLock.lock();
|
this.setupLock.lock();
|
||||||
|
|
||||||
EVENT_LOGGER.info("Queuing Renderer Cleanup for main render thread");
|
EVENT_LOGGER.info("Queuing Renderer Cleanup for main render thread");
|
||||||
GLProxy.getInstance().recordOpenGlCall(() ->
|
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||||
{
|
{
|
||||||
EVENT_LOGGER.info("Renderer Cleanup Started");
|
EVENT_LOGGER.info("Renderer Cleanup Started");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user