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 6aca3891e..4ba33cfce 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
@@ -69,6 +69,17 @@ public class GLBuffer implements AutoCloseable
protected boolean bufferStorage;
protected boolean isMapped = false;
+ /**
+ * Locking on the render thread isn't great, but is needed due to an inconsistent
+ * race condition where VBOs can be marked as deleted outside the render thread.
+ *
+ * But, due to being a read-write lock the chance of freezing
+ * the render thread is very low
+ * and since this is a stamped lock, the optimistic read time is basically zero.
+ * (The optimistic lock time doesn't even appear in the profiler).
+ */
+ public final StampedLock renderStampLock = new StampedLock();
+
//==============//
@@ -142,14 +153,27 @@ public class GLBuffer implements AutoCloseable
return;
}
- 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); });
+ long writeStamp = 0;
+ try
+ {
+ // lock to prevent the render thread from accessing the buffer's ID
+ // while we are removing it
+ writeStamp = renderStampLock.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); });
+ }
+ finally
+ {
+ renderStampLock.unlock(writeStamp);
+ }
}
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 ff8b9b6cf..df547a171 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,33 +341,45 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
continue;
}
- // don't render empty sections
- if (vbo.getVertexCount() == 0)
+
+ // for lock information please view the lock's javadocs
+ long vboReadStamp = vbo.renderStampLock.readLock();
+ long iboReadStamp = vbo.getQuadIBO().renderStampLock.readLock();
+ try
{
- continue;
+ // don't render empty sections
+ if (vbo.getVertexCount() == 0)
+ {
+ continue;
+ }
+
+ // don't render deleted VBOs (this will crash the driver/game)
+ 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();
}
-
- // don't render deleted VBOs (this will crash the driver/game)
- if (vbo.getId() == 0
- || vbo.getQuadIBO().getId() == 0)
+ finally
{
- continue;
+ vbo.renderStampLock.unlock(vboReadStamp);
+ vbo.getQuadIBO().renderStampLock.unlock(iboReadStamp);
}
-
- // 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();
}
}
}
diff --git a/coreSubProjects b/coreSubProjects
index e465ef532..d9f3b31cc 160000
--- a/coreSubProjects
+++ b/coreSubProjects
@@ -1 +1 @@
-Subproject commit e465ef5325479fa67e8227d574f145f2a07f842a
+Subproject commit d9f3b31cc56dc463283a68ab89139562f4c851e9