From c13e9f354e86b321e5c3aa1144fda0e3d6a8c0d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 12:39:58 +0000 Subject: [PATCH 1/2] Initial plan From 174adaac6bdb108f045d1fc25a52699c7be3a4da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 12:46:40 +0000 Subject: [PATCH 2/2] Fix fatal JVM crash on macOS: use core GL functions in LwjglGLExt instead of ARB extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS OpenGL Core Profile, legacy ARB extension pointers are stripped even when the same functionality is available via core entry points. This caused a JVM crash when attempting hardware instancing because LwjglGLExt was calling ARBDrawInstanced/ARBInstancedArrays functions that don't exist in the Core Profile. Each method now prefers the equivalent core GL function (promoted to core in the GL version noted in the comment) and falls back to the corresponding ARB extension only when the core entry point is unavailable. This keeps compatibility with older GL2-era contexts that have the ARB extensions but lack the core promotion. Affected mappings: - glDrawArraysInstancedARB → GL31.glDrawArraysInstanced (core since GL3.1) - glDrawElementsInstancedARB → GL31.glDrawElementsInstanced (core since GL3.1) - glVertexAttribDivisorARB → GL33.glVertexAttribDivisor (core since GL3.3) - glGetMultisample → GL32.glGetMultisamplefv (core since GL3.2) - glTexImage2DMultisample → GL32.glTexImage2DMultisample (core since GL3.2) - glGetUniformBlockIndex → GL31.glGetUniformBlockIndex (core since GL3.1) - glBindBufferBase → GL30.glBindBufferBase (core since GL3.0) - glUniformBlockBinding → GL31.glUniformBlockBinding (core since GL3.1) - glGetProgramResourceIndex → GL43.glGetProgramResourceIndex (core since GL4.3) - glShaderStorageBlockBinding→ GL43.glShaderStorageBlockBinding (core since GL4.3) - glFenceSync → GL32.glFenceSync (core since GL3.2) - glClientWaitSync → GL32.glClientWaitSync (core since GL3.2) - glDeleteSync → GL32.glDeleteSync (core since GL3.2) Fixes #2892 --- .../com/jme3/renderer/lwjgl/LwjglGLExt.java | 102 +++++++++++++++--- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java index 83836aa3da..38d66b7f23 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java @@ -38,7 +38,14 @@ import java.nio.IntBuffer; /** - * The LWJGL implementation og {@link GLExt}. + * The LWJGL implementation of {@link GLExt}. + * + *
Each method prefers the equivalent core OpenGL function (available since + * the GL version that promoted the feature to core) and falls back to the + * corresponding ARB extension only when the core entry point is unavailable. + * This avoids JVM crashes on macOS Core Profile drivers that strip legacy ARB + * extension pointers even when the underlying functionality is exposed through + * the core profile. */ public class LwjglGLExt extends LwjglRender implements GLExt { @@ -56,7 +63,12 @@ public void glBufferSubData(final int target, final long offset, final IntBuffer @Override public void glDrawArraysInstancedARB(final int mode, final int first, final int count, final int primCount) { - ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primCount); + // glDrawArraysInstanced is core since OpenGL 3.1 + if (GL.getCapabilities().OpenGL31) { + GL31.glDrawArraysInstanced(mode, first, count, primCount); + } else { + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primCount); + } } @Override @@ -68,64 +80,124 @@ public void glDrawBuffers(final IntBuffer bufs) { @Override public void glDrawElementsInstancedARB(final int mode, final int indicesCount, final int type, final long indicesBufferOffset, final int primCount) { - ARBDrawInstanced.glDrawElementsInstancedARB(mode, indicesCount, type, indicesBufferOffset, primCount); + // glDrawElementsInstanced is core since OpenGL 3.1 + if (GL.getCapabilities().OpenGL31) { + GL31.glDrawElementsInstanced(mode, indicesCount, type, indicesBufferOffset, primCount); + } else { + ARBDrawInstanced.glDrawElementsInstancedARB(mode, indicesCount, type, indicesBufferOffset, primCount); + } } @Override public void glGetMultisample(final int pname, final int index, final FloatBuffer val) { checkLimit(val); - ARBTextureMultisample.glGetMultisamplefv(pname, index, val); + // glGetMultisamplefv is core since OpenGL 3.2 + if (GL.getCapabilities().OpenGL32) { + GL32.glGetMultisamplefv(pname, index, val); + } else { + ARBTextureMultisample.glGetMultisamplefv(pname, index, val); + } } @Override public void glTexImage2DMultisample(final int target, final int samples, final int internalFormat, final int width, final int height, final boolean fixedSampleLocations) { - ARBTextureMultisample.glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); + // glTexImage2DMultisample is core since OpenGL 3.2 + if (GL.getCapabilities().OpenGL32) { + GL32.glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); + } else { + ARBTextureMultisample.glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); + } } @Override public void glVertexAttribDivisorARB(final int index, final int divisor) { - ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + // glVertexAttribDivisor is core since OpenGL 3.3 + if (GL.getCapabilities().OpenGL33) { + GL33.glVertexAttribDivisor(index, divisor); + } else { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } } @Override public int glGetUniformBlockIndex(final int program, final String uniformBlockName) { - return ARBUniformBufferObject.glGetUniformBlockIndex(program, uniformBlockName); + // glGetUniformBlockIndex is core since OpenGL 3.1 + if (GL.getCapabilities().OpenGL31) { + return GL31.glGetUniformBlockIndex(program, uniformBlockName); + } else { + return ARBUniformBufferObject.glGetUniformBlockIndex(program, uniformBlockName); + } } @Override public void glBindBufferBase(final int target, final int index, final int buffer) { - ARBUniformBufferObject.glBindBufferBase(target, index, buffer); + // glBindBufferBase is core since OpenGL 3.0 + if (GL.getCapabilities().OpenGL30) { + GL30.glBindBufferBase(target, index, buffer); + } else { + ARBUniformBufferObject.glBindBufferBase(target, index, buffer); + } } @Override public void glUniformBlockBinding(final int program, final int uniformBlockIndex, final int uniformBlockBinding) { - ARBUniformBufferObject.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); + // glUniformBlockBinding is core since OpenGL 3.1 + if (GL.getCapabilities().OpenGL31) { + GL31.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); + } else { + ARBUniformBufferObject.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); + } } @Override public int glGetProgramResourceIndex(final int program, final int programInterface, final String name) { - return ARBProgramInterfaceQuery.glGetProgramResourceIndex(program, programInterface, name); + // glGetProgramResourceIndex is core since OpenGL 4.3 + if (GL.getCapabilities().OpenGL43) { + return GL43.glGetProgramResourceIndex(program, programInterface, name); + } else { + return ARBProgramInterfaceQuery.glGetProgramResourceIndex(program, programInterface, name); + } } @Override public void glShaderStorageBlockBinding(final int program, final int storageBlockIndex, final int storageBlockBinding) { - ARBShaderStorageBufferObject.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding); + // glShaderStorageBlockBinding is core since OpenGL 4.3 + if (GL.getCapabilities().OpenGL43) { + GL43.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding); + } else { + ARBShaderStorageBufferObject.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding); + } } @Override public Object glFenceSync(final int condition, final int flags) { - return ARBSync.glFenceSync(condition, flags); + // glFenceSync is core since OpenGL 3.2 + if (GL.getCapabilities().OpenGL32) { + return GL32.glFenceSync(condition, flags); + } else { + return ARBSync.glFenceSync(condition, flags); + } } - + @Override public int glClientWaitSync(final Object sync, final int flags, final long timeout) { - return ARBSync.glClientWaitSync((Long) sync, flags, timeout); + // glClientWaitSync is core since OpenGL 3.2 + if (GL.getCapabilities().OpenGL32) { + return GL32.glClientWaitSync((Long) sync, flags, timeout); + } else { + return ARBSync.glClientWaitSync((Long) sync, flags, timeout); + } } @Override public void glDeleteSync(final Object sync) { - ARBSync.glDeleteSync((Long) sync); + // glDeleteSync is core since OpenGL 3.2 + if (GL.getCapabilities().OpenGL32) { + GL32.glDeleteSync((Long) sync); + } else { + ARBSync.glDeleteSync((Long) sync); + } } @Override