From fbe00e6f5dca8043b40dd96f096fecc9424e0cc3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 24 Jan 2014 05:16:05 +0100 Subject: Bug 948 - NVIDIA 331.38 (Linux X11) EGL impl. only supports _one_ EGL Display via eglGetDisplay(..) NVIDIA 331.38 (Linux X11) EGL impl. only supports _one_ EGL Display via eglGetDisplay. - Subsequent eglGetDisplay(..) calls fail. - Using the same 'global' egl-display does work though Remedy: Add 'GLRendererQuirks.SingletonEGLDisplayOnly' Detection of quirk is done as usual in GLContextImpl.setRendererQuirks(..), and EGLDrawableFactory passes the quirk, if detected, down to EGLDisplayUtil. The latter implements the singleton eglDisplay handle. EGLDisplayUtil: Cleaned up .. - EGLDisplayRef employs the reference handling incl. eglInitialize(..) and eglTerminate(), as well as the new singleton quirk. - Mark all internal methods 'private', to remove possible [untested] sideffects. --- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 54 ++++-- .../classes/jogamp/opengl/egl/EGLDisplayUtil.java | 184 ++++++++++++--------- .../jogamp/opengl/egl/EGLDrawableFactory.java | 18 ++ 3 files changed, 167 insertions(+), 89 deletions(-) (limited to 'src/jogl/classes/jogamp/opengl') diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 417dbd011..652fc6ba9 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -1548,7 +1548,9 @@ public abstract class GLContextImpl extends GLContext { final VersionNumberString vendorVersion = GLVersionNumber.createVendorVersion(glVersion); - setRendererQuirks(adevice, reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits, major, minor, ctxProfileBits, vendorVersion, withinGLVersionsMapping); + setRendererQuirks(adevice, getDrawableImpl().getFactoryImpl(), + reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits, + major, minor, ctxProfileBits, vendorVersion, withinGLVersionsMapping); if( strictMatch && glRendererQuirks.exist(GLRendererQuirks.GLNonCompliant) ) { if(DEBUG) { @@ -1665,7 +1667,7 @@ public abstract class GLContextImpl extends GLContext { return true; } - private final void setRendererQuirks(final AbstractGraphicsDevice adevice, + private final void setRendererQuirks(final AbstractGraphicsDevice adevice, final GLDrawableFactoryImpl factory, int reqMajor, int reqMinor, int reqCTP, int major, int minor, int ctp, final VersionNumberString vendorVersion, boolean withinGLVersionsMapping) { @@ -1688,16 +1690,26 @@ public abstract class GLContextImpl extends GLContext { // General Quirks // if( esCtx ) { - final int quirk = GLRendererQuirks.GLES3ViaEGLES2Config; - if( GLRendererQuirks.existStickyDeviceQuirk( GLDrawableFactory.getEGLFactory().getDefaultDevice(), GLRendererQuirks.GLES3ViaEGLES2Config) ) { - // Merge default sticky quirk! + if( 2 == reqMajor && 2 < major ) { + final int quirk = GLRendererQuirks.GLES3ViaEGLES2Config; if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Default EGL Device"); + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major); } quirks[i++] = quirk; - } else if( 2 == reqMajor && 2 < major ) { + if( withinGLVersionsMapping ) { + // Thread safe due to single threaded initialization! + GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); + } else { + // FIXME: Remove when moving EGL/ES to ARB ctx creation + synchronized(GLContextImpl.class) { + GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); + } + } + } + if( isX11 && isDriverNVIDIAGeForce && Platform.CPUFamily.X86 == Platform.getCPUFamily() ) { + final int quirk = GLRendererQuirks.SingletonEGLDisplayOnly; if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major); + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES, X11, CPUFamily AMD/Intel, [Vendor "+glVendor+" or Renderer "+glRenderer+"]"); } quirks[i++] = quirk; if( withinGLVersionsMapping ) { @@ -1794,14 +1806,14 @@ public abstract class GLContextImpl extends GLContext { if( glRenderer.contains("PowerVR") ) { final int quirk = GLRendererQuirks.NoSetSwapInterval; if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer); + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer); } quirks[i++] = quirk; } if( glRenderer.contains("Immersion.16") ) { final int quirk = GLRendererQuirks.GLSharedContextBuggy; if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer); + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer); } quirks[i++] = quirk; } @@ -1906,9 +1918,27 @@ public abstract class GLContextImpl extends GLContext { } glRendererQuirks = new GLRendererQuirks(quirks, 0, i); - GLRendererQuirks.pushStickyDeviceQuirks(adevice, glRendererQuirks); // Thread safe due to single threaded initialization! if(DEBUG) { - System.err.println("Quirks local: "+glRendererQuirks); + System.err.println("Quirks local.0: "+glRendererQuirks); + } + { + // Merge sticky quirks, thread safe due to single threaded initialization! + GLRendererQuirks.pushStickyDeviceQuirks(adevice, glRendererQuirks); + + final AbstractGraphicsDevice factoryDefaultDevice = factory.getDefaultDevice(); + if( !GLRendererQuirks.areSameStickyDevice(factoryDefaultDevice, adevice) ) { + GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, glRendererQuirks); + } + if( esCtx ) { + final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice(); + if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) && + !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) { + GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, glRendererQuirks); + } + } + } + if(DEBUG) { + System.err.println("Quirks local.X: "+glRendererQuirks); System.err.println("Quirks sticky on "+adevice+": "+GLRendererQuirks.getStickyDeviceQuirks(adevice)); } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index a1899e032..c5f76f667 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -49,57 +49,120 @@ import com.jogamp.nativewindow.egl.EGLGraphicsDevice; * and eglTerminate(..) is issued only for the last call. *

* This class is required, due to implementation bugs within EGL where {@link EGL#eglTerminate(long)} - * does not mark the resource for deletion when still in use, bug releases them immediatly. + * does not mark the resource for deletion when still in use, bug releases them immediately. *

*/ public class EGLDisplayUtil { - protected static final boolean DEBUG = Debug.debug("EGLDisplayUtil"); + private static final boolean DEBUG = Debug.debug("EGLDisplayUtil"); + private static boolean useSingletonEGLDisplay = false; + private static EGLDisplayRef singletonEGLDisplay = null; - private static class DpyCounter { + private static class EGLDisplayRef { final long eglDisplay; final Throwable createdStack; - int refCount; + int initRefCount; - private DpyCounter(long eglDisplay) { + /** + * Returns an already opened {@link EGLDisplayRef} or opens a new {@link EGLDisplayRef}. + *

+ * Opened {@link EGLDisplayRef}s are mapped against their eglDisplay handle. + *

+ *

+ * Method utilizes {@link EGLDisplayRef}'s reference counter, i.e. increases it. + *

+ *

+ * An {@link EGLDisplayRef} is opened via {@link EGL#eglInitialize(long, IntBuffer, IntBuffer)}. + *

+ */ + static EGLDisplayRef getOrCreateOpened(final long eglDisplay, final IntBuffer major, final IntBuffer minor) { + EGLDisplayRef o = (EGLDisplayRef) openEGLDisplays.get(eglDisplay); + if( null == o ) { + if( EGL.eglInitialize(eglDisplay, major, minor) ) { + final EGLDisplayRef n = new EGLDisplayRef(eglDisplay); + openEGLDisplays.put(eglDisplay, n); + n.initRefCount++; + if( null == singletonEGLDisplay ) { + singletonEGLDisplay = n; + } + return n; + } else { + return null; + } + } else { + o.initRefCount++; + return o; + } + } + + /** + * Closes an already opened {@link EGLDisplayRef}. + *

+ * Method decreases a reference counter and closes the {@link EGLDisplayRef} if it reaches zero. + *

+ *

+ * An {@link EGLDisplayRef} is closed via {@link EGL#eglTerminate(long)}. + *

+ */ + static EGLDisplayRef closeOpened(final long eglDisplay, final boolean[] res) { + final EGLDisplayRef o = (EGLDisplayRef) openEGLDisplays.get(eglDisplay); + res[0] = true; + if( null != o ) { + if( 0 < o.initRefCount ) { // no negative refCount + o.initRefCount--; + if( 0 == o.initRefCount ) { + res[0] = EGL.eglTerminate(eglDisplay); + if( o == singletonEGLDisplay ) { + singletonEGLDisplay = null; + } + } + } + if( 0 >= o.initRefCount ) { + openEGLDisplays.remove(eglDisplay); + } + } + return o; + } + + private EGLDisplayRef(long eglDisplay) { this.eglDisplay = eglDisplay; - this.refCount = 0; + this.initRefCount = 0; this.createdStack = DEBUG ? new Throwable() : null; } @Override public String toString() { - return "EGLDisplay[0x"+Long.toHexString(eglDisplay)+": refCnt "+refCount+"]"; + return "EGLDisplayRef[0x"+Long.toHexString(eglDisplay)+": refCnt "+initRefCount+"]"; } } - static final LongObjectHashMap eglDisplayCounter; + private static final LongObjectHashMap openEGLDisplays; static { - eglDisplayCounter = new LongObjectHashMap(); - eglDisplayCounter.setKeyNotFoundValue(null); + openEGLDisplays = new LongObjectHashMap(); + openEGLDisplays.setKeyNotFoundValue(null); } /** * @return number of unclosed EGL Displays.
*/ public static int shutdown(boolean verbose) { - if(DEBUG || verbose || eglDisplayCounter.size() > 0 ) { - System.err.println("EGLDisplayUtil.EGLDisplays: Shutdown (open: "+eglDisplayCounter.size()+")"); + if(DEBUG || verbose || openEGLDisplays.size() > 0 ) { + System.err.println("EGLDisplayUtil.EGLDisplays: Shutdown (open: "+openEGLDisplays.size()+")"); if(DEBUG) { Thread.dumpStack(); } - if( eglDisplayCounter.size() > 0) { + if( openEGLDisplays.size() > 0) { dumpOpenDisplayConnections(); } } - return eglDisplayCounter.size(); + return openEGLDisplays.size(); } public static void dumpOpenDisplayConnections() { - System.err.println("EGLDisplayUtil: Open EGL Display Connections: "+eglDisplayCounter.size()); + System.err.println("EGLDisplayUtil: Open EGL Display Connections: "+openEGLDisplays.size()); int i=0; - for(Iterator iter = eglDisplayCounter.iterator(); iter.hasNext(); i++) { + for(Iterator iter = openEGLDisplays.iterator(); iter.hasNext(); i++) { final LongObjectHashMap.Entry e = iter.next(); - final DpyCounter v = (DpyCounter) e.value; + final EGLDisplayRef v = (EGLDisplayRef) e.value; System.err.println("EGLDisplayUtil: Open["+i+"]: 0x"+Long.toHexString(e.key)+": "+v); if(null != v.createdStack) { v.createdStack.printStackTrace(); @@ -107,12 +170,22 @@ public class EGLDisplayUtil { } } - public static long eglGetDisplay(long nativeDisplay_id) { + /* pp */ static synchronized void setSingletonEGLDisplayOnly(boolean v) { useSingletonEGLDisplay = v; } + + private static synchronized long eglGetDisplay(long nativeDisplay_id) { + if( useSingletonEGLDisplay && null != singletonEGLDisplay ) { + if(DEBUG) { + System.err.println("EGLDisplayUtil.eglGetDisplay.s: eglDisplay("+EGLContext.toHexString(nativeDisplay_id)+"): "+ + EGLContext.toHexString(singletonEGLDisplay.eglDisplay)+ + ", "+((EGL.EGL_NO_DISPLAY != singletonEGLDisplay.eglDisplay)?"OK":"Failed")+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); + } + return singletonEGLDisplay.eglDisplay; + } final long eglDisplay = EGL.eglGetDisplay(nativeDisplay_id); if(DEBUG) { - System.err.println("EGLDisplayUtil.eglGetDisplay(): eglDisplay("+EGLContext.toHexString(nativeDisplay_id)+"): "+ + System.err.println("EGLDisplayUtil.eglGetDisplay.X: eglDisplay("+EGLContext.toHexString(nativeDisplay_id)+"): "+ EGLContext.toHexString(eglDisplay)+ - ", "+((EGL.EGL_NO_DISPLAY != eglDisplay)?"OK":"Failed")); + ", "+((EGL.EGL_NO_DISPLAY != eglDisplay)?"OK":"Failed")+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); } return eglDisplay; } @@ -125,39 +198,16 @@ public class EGLDisplayUtil { * * @see EGL#eglInitialize(long, IntBuffer, IntBuffer) */ - public static synchronized boolean eglInitialize(long eglDisplay, IntBuffer major, IntBuffer minor) { + private static synchronized boolean eglInitialize(long eglDisplay, IntBuffer major, IntBuffer minor) { if( EGL.EGL_NO_DISPLAY == eglDisplay) { return false; } - final int refCnt; - final DpyCounter d; - { - DpyCounter _d = (DpyCounter) eglDisplayCounter.get(eglDisplay); - if(null == _d) { - _d = new DpyCounter(eglDisplay); - refCnt = 1; // 1st init - } else { - refCnt = _d.refCount + 1; - } - d = _d; - } - final boolean res; - if(1==refCnt) { // only initialize once - res = EGL.eglInitialize(eglDisplay, major, minor); - } else { - res = true; - } - if(res) { // update refCount and map if successfully initialized, only - d.refCount = refCnt; - if(1 == refCnt) { - eglDisplayCounter.put(eglDisplay, d); - } - } + final EGLDisplayRef d = EGLDisplayRef.getOrCreateOpened(eglDisplay, major, minor); if(DEBUG) { - System.err.println("EGLDisplayUtil.eglInitialize("+EGLContext.toHexString(eglDisplay)+" ...): #"+refCnt+", "+d+" = "+res); + System.err.println("EGLDisplayUtil.eglInitialize("+EGLContext.toHexString(eglDisplay)+" ...): "+d+" = "+(null != d)+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); // Thread.dumpStack(); } - return res; + return null != d; } /** @@ -172,14 +222,14 @@ public class EGLDisplayUtil { * @see #eglGetDisplay(long) * @see #eglInitialize(long, IntBuffer, IntBuffer) */ - public static synchronized int eglGetDisplayAndInitialize(long nativeDisplayID, long[] eglDisplay, int[] eglErr, IntBuffer major, IntBuffer minor) { + private static synchronized int eglGetDisplayAndInitialize(long nativeDisplayID, long[] eglDisplay, int[] eglErr, IntBuffer major, IntBuffer minor) { eglDisplay[0] = EGL.EGL_NO_DISPLAY; - final long _eglDisplay = EGLDisplayUtil.eglGetDisplay( nativeDisplayID ); + final long _eglDisplay = eglGetDisplay( nativeDisplayID ); if ( EGL.EGL_NO_DISPLAY == _eglDisplay ) { eglErr[0] = EGL.eglGetError(); return EGL.EGL_BAD_DISPLAY; } - if ( !EGLDisplayUtil.eglInitialize( _eglDisplay, major, minor) ) { + if ( !eglInitialize( _eglDisplay, major, minor) ) { eglErr[0] = EGL.eglGetError(); return EGL.EGL_NOT_INITIALIZED; } @@ -197,7 +247,7 @@ public class EGLDisplayUtil { * @return the initialized EGL display ID * @throws GLException if not successful */ - public static synchronized long eglGetDisplayAndInitialize(long[] nativeDisplayID) { + private static synchronized long eglGetDisplayAndInitialize(long[] nativeDisplayID) { final long[] eglDisplay = new long[1]; final int[] eglError = new int[1]; int eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(nativeDisplayID[0], eglDisplay, eglError, null, null); @@ -221,40 +271,20 @@ public class EGLDisplayUtil { * @param eglDisplay the EGL display handle * @return true if the eglDisplay is valid and it's reference counter becomes zero and {@link EGL#eglTerminate(long)} was successful, otherwise false */ - public static synchronized boolean eglTerminate(long eglDisplay) { + private static synchronized boolean eglTerminate(long eglDisplay) { if( EGL.EGL_NO_DISPLAY == eglDisplay) { return false; } - final boolean res; - final int refCnt; - final DpyCounter d; - { - DpyCounter _d = (DpyCounter) eglDisplayCounter.get(eglDisplay); - if(null == _d) { - _d = null; - refCnt = -1; // n/a - } else { - refCnt = _d.refCount - 1; // 1 - 1 = 0 -> final terminate - } - d = _d; - } - if( 0 == refCnt ) { // no terminate if still in use or already terminated - res = EGL.eglTerminate(eglDisplay); - eglDisplayCounter.remove(eglDisplay); - } else { - if(0 < refCnt) { // no negative refCount - d.refCount = refCnt; - } - res = true; - } + final boolean[] res = new boolean[1]; + final EGLDisplayRef d = EGLDisplayRef.closeOpened(eglDisplay, res); if(DEBUG) { - System.err.println("EGLDisplayUtil.eglTerminate("+EGLContext.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res); + System.err.println("EGLDisplayUtil.eglTerminate.X("+EGLContext.toHexString(eglDisplay)+" ...): "+d+" = "+res[0]+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); // Thread.dumpStack(); } - return res; + return res[0]; } - public static final EGLGraphicsDevice.EGLDisplayLifecycleCallback eglLifecycleCallback = new EGLGraphicsDevice.EGLDisplayLifecycleCallback() { + private static final EGLGraphicsDevice.EGLDisplayLifecycleCallback eglLifecycleCallback = new EGLGraphicsDevice.EGLDisplayLifecycleCallback() { @Override public long eglGetAndInitDisplay(long[] nativeDisplayID) { return eglGetDisplayAndInitialize(nativeDisplayID); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 3651d71a9..65ce98e07 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -361,6 +361,13 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return new ArrayList(0); } + private static void dumpEGLInfo(final String prefix, final long eglDisplay) { + final String eglVendor = EGL.eglQueryString(eglDisplay, EGL.EGL_VENDOR); + final String eglClientAPIs = EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS); + final String eglVersion = EGL.eglQueryString(eglDisplay, EGL.EGL_VERSION); + System.err.println(prefix+"EGL vendor "+eglVendor+", version "+eglVersion+", clientAPIs "+eglClientAPIs); + } + private boolean mapAvailableEGLESConfig(AbstractGraphicsDevice adevice, int[] esProfile, boolean[] hasPBuffer, GLRendererQuirks[] rendererQuirks, int[] ctp) { final String profileString; @@ -404,6 +411,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { // In this branch, any non EGL device is mapped to EGL default shared resources (default behavior). // Only one default shared resource instance is ever be created. defaultDevice.open(); + if( DEBUG ) { + dumpEGLInfo("EGLDrawableFactory.mapAvailableEGLESConfig: ", defaultDevice.getHandle()); + } + final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); final List availablePBufferCapsL = getAvailableEGLConfigs(defaultDevice, reqCapsPBuffer); hasPBuffer[0] = availablePBufferCapsL.size() > 0; @@ -475,6 +486,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { surface = upstreamSurface; eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(surface); eglDevice.open(); + if( DEBUG ) { + dumpEGLInfo("EGLDrawableFactory.mapAvailableEGLESConfig: ", eglDevice.getHandle()); + } hasPBuffer[0] = true; } @@ -533,6 +547,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } } } + if( null != rendererQuirks[0] && rendererQuirks[0].exist(GLRendererQuirks.SingletonEGLDisplayOnly) ) { + EGLDisplayUtil.setSingletonEGLDisplayOnly(true); + } + return success; } -- cgit v1.2.3