From b0e924c7fea07e4dae12867a4666bb6fd7d2e143 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 22 Apr 2026 17:14:50 -0500 Subject: [PATCH] Fix nvidia driver crash --- .../openGl/glObject/buffer/GLBuffer.java | 58 ++++++++----------- .../terrain/GlDhTerrainShaderProgram.java | 55 +++++++----------- 2 files changed, 46 insertions(+), 67 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java index aaed1cfd8..6aca3891e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java @@ -62,14 +62,13 @@ public class GLBuffer implements AutoCloseable private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup"); - protected int id; + protected int id = 0; public final int getId() { return this.id; } protected int size = 0; public int getSize() { return this.size; } protected boolean bufferStorage; protected boolean isMapped = false; - public final StampedLock writeLock = new StampedLock(); //==============// @@ -112,27 +111,26 @@ public class GLBuffer implements AutoCloseable LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread."); } - // destroy the old buffer if one is present - if (this.id != 0) + + int oldId = this.id; + this.id = GLMC.glGenBuffers(); + + // destroy the old buffer + // after the new one has been created + // to hopefully prevent a rare race conditions where the old ID + // is still used somewhere + if (oldId != 0) { - destroyBufferIdNow(this.id); + destroyBufferIdNow(oldId); } - long writeLock = this.writeLock.writeLock(); - try - { - this.id = GLMC.glGenBuffers(); - this.bufferStorage = asBufferStorage; - bufferCount.getAndIncrement(); - - PhantomReference phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE); - PHANTOM_TO_BUFFER_ID.put(phantom, this.id); - BUFFER_ID_TO_PHANTOM.put(this.id, phantom); - } - finally - { - this.writeLock.unlock(writeLock); - } + + this.bufferStorage = asBufferStorage; + bufferCount.getAndIncrement(); + + PhantomReference phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE); + PHANTOM_TO_BUFFER_ID.put(phantom, this.id); + BUFFER_ID_TO_PHANTOM.put(this.id, phantom); } @@ -144,20 +142,14 @@ public class GLBuffer implements AutoCloseable return; } - long writeLock = this.writeLock.writeLock(); - try - { - final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda - RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); }); - - this.id = 0; - this.size = 0; - } - finally - { - this.writeLock.unlock(writeLock); - } + final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda + // mark the old data is invalid before deleting to prevent a rare race condition + // where the queued on render thread task runs before the ID is cleared + this.id = 0; + this.size = 0; + + RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); }); } private static void destroyBufferIdNow(int id) { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/terrain/GlDhTerrainShaderProgram.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/terrain/GlDhTerrainShaderProgram.java index 027e5c295..ff8b9b6cf 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/terrain/GlDhTerrainShaderProgram.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/terrain/GlDhTerrainShaderProgram.java @@ -341,46 +341,33 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS continue; } - - long vboReadLock = vbo.writeLock.tryReadLock(); - if (vboReadLock == 0) + // don't render empty sections + if (vbo.getVertexCount() == 0) { - // VBO is being deleted continue; } - try + // don't render deleted VBOs (this will crash the driver/game) + if (vbo.getId() == 0 + || vbo.getQuadIBO().getId() == 0) { - if (vbo.getVertexCount() == 0) - { - continue; - } - - if (vbo.getId() == 0 - || vbo.getQuadIBO().getId() == 0) - { - continue; - } - - // 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5 - int indexCount = (int)(vbo.getVertexCount() * 1.5); - - vbo.bind(); - vbo.getQuadIBO().bind(); - - GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId()); - GL32.glDrawElements( - GL32.GL_TRIANGLES, - indexCount, - vbo.getQuadIBO().getGlType(), 0); - - vbo.unbind(); - vbo.getQuadIBO().unbind(); - } - finally - { - vbo.writeLock.unlock(vboReadLock); + continue; } + + // 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5 + int indexCount = (int)(vbo.getVertexCount() * 1.5); + + vbo.bind(); + vbo.getQuadIBO().bind(); + + GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId()); + GL32.glDrawElements( + GL32.GL_TRIANGLES, + indexCount, + vbo.getQuadIBO().getGlType(), 0); + + vbo.unbind(); + vbo.getQuadIBO().unbind(); } } }