From e674f4fa0e795bd67335025123f9af727d856f7d Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 22 Nov 2019 17:10:58 +0100 Subject: Bug 1156: Utilize internal glGetStringi (same as glGetString) - Robostness Using EGL-GBM, using desktop GL we end up with an unsatisfied linkage error after the ProcAddressTable has been reset using the 'hasMajor' and 'hasCtxOptions'. However looking up using 'reqMajor' and 'reqCtxOptions' seems to work. Needs more analysis. This change also increases robustness for scanning through GL profiles at initialization. --- .../jogamp/opengl/ExtensionAvailabilityCache.java | 29 ++-- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 182 +++++++++++++-------- src/jogl/native/GLContext.c | 17 ++ 3 files changed, 147 insertions(+), 81 deletions(-) diff --git a/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java b/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java index b28b79418..79ceeaf7a 100644 --- a/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java +++ b/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java @@ -46,7 +46,7 @@ import java.util.StringTokenizer; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES3; import com.jogamp.opengl.GLContext; - +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.VersionNumber; /** @@ -140,7 +140,7 @@ final class ExtensionAvailabilityCache { // Use 'glGetStringi' only for ARB GL3 and ES3 context, // on GL2 platforms the function might be available, but not working. if ( context.isGL3() || context.isGLES3() ) { - if ( ! context.isFunctionAvailable("glGetStringi") ) { + if ( ! context.has_glGetStringiInt() ) { if(DEBUG) { System.err.println("GLContext: GL >= 3.1 usage, but no glGetStringi"); } @@ -155,23 +155,26 @@ final class ExtensionAvailabilityCache { } if(useGetStringi) { - final GL2ES3 gl2es3 = (GL2ES3)gl; // validated via context - OK! final int count; { final int[] val = { 0 } ; - gl2es3.glGetIntegerv(GL2ES3.GL_NUM_EXTENSIONS, val, 0); + context.glGetIntegervInt(GL2ES3.GL_NUM_EXTENSIONS, val, 0); count = val[0]; } final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) { - final String ext = gl2es3.glGetStringi(GL.GL_EXTENSIONS, i); - if( null == availableExtensionCache.put(ext, ext) ) { - // new one - if( 0 < i ) { - sb.append(" "); + try { + for (int i = 0; i < count; i++) { + final String ext = context.glGetStringiInt(GL.GL_EXTENSIONS, i); + if( null == availableExtensionCache.put(ext, ext) ) { + // new one + if( 0 < i ) { + sb.append(" "); + } + sb.append(ext); } - sb.append(ext); } + } catch (final UnsatisfiedLinkError ule) { + ExceptionUtils.dumpThrowable("glGetStringi native access", ule); } if(0==count || sb.length()==0) { // fall back .. @@ -182,7 +185,7 @@ final class ExtensionAvailabilityCache { } } if(!useGetStringi) { - glExtensions = gl.glGetString(GL.GL_EXTENSIONS); + glExtensions = context.glGetStringInt(GL.GL_EXTENSIONS); if(null != glExtensions) { final StringTokenizer tok = new StringTokenizer(glExtensions); int count = 0; @@ -223,7 +226,7 @@ final class ExtensionAvailabilityCache { if (DEBUG) { System.err.println(getThreadName() + ":ExtensionAvailabilityCache: GLX_EXTENSIONS: "+glXExtensionCount); - System.err.println(getThreadName() + ":ExtensionAvailabilityCache: GL vendor: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println(getThreadName() + ":ExtensionAvailabilityCache: GL vendor: " + context.glGetStringInt(GL.GL_VENDOR)); System.err.println(getThreadName() + ":ExtensionAvailabilityCache: ALL EXTENSIONS: "+availableExtensionCache.size()); } diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 0b1214720..b3625507e 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -107,6 +107,7 @@ public abstract class GLContextImpl extends GLContext { private boolean glGetPtrInit = false; private long glGetStringPtr = 0; private long glGetIntegervPtr = 0; + private long glGetStringiPtr = 0; // Tracks lifecycle of buffer objects to avoid // repeated glGet calls upon glMapBuffer operations @@ -208,6 +209,7 @@ public abstract class GLContextImpl extends GLContext { glGetPtrInit = false; glGetStringPtr = 0; glGetIntegervPtr = 0; + glGetStringiPtr = 0; if ( !isInit && null != boundFBOTarget ) { // : boundFBOTarget is not written yet boundFBOTarget[0] = 0; // draw @@ -1460,7 +1462,7 @@ public abstract class GLContextImpl extends GLContext { if(useGL) { ctxGLSLVersion = VersionNumber.zeroVersion; if( hasGLSL() ) { // >= ES2 || GL2.0 - final String glslVersion = isGLES() ? null : gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION) ; // Use static GLSL version for ES to be safe! + final String glslVersion = isGLES() ? null : glGetStringInt(GL2ES2.GL_SHADING_LANGUAGE_VERSION) ; // Use static GLSL version for ES to be safe! if( null != glslVersion ) { ctxGLSLVersion = new VersionNumber(glslVersion); if( ctxGLSLVersion.getMajor() < 1 ) { @@ -1607,65 +1609,39 @@ public abstract class GLContextImpl extends GLContext { protected abstract void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh); private final boolean initGLRendererAndGLVersionStrings(final int majorVersion, final int contextOptions) { - if( !glGetPtrInit ) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - final GLDynamicLookupHelper glDynLookupHelper = getGLDynamicLookupHelper(majorVersion, contextOptions); - if( null != glDynLookupHelper ) { - glDynLookupHelper.claimAllLinkPermission(); - try { - glGetStringPtr = glDynLookupHelper.dynamicLookupFunction("glGetString"); - glGetIntegervPtr = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv"); - } finally { - glDynLookupHelper.releaseAllLinkPermission(); - } - } - return null; - } } ); - glGetPtrInit = true; - } - if( 0 == glGetStringPtr || 0 == glGetIntegervPtr ) { - System.err.println("Error: Could not lookup: glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr)); - if(DEBUG) { - ExceptionUtils.dumpStack(System.err); - } - return false; - } else { - final String _glVendor = glGetStringInt(GL.GL_VENDOR, glGetStringPtr); - if(null == _glVendor) { - if(DEBUG) { - System.err.println("Warning: GL_VENDOR is NULL."); - ExceptionUtils.dumpStack(System.err); - } - return false; - } - glVendor = _glVendor; + final String _glVendor = glGetStringInt(GL.GL_VENDOR); + if(null == _glVendor) { + if(DEBUG) { + System.err.println("Warning: GL_VENDOR is NULL."); + ExceptionUtils.dumpStack(System.err); + } + return false; + } + glVendor = _glVendor; - final String _glRenderer = glGetStringInt(GL.GL_RENDERER, glGetStringPtr); - if(null == _glRenderer) { - if(DEBUG) { - System.err.println("Warning: GL_RENDERER is NULL."); - ExceptionUtils.dumpStack(System.err); - } - return false; - } - glRenderer = _glRenderer; - glRendererLowerCase = glRenderer.toLowerCase(); + final String _glRenderer = glGetStringInt(GL.GL_RENDERER); + if(null == _glRenderer) { + if(DEBUG) { + System.err.println("Warning: GL_RENDERER is NULL."); + ExceptionUtils.dumpStack(System.err); + } + return false; + } + glRenderer = _glRenderer; + glRendererLowerCase = glRenderer.toLowerCase(); - final String _glVersion = glGetStringInt(GL.GL_VERSION, glGetStringPtr); - if(null == _glVersion) { - // FIXME - if(DEBUG) { - System.err.println("Warning: GL_VERSION is NULL."); - ExceptionUtils.dumpStack(System.err); - } - return false; - } - glVersion = _glVersion; + final String _glVersion = glGetStringInt(GL.GL_VERSION); + if(null == _glVersion) { + // FIXME + if(DEBUG) { + System.err.println("Warning: GL_VERSION is NULL."); + ExceptionUtils.dumpStack(System.err); + } + return false; + } + glVersion = _glVersion; - return true; - } + return true; } /** @@ -1678,19 +1654,13 @@ public abstract class GLContextImpl extends GLContext { private final void getGLIntVersion(final int[] glIntMajor, final int[] glIntMinor, final int[] glIntCtxProfileMask) { glIntMajor[0] = 0; // clear glIntMinor[0] = 0; // clear - if( 0 == glGetIntegervPtr ) { - // should not be reached, since initGLRendererAndGLVersionStrings(..)'s failure should abort caller! - throw new InternalError("Not initialized: glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr)); - } else { - glGetIntegervInt(GL2ES3.GL_MAJOR_VERSION, glIntMajor, 0, glGetIntegervPtr); - glGetIntegervInt(GL2ES3.GL_MINOR_VERSION, glIntMinor, 0, glGetIntegervPtr); - if( null != glIntCtxProfileMask ) { - glGetIntegervInt(GL3.GL_CONTEXT_PROFILE_MASK, glIntCtxProfileMask, 0, glGetIntegervPtr); - } + glGetIntegervInt(GL2ES3.GL_MAJOR_VERSION, glIntMajor, 0); + glGetIntegervInt(GL2ES3.GL_MINOR_VERSION, glIntMinor, 0); + if( null != glIntCtxProfileMask ) { + glGetIntegervInt(GL3.GL_CONTEXT_PROFILE_MASK, glIntCtxProfileMask, 0); } } - /** * Returns null if version string is invalid, otherwise a valid instance. *

@@ -1776,6 +1746,44 @@ public abstract class GLContextImpl extends GLContext { final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + + if( !glGetPtrInit ) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + final GLDynamicLookupHelper glDynLookupHelper = getGLDynamicLookupHelper(reqMajor, reqCtxProfileBits); + if( null != glDynLookupHelper ) { + glDynLookupHelper.claimAllLinkPermission(); + try { + glGetStringPtr = glDynLookupHelper.dynamicLookupFunction("glGetString"); + glGetIntegervPtr = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv"); + glGetStringiPtr = glDynLookupHelper.dynamicLookupFunction("glGetStringi"); // optional + } finally { + glDynLookupHelper.releaseAllLinkPermission(); + } + } + return null; + } } ); + glGetPtrInit = true; + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: glGetStringi "+toHexString(glGetStringiPtr)+" (opt), glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr)); + } + if( 0 == glGetStringPtr || 0 == glGetIntegervPtr ) { + final String errMsg = "Intialization of glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr)+" failed. "+adevice+" - requested "+ + GLContext.getGLVersion(reqMajor, reqMinor, reqCtxProfileBits, null); + if( strictMatch ) { + // query mode .. simply fail + if(DEBUG) { + System.err.println("Warning: setGLFunctionAvailability: "+errMsg); + } + return false; + } else { + // unusable GL context - non query mode - hard fail! + throw new GLException(errMsg); + } + } + } + final VersionNumber hasGLVersionByString; { final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings(reqMajor, reqCtxProfileBits); @@ -2960,7 +2968,45 @@ public abstract class GLContextImpl extends GLContext { } } - /** Internal bootstraping glGetString(GL_RENDERER) */ + /* pp */ final String glGetStringiInt(final int name, final int index) { + if( 0 == glGetStringiPtr ) { + // should not be reached, since initGLRendererAndGLVersionStrings(..)'s failure should abort caller! + throw new InternalError("Not initialized: glGetStringiPtr "+toHexString(glGetStringiPtr)); + } + return glGetStringiInt(name, index, glGetStringiPtr); + } + /* pp */ final boolean has_glGetStringiInt() { return 0 != glGetStringiPtr; } + + /* pp */ final String glGetStringInt(final int name) { + if( 0 == glGetStringPtr ) { + // should not be reached, since initGLRendererAndGLVersionStrings(..)'s failure should abort caller! + throw new InternalError("Not initialized: glGetStringPtr "+toHexString(glGetStringPtr)); + } + return glGetStringInt(name, glGetStringPtr); + } + + /* pp */ final void glGetIntegervInt(final int pname, final int[] params, final int params_offset) { + if( 0 == glGetIntegervPtr ) { + // should not be reached, since initGLRendererAndGLVersionStrings(..)'s failure should abort caller! + throw new InternalError("Not initialized: glGetIntegerv "+toHexString(glGetIntegervPtr)); + } + glGetIntegervInt(pname, params, params_offset, glGetIntegervPtr); + } + + /** + * Internal bootstraping glGetString(GL_RENDERER). + *

+ * Entry point to C language function: const GLubyte * {@native glGetStringi}(GLenum name, GLuint index)
Part of GL_ES_VERSION_3_0, GL_VERSION_3_0
+ *

+ **/ + private static native String glGetStringiInt(int name, int index, long procAddress); + + /** + * Internal bootstraping glGetString(GL_RENDERER). + *

+ * Entry point to C language function: const GLubyte * {@native glGetString}(GLenum name)
Part of GL_ES_VERSION_2_0, GL_VERSION_ES_CL_CM, GL_VERSION_1_0
+ *

+ */ private static native String glGetStringInt(int name, long procAddress); /** Internal bootstraping glGetIntegerv(..) for version */ diff --git a/src/jogl/native/GLContext.c b/src/jogl/native/GLContext.c index 9be9f82af..e1fbb796f 100644 --- a/src/jogl/native/GLContext.c +++ b/src/jogl/native/GLContext.c @@ -5,6 +5,23 @@ #include #include +/* + * Class: jogamp_opengl_GLContextImpl + * Method: glGetStringiInt + * Signature: (IIJ)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_jogamp_opengl_GLContextImpl_glGetStringiInt(JNIEnv *env, jclass _unused, jint name, jint index, jlong procAddress) { + typedef const khronos_uint8_t * (KHRONOS_APIENTRY*_local_PFNGLGETSTRINGIPROC)(unsigned int name, unsigned int index); + _local_PFNGLGETSTRINGIPROC ptr_glGetStringi; + const khronos_uint8_t * _res; + ptr_glGetStringi = (_local_PFNGLGETSTRINGIPROC) (intptr_t) procAddress; + assert(ptr_glGetStringi != NULL); + _res = (* ptr_glGetStringi) ((unsigned int) name, (unsigned int)index); + if (NULL == _res) return NULL; + return (*env)->NewStringUTF(env, (const char *)_res); +} + /* * Class: jogamp_opengl_GLContextImpl * Method: glGetStringInt -- cgit v1.2.3