aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java337
1 files changed, 271 insertions, 66 deletions
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java
index e09400c09..c5f76f667 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java
@@ -3,14 +3,14 @@
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
@@ -20,7 +20,7 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
@@ -29,105 +29,310 @@
package jogamp.opengl.egl;
import java.nio.IntBuffer;
+import java.util.Iterator;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.ToolkitLock;
+import javax.media.opengl.GLException;
import jogamp.opengl.Debug;
-import com.jogamp.common.util.LongIntHashMap;
+import com.jogamp.common.util.LongObjectHashMap;
+import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
-/**
- * This implementation provides recursive calls to
+/**
+ * This implementation provides recursive calls to
* {@link EGL#eglInitialize(long, IntBuffer, IntBuffer)} and {@link EGL#eglTerminate(long)},
* where <code>eglInitialize(..)</code> is issued only for the 1st call per <code>eglDisplay</code>
* and <code>eglTerminate(..)</code> is issued only for the last call.
* <p>
* 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.
* </p>
*/
public class EGLDisplayUtil {
- protected static final boolean DEBUG = Debug.debug("EGL");
-
- static LongIntHashMap eglDisplayCounter;
-
+ private static final boolean DEBUG = Debug.debug("EGLDisplayUtil");
+ private static boolean useSingletonEGLDisplay = false;
+ private static EGLDisplayRef singletonEGLDisplay = null;
+
+ private static class EGLDisplayRef {
+ final long eglDisplay;
+ final Throwable createdStack;
+ int initRefCount;
+
+ /**
+ * Returns an already opened {@link EGLDisplayRef} or opens a new {@link EGLDisplayRef}.
+ * <p>
+ * Opened {@link EGLDisplayRef}s are mapped against their <code>eglDisplay</code> handle.
+ * </p>
+ * <p>
+ * Method utilizes {@link EGLDisplayRef}'s reference counter, i.e. increases it.
+ * </p>
+ * <p>
+ * An {@link EGLDisplayRef} is <i>opened</i> via {@link EGL#eglInitialize(long, IntBuffer, IntBuffer)}.
+ * </p>
+ */
+ 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}.
+ * <p>
+ * Method decreases a reference counter and closes the {@link EGLDisplayRef} if it reaches zero.
+ * </p>
+ * <p>
+ * An {@link EGLDisplayRef} is <i>closed</i> via {@link EGL#eglTerminate(long)}.
+ * </p>
+ */
+ 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.initRefCount = 0;
+ this.createdStack = DEBUG ? new Throwable() : null;
+ }
+
+ @Override
+ public String toString() {
+ return "EGLDisplayRef[0x"+Long.toHexString(eglDisplay)+": refCnt "+initRefCount+"]";
+ }
+ }
+ private static final LongObjectHashMap openEGLDisplays;
+
static {
- eglDisplayCounter = new LongIntHashMap();
- eglDisplayCounter.setKeyNotFoundValue(0);
+ openEGLDisplays = new LongObjectHashMap();
+ openEGLDisplays.setKeyNotFoundValue(null);
+ }
+
+ /**
+ * @return number of unclosed EGL Displays.<br>
+ */
+ public static int shutdown(boolean verbose) {
+ if(DEBUG || verbose || openEGLDisplays.size() > 0 ) {
+ System.err.println("EGLDisplayUtil.EGLDisplays: Shutdown (open: "+openEGLDisplays.size()+")");
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ if( openEGLDisplays.size() > 0) {
+ dumpOpenDisplayConnections();
+ }
+ }
+ return openEGLDisplays.size();
+ }
+
+ public static void dumpOpenDisplayConnections() {
+ System.err.println("EGLDisplayUtil: Open EGL Display Connections: "+openEGLDisplays.size());
+ int i=0;
+ for(Iterator<LongObjectHashMap.Entry> iter = openEGLDisplays.iterator(); iter.hasNext(); i++) {
+ final LongObjectHashMap.Entry e = iter.next();
+ 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();
+ }
+ }
}
- 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;
}
-
- public static long eglGetDisplay(NativeSurface surface, boolean allowFallBackToDefault) {
- final long nDisplay;
- if( NativeWindowFactory.TYPE_WINDOWS.equals(NativeWindowFactory.getNativeWindowType(false)) ) {
- nDisplay = surface.getSurfaceHandle(); // don't even ask ..
- } else {
- nDisplay = surface.getDisplayHandle(); // 0 == EGL.EGL_DEFAULT_DISPLAY
+
+ /**
+ * @param eglDisplay
+ * @param major
+ * @param minor
+ * @return true if the eglDisplay is valid and it's reference counter becomes one and {@link EGL#eglInitialize(long, IntBuffer, IntBuffer)} was successful, otherwise false
+ *
+ * @see EGL#eglInitialize(long, IntBuffer, IntBuffer)
+ */
+ private static synchronized boolean eglInitialize(long eglDisplay, IntBuffer major, IntBuffer minor) {
+ if( EGL.EGL_NO_DISPLAY == eglDisplay) {
+ return false;
+ }
+ final EGLDisplayRef d = EGLDisplayRef.getOrCreateOpened(eglDisplay, major, minor);
+ if(DEBUG) {
+ System.err.println("EGLDisplayUtil.eglInitialize("+EGLContext.toHexString(eglDisplay)+" ...): "+d+" = "+(null != d)+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")");
+ // Thread.dumpStack();
+ }
+ return null != d;
+ }
+
+ /**
+ * @param nativeDisplayID
+ * @param eglDisplay array of size 1 holding return value if successful, otherwise {@link EGL#EGL_NO_DISPLAY}.
+ * @param eglErr array of size 1 holding the EGL error value as retrieved by {@link EGL#eglGetError()} if not successful.
+ * @param major
+ * @param minor
+ * @return {@link EGL#EGL_SUCCESS} if successful, otherwise {@link EGL#EGL_BAD_DISPLAY} if {@link #eglGetDisplay(long)} failed
+ * or {@link EGL#EGL_NOT_INITIALIZED} if {@link #eglInitialize(long, IntBuffer, IntBuffer)} failed.
+ *
+ * @see #eglGetDisplay(long)
+ * @see #eglInitialize(long, IntBuffer, IntBuffer)
+ */
+ private static synchronized int eglGetDisplayAndInitialize(long nativeDisplayID, long[] eglDisplay, int[] eglErr, IntBuffer major, IntBuffer minor) {
+ eglDisplay[0] = EGL.EGL_NO_DISPLAY;
+ final long _eglDisplay = eglGetDisplay( nativeDisplayID );
+ if ( EGL.EGL_NO_DISPLAY == _eglDisplay ) {
+ eglErr[0] = EGL.eglGetError();
+ return EGL.EGL_BAD_DISPLAY;
}
- long eglDisplay = EGLDisplayUtil.eglGetDisplay(nDisplay);
- if (eglDisplay == EGL.EGL_NO_DISPLAY && nDisplay != EGL.EGL_DEFAULT_DISPLAY && allowFallBackToDefault) {
+ if ( !eglInitialize( _eglDisplay, major, minor) ) {
+ eglErr[0] = EGL.eglGetError();
+ return EGL.EGL_NOT_INITIALIZED;
+ }
+ eglDisplay[0] = _eglDisplay;
+ return EGL.EGL_SUCCESS;
+ }
+
+ /**
+ * Attempts to {@link #eglGetDisplayAndInitialize(long, long[], int[], IntBuffer, IntBuffer)} with given <code>nativeDisplayID</code>.
+ * If this fails, method retries with <code>nativeDisplayID</code> {@link EGL#EGL_DEFAULT_DISPLAY} - the fallback mechanism.
+ * The actual used <code>nativeDisplayID</code> is returned in it's in/out array.
+ *
+ * @throws GLException if {@link EGL#eglGetDisplay(long)} or {@link EGL#eglInitialize(long, int[], int, int[], int)} fails incl fallback
+ * @param nativeDisplayID in/out array of size 1, passing the requested nativeVisualID, may return a different revised nativeVisualID handle
+ * @return the initialized EGL display ID
+ * @throws GLException if not successful
+ */
+ 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);
+ if( EGL.EGL_SUCCESS == eglRes ) {
+ return eglDisplay[0];
+ }
+ if( EGL.EGL_DEFAULT_DISPLAY != nativeDisplayID[0] ) { // fallback to DEGAULT_DISPLAY
if(DEBUG) {
- System.err.println("EGLDisplayUtil.eglGetDisplay(): Fall back to EGL_DEFAULT_DISPLAY");
+ System.err.println("EGLDisplayUtil.eglGetAndInitDisplay failed with native "+EGLContext.toHexString(nativeDisplayID[0])+", error "+EGLContext.toHexString(eglRes)+"/"+EGLContext.toHexString(eglError[0])+" - fallback!");
+ }
+ eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(EGL.EGL_DEFAULT_DISPLAY, eglDisplay, eglError, null, null);
+ if( EGL.EGL_SUCCESS == eglRes ) {
+ nativeDisplayID[0] = EGL.EGL_DEFAULT_DISPLAY;
+ return eglDisplay[0];
}
- eglDisplay = EGLDisplayUtil.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY);
}
- return eglDisplay;
+ throw new GLException("Failed to created/initialize EGL display incl. fallback default: native "+EGLContext.toHexString(nativeDisplayID[0])+", error "+EGLContext.toHexString(eglRes)+"/"+EGLContext.toHexString(eglError[0]));
}
-
- public static synchronized boolean eglInitialize(long eglDisplay, int[] major, int major_offset, int[] minor, int minor_offset) {
- final boolean res;
- final int refCnt = eglDisplayCounter.get(eglDisplay) + 1; // 0 + 1 = 1 -> 1st init
- if(1==refCnt) {
- res = EGL.eglInitialize(eglDisplay, major, major_offset, minor, minor_offset);
- } else {
- res = true;
+
+ /**
+ * @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
+ */
+ private static synchronized boolean eglTerminate(long eglDisplay) {
+ if( EGL.EGL_NO_DISPLAY == eglDisplay) {
+ return false;
}
- eglDisplayCounter.put(eglDisplay, refCnt);
+ final boolean[] res = new boolean[1];
+ final EGLDisplayRef d = EGLDisplayRef.closeOpened(eglDisplay, res);
if(DEBUG) {
- System.err.println("EGL.eglInitialize(0x"+Long.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 synchronized boolean eglInitialize(long eglDisplay, IntBuffer major, IntBuffer minor) {
- final boolean res;
- final int refCnt = eglDisplayCounter.get(eglDisplay) + 1; // 0 + 1 = 1 -> 1st init
- if(1==refCnt) { // only initialize once
- res = EGL.eglInitialize(eglDisplay, major, minor);
- } else {
- res = true;
+
+ private static final EGLGraphicsDevice.EGLDisplayLifecycleCallback eglLifecycleCallback = new EGLGraphicsDevice.EGLDisplayLifecycleCallback() {
+ @Override
+ public long eglGetAndInitDisplay(long[] nativeDisplayID) {
+ return eglGetDisplayAndInitialize(nativeDisplayID);
}
- eglDisplayCounter.put(eglDisplay, refCnt);
- if(DEBUG) {
- System.err.println("EGL.eglInitialize(0x"+Long.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res);
+ @Override
+ public void eglTerminate(long eglDisplayHandle) {
+ EGLDisplayUtil.eglTerminate(eglDisplayHandle);
}
- return res;
+ };
+
+ /**
+ * Returns an uninitialized {@link EGLGraphicsDevice}. User needs to issue {@link EGLGraphicsDevice#open()} before usage.
+ * <p>
+ * Using {@link #eglGetDisplayAndInitialize(long[])} for the {@link EGLGraphicsDevice#open()} implementation
+ * and {@link #eglTerminate(long)} for {@link EGLGraphicsDevice#close()}.
+ * </p>
+ * <p>
+ * Using the default {@link ToolkitLock}, via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
+ * </p>
+ * @param nativeDisplayID
+ * @param connection
+ * @param unitID
+ * @return an uninitialized {@link EGLGraphicsDevice}
+ */
+ public static EGLGraphicsDevice eglCreateEGLGraphicsDevice(long nativeDisplayID, String connection, int unitID) {
+ return new EGLGraphicsDevice(nativeDisplayID, EGL.EGL_NO_DISPLAY, connection, unitID, eglLifecycleCallback);
}
-
- public static synchronized boolean eglTerminate(long eglDisplay) {
- final boolean res;
- final int refCnt = eglDisplayCounter.get(eglDisplay) - 1; // 1 - 1 = 0 -> final terminate
- if(0==refCnt) { // no terminate if still in use or already terminated
- res = EGL.eglTerminate(eglDisplay);
+
+ /**
+ * Returns an uninitialized {@link EGLGraphicsDevice}. User needs to issue {@link EGLGraphicsDevice#open()} before usage.
+ * <p>
+ * Using {@link #eglGetDisplayAndInitialize(long[])} for the {@link EGLGraphicsDevice#open()} implementation
+ * and {@link #eglTerminate(long)} for {@link EGLGraphicsDevice#close()}.
+ * </p>
+ * <p>
+ * Using the default {@link ToolkitLock}, via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
+ * </p>
+ * @param surface
+ * @return an uninitialized EGLGraphicsDevice
+ */
+ public static EGLGraphicsDevice eglCreateEGLGraphicsDevice(NativeSurface surface) {
+ final long nativeDisplayID;
+ if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) ) {
+ nativeDisplayID = surface.getSurfaceHandle(); // don't even ask ..
} else {
- res = true;
- }
- if(0<=refCnt) { // no negative refCount
- eglDisplayCounter.put(eglDisplay, refCnt);
- }
- if(DEBUG) {
- System.err.println("EGL.eglTerminate(0x"+Long.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res);
+ nativeDisplayID = surface.getDisplayHandle(); // 0 == EGL.EGL_DEFAULT_DISPLAY
}
- return res;
+ final AbstractGraphicsDevice adevice = surface.getGraphicsConfiguration().getScreen().getDevice();
+ return new EGLGraphicsDevice(nativeDisplayID, EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), eglLifecycleCallback);
}
}