diff options
author | Sven Gothel <[email protected]> | 2012-11-08 18:07:19 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-11-08 18:07:19 +0100 |
commit | d0f91a8ed17fbb1a7b56511c4e53a29e576f01af (patch) | |
tree | 3e3f906f794ba1abe340190a4dfac12dadf5c921 | |
parent | 9ce042df68b70a0e62b21b93d2a1a64722e1e49e (diff) |
Fix GLAutoDrawable.dispose(): Dispose drawable even w/o context; JAWTWindow.lockSurface(): Check AWT component's native peer
- Fix GLAutoDrawable.dispose(): Dispose drawable even w/o context
- It is possible to have the GLContext not being created (not made current),
so drawable shall be disposed independent.
- Merge Runnable 'postDisposeOnEDTAction' to dispose Runnable for clarity
- GLDrawableHelper: Split disposeGL from invokeGLImpl for clarity
- JAWTWindow.lockSurface(): Check AWT component's native peer
- W/o a native peer (!isDisplayable()), JAWT locking cannot succeed.
- On OSX OpenJDK 1.7, attempting to JAWT lock a peer-less component crashes the VM
- MacOSXJAWTWindow.lockSurfaceImpl(): Remove redundant null checks
11 files changed, 355 insertions, 280 deletions
diff --git a/make/scripts/tests-osx-x64-custom.sh b/make/scripts/tests-osx-x64-custom.sh new file mode 100755 index 000000000..88587f086 --- /dev/null +++ b/make/scripts/tests-osx-x64-custom.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH + +spath=`dirname $0` + +. $spath/tests.sh "`which java`" -d64 ../build-macosx $* + + diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index e746f5e4c..3add0371f 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -5,15 +5,15 @@ if [ -z "$1" -o -z "$2" -o -z "$3" ] ; then exit 0 fi -javaexe=$1 +javaexe="$1" shift javaxargs=$1 shift bdir=$1 shift -if [ ! -x $javaexe ] ; then - echo java-exe $javaexe is not an executable +if [ ! -x "$javaexe" ] ; then + echo java-exe "$javaexe" is not an executable exit 1 fi if [ ! -d $bdir ] ; then @@ -42,15 +42,15 @@ if [ $MOSX -eq 1 ] ; then MOSX_MT=1 fi -which $javaexe 2>&1 | tee -a java-run.log -$javaexe -version 2>&1 | tee -a java-run.log +which "$javaexe" 2>&1 | tee -a java-run.log +"$javaexe" -version 2>&1 | tee -a java-run.log echo LIBXCB_ALLOW_SLOPPY_LOCK: $LIBXCB_ALLOW_SLOPPY_LOCK 2>&1 | tee -a java-run.log echo LIBGL_DRIVERS_PATH: $LIBGL_DRIVERS_PATH 2>&1 | tee -a java-run.log echo LIBGL_DEBUG: $LIBGL_DEBUG 2>&1 | tee -a java-run.log echo LIBGL_ALWAYS_INDIRECT: $LIBGL_ALWAYS_INDIRECT 2>&1 | tee -a java-run.log echo LIBGL_ALWAYS_SOFTWARE: $LIBGL_ALWAYS_SOFTWARE 2>&1 | tee -a java-run.log echo SWT_CLASSPATH: $SWT_CLASSPATH 2>&1 | tee -a java-run.log -echo $javaexe $javaxargs $X_ARGS $D_ARGS $* 2>&1 | tee -a java-run.log +echo "$javaexe" $javaxargs $X_ARGS $D_ARGS $* 2>&1 | tee -a java-run.log echo MacOsX $MOSX function jrun() { @@ -209,13 +209,13 @@ function jrun() { echo echo LD_LIBRARY_PATH $LD_LIBRARY_PATH echo - echo $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* + echo "$javaexe" $javaxargs $X_ARGS $D_ARGS $C_ARG $* #LIBGL_DRIVERS_PATH=/usr/lib/mesa:/usr/lib32/mesa \ #LIBGL_DEBUG=verbose INTEL_STRICT_CONFORMANCE=1 INTEL_DEBUG="buf bat" \ #LIBGL_DEBUG=verbose MESA_DEBUG=true INTEL_STRICT_CONFORMANCE=1 \ #export LIBGL_DEBUG=verbose MESA_DEBUG=true LIBGL_ALWAYS_SOFTWARE=true - #gdb --args $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* - $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* + #gdb --args "$javaexe" $javaxargs $X_ARGS $D_ARGS $C_ARG $* + "$javaexe" $javaxargs $X_ARGS $D_ARGS $C_ARG $* echo echo "Test End: $*" echo @@ -266,7 +266,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestPointsNEWT $* @@ -285,6 +285,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOf #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1DemoES2NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMRTNEWT01 $* + #testawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableDeadlockAWT $* #testawt com.jogamp.opengl.test.junit.jogl.awt.TestBug461FBOSupersamplingSwingAWT #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* @@ -351,7 +352,7 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOf #testawt com.jogamp.opengl.test.junit.jogl.glu.TestBug463ScaleImageMemoryAWT $* #testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWTCardLayoutAnimatorStartStopBug532 $* #testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock00AWT $* -#testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock01AWT $* +testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock01AWT $* #testawt com.jogamp.opengl.test.junit.jogl.awt.TestGLCanvasAWTActionDeadlock02AWT $* # diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 755a7c392..e80079c20 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -173,45 +173,49 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { /* * Disposes of OpenGL resources */ - private final Runnable postDisposeGLAction = new Runnable() { - @Override - public void run() { - context = null; - if (null != drawable) { - drawable.setRealized(false); - drawable = null; - } - } - }; - private final Runnable disposeOnEDTGLAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; _lock.lock(); try { - if (null != drawable && null != context) { - boolean animatorPaused = false; - final GLAnimatorControl animator = getAnimator(); - if (null != animator) { - animatorPaused = animator.pause(); - } - - if(context.isCreated()) { - helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); - } - - if (animatorPaused) { - animator.resume(); - } + final GLAnimatorControl animator = getAnimator(); + final boolean animatorPaused; + if(null!=animator) { + // can't remove us from animator for recreational addNotify() + animatorPaused = animator.pause(); + } else { + animatorPaused = false; + } + + if ( null != context ) { + if( context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.disposeGL(GLCanvas.this, context); + } catch (GLException gle) { + gle.printStackTrace(); + } + } + context = null; + } + if ( null != drawable ) { + drawable.setRealized(false); + drawable = null; } // SWT is owner of the device handle, not us. // Hence close() operation is a NOP. if (null != device) { - device.close(); - device = null; + device.close(); + device = null; } SWTAccessor.setRealized(GLCanvas.this, false); // unrealize .. + + if (animatorPaused) { + animator.resume(); + } + } finally { _lock.unlock(); } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 1d8666e6a..a40cdcf88 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -888,33 +888,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // private boolean disposeRegenerate; - private final Runnable postDisposeOnEDTAction = new Runnable() { - @Override - public void run() { - context=null; - if(null!=drawable) { - drawable.setRealized(false); - drawable=null; - if(null!=jawtWindow) { - jawtWindow.destroy(); - jawtWindow=null; - } - } - - if(disposeRegenerate) { - // Similar process as in addNotify()! - - // Recreate GLDrawable/GLContext to reflect it's new graphics configuration - createDrawableAndContext(); - - if(DEBUG) { - System.err.println(getThreadName()+": GLCanvas.dispose(true): new drawable: "+drawable); - } - validateGLDrawable(); // immediate attempt to recreate the drawable - } - } - }; - private final Runnable disposeOnEDTAction = new Runnable() { @Override public void run() { @@ -929,31 +902,64 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing Thread.dumpStack(); } - if(null!=drawable && null!=context) { - boolean animatorPaused = false; - if(null!=animator) { - // can't remove us from animator for recreational addNotify() - animatorPaused = animator.pause(); - } - - if(context.isCreated()) { - helper.disposeGL(GLCanvas.this, drawable, context, postDisposeOnEDTAction); + final boolean animatorPaused; + if(null!=animator) { + // can't remove us from animator for recreational addNotify() + animatorPaused = animator.pause(); + } else { + animatorPaused = false; + } + + if( null != context ) { + if( context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.disposeGL(GLCanvas.this, context); + } catch (GLException gle) { + gle.printStackTrace(); + } + } + context=null; + } + if( null != drawable ) { + drawable.setRealized(false); + if(DEBUG) { + System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - 1: "+drawable); } - - if(animatorPaused) { - animator.resume(); + drawable=null; + } + if( null != jawtWindow ) { + jawtWindow.destroy(); + if(DEBUG) { + System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - 2: "+jawtWindow); } + jawtWindow=null; } - - if(!disposeRegenerate) { + + if(disposeRegenerate) { + // Similar process as in addNotify()! + + // Recreate GLDrawable/GLContext to reflect it's new graphics configuration + createDrawableAndContext(); + + if(DEBUG) { + System.err.println(getThreadName()+": GLCanvas.dispose(true): new drawable: "+drawable); + } + validateGLDrawable(); // immediate attempt to recreate the drawable + } else { if(null != awtConfig) { AWTEDTExecutor.singleton.invoke(getTreeLock(), true, disposeAbstractGraphicsDeviceActionOnEDT); } awtConfig=null; } + if(animatorPaused) { + animator.resume(); + } + if(DEBUG) { - System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - END, "+animator); + System.err.println(getThreadName()+": dispose("+disposeRegenerate+") - END, animator "+animator); } } finally { diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 58b1baa65..dcfc1f0dd 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -757,21 +757,26 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return "AWT-GLJPanel[ "+((null!=backend)?backend.getDrawable().getClass().getName():"null-drawable")+"]"; } - private final Runnable postDisposeAction = new Runnable() { - @Override - public void run() { - if (backend != null && !backend.isUsingOwnThreadManagment()) { - backend.destroy(); - backend = null; - isInitialized = false; - } - } - }; - private final Runnable disposeAction = new Runnable() { @Override public void run() { - helper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); + if ( null != backend ) { + final GLContext _context = backend.getContext(); + if( null != _context && _context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.disposeGL(GLJPanel.this, _context); + } catch (GLException gle) { + gle.printStackTrace(); + } + } + if ( !backend.isUsingOwnThreadManagment() ) { + backend.destroy(); + backend = null; + isInitialized = false; + } + } } }; diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index 7bcd37ecd..68fbe3dd5 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -223,27 +223,26 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { * In such case call <code>super.destroyImplInLock</code> first.</p> */ protected void destroyImplInLock() { - final GLContext _context = context; - final GLDrawable _drawable = drawable; - if( null != _drawable ) { - if( _drawable.isRealized() ) { - if( null != _context && _context.isCreated() ) { - // Catch dispose GLExceptions by GLEventListener, just 'print' them - // so we can continue with the destruction. - try { - helper.disposeGL(this, _drawable, _context, null); - } catch (GLException gle) { - gle.printStackTrace(); - } + if( null != context ) { + if( context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.disposeGL(this, context); + } catch (GLException gle) { + gle.printStackTrace(); } - _drawable.setRealized(false); } + context = null; + } + if( null != drawable ) { + final AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); + drawable.setRealized(false); + drawable = null; if( ownsDevice ) { - _drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice().close(); + device.close(); } - } - context = null; - drawable = null; + } } public final void defaultSwapBuffers() throws GLException { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 36dc933ab..f7f846b05 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -397,8 +397,8 @@ public class GLDrawableHelper { * otherwise maked uninitialized. * </p> * <p> - * Please consider using {@link #disposeAllGLEventListener(GLAutoDrawable, GLDrawable, GLContext)} - * or {@link #disposeGL(GLAutoDrawable, GLDrawable, GLContext, Runnable)} + * Please consider using {@link #disposeAllGLEventListener(GLAutoDrawable, GLContext, boolean)} + * or {@link #disposeGL(GLAutoDrawable, GLContext)} * for correctness, i.e. encapsulating all calls w/ makeCurrent etc. * </p> * @param autoDrawable @@ -483,8 +483,7 @@ public class GLDrawableHelper { * * @param autoDrawable * @param context - * @param listener - * @param initAction + * @param remove */ public final void disposeAllGLEventListener(final GLAutoDrawable autoDrawable, final GLDrawable drawable, @@ -505,29 +504,6 @@ public class GLDrawableHelper { } } - /** - * Principal helper method which runs - * {@link #disposeAllGLEventListener(GLAutoDrawable, boolean) disposeAllGLEventListener(autoDrawable, false)} - * with the context made current <b>and</b> destroys the context afterwards while holding the lock. - * @param autoDrawable - * @param drawable - * @param context - * @param postAction - */ - public final void disposeGL(final GLAutoDrawable autoDrawable, - final GLDrawable drawable, - final GLContext context, - final Runnable postAction) { - if(PERF_STATS) { - invokeGLImplStats(drawable, context, null, null, autoDrawable); - } else { - invokeGLImpl(drawable, context, null, null, autoDrawable); - } - if(null != postAction) { - postAction.run(); - } - } - private final void init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { l.init(drawable); if(sendReshape) { @@ -842,21 +818,66 @@ public class GLDrawableHelper { } if(PERF_STATS) { - invokeGLImplStats(drawable, context, runnable, initAction, null); + invokeGLImplStats(drawable, context, runnable, initAction); } else { - invokeGLImpl(drawable, context, runnable, initAction, null); + invokeGLImpl(drawable, context, runnable, initAction); } } + /** + * Principal helper method which runs + * {@link #disposeAllGLEventListener(GLAutoDrawable, boolean) disposeAllGLEventListener(autoDrawable, false)} + * with the context made current <b>and</b> destroys the context afterwards while holding the lock. + * @param autoDrawable + * @param context + */ + public final void disposeGL(final GLAutoDrawable autoDrawable, + final GLContext context) { + // Support for recursive makeCurrent() calls as well as calling + // other drawables' display() methods from within another one's + GLContext lastContext = GLContext.getCurrent(); + Runnable lastInitAction = null; + if (lastContext != null) { + if (lastContext == context) { + lastContext = null; // utilize recursive locking + } else { + lastInitAction = perThreadInitAction.get(); + lastContext.release(); + } + } + int res = GLContext.CONTEXT_NOT_CURRENT; + + try { + res = context.makeCurrent(); + if (GLContext.CONTEXT_NOT_CURRENT != res) { + if(GLContext.CONTEXT_CURRENT_NEW == res) { + throw new GLException(Thread.currentThread().getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); + } + if( listeners.size() > 0 && null != autoDrawable ) { + disposeAllGLEventListener(autoDrawable, false); + } + } + } finally { + try { + context.destroy(); + flushGLRunnables(); + } catch (Exception e) { + System.err.println("Catched: "+e.getMessage()); + e.printStackTrace(); + } + if (lastContext != null) { + final int res2 = lastContext.makeCurrent(); + if (null != lastInitAction && res2 == GLContext.CONTEXT_CURRENT_NEW) { + lastInitAction.run(); + } + } + } + } + private final void invokeGLImpl(final GLDrawable drawable, final GLContext context, final Runnable runnable, - final Runnable initAction, - final GLAutoDrawable disposeAutoDrawable) { - final Thread currentThread = Thread.currentThread(); - - final boolean isDisposeAction = null==initAction ; - + final Runnable initAction) { // Support for recursive makeCurrent() calls as well as calling // other drawables' display() methods from within another one's GLContext lastContext = GLContext.getCurrent(); @@ -874,35 +895,21 @@ public class GLDrawableHelper { try { res = context.makeCurrent(); if (GLContext.CONTEXT_NOT_CURRENT != res) { - if(!isDisposeAction) { - perThreadInitAction.set(initAction); - if (GLContext.CONTEXT_CURRENT_NEW == res) { - if (DEBUG) { - System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); - } - initAction.run(); - } - runnable.run(); - if (autoSwapBufferMode) { - drawable.swapBuffers(); - } - } else { - if(GLContext.CONTEXT_CURRENT_NEW == res) { - throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); - } - if( listeners.size() > 0 && null != disposeAutoDrawable ) { - disposeAllGLEventListener(disposeAutoDrawable, false); - } + perThreadInitAction.set(initAction); + if (GLContext.CONTEXT_CURRENT_NEW == res) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); + } + initAction.run(); + } + runnable.run(); + if ( autoSwapBufferMode ) { + drawable.swapBuffers(); } } } finally { try { - if(isDisposeAction) { - context.destroy(); - flushGLRunnables(); - } else if( GLContext.CONTEXT_NOT_CURRENT != res ) { - context.release(); - } + context.release(); } catch (Exception e) { System.err.println("Catched: "+e.getMessage()); e.printStackTrace(); @@ -919,12 +926,9 @@ public class GLDrawableHelper { private final void invokeGLImplStats(final GLDrawable drawable, final GLContext context, final Runnable runnable, - final Runnable initAction, - final GLAutoDrawable disposeAutoDrawable) { + final Runnable initAction) { final Thread currentThread = Thread.currentThread(); - final boolean isDisposeAction = null==initAction ; - // Support for recursive makeCurrent() calls as well as calling // other drawables' display() methods from within another one's int res = GLContext.CONTEXT_NOT_CURRENT; @@ -956,41 +960,28 @@ public class GLDrawableHelper { ctxClaimed = true; } if (res != GLContext.CONTEXT_NOT_CURRENT) { - if(!isDisposeAction) { - perThreadInitAction.set(initAction); - if (res == GLContext.CONTEXT_CURRENT_NEW) { - if (DEBUG) { - System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); - } - initAction.run(); - } - tdR = System.currentTimeMillis(); - tdA = tdR - t0; // makeCurrent - runnable.run(); - tdS = System.currentTimeMillis(); - tdR = tdS - tdR; // render time - if (autoSwapBufferMode) { - drawable.swapBuffers(); - tdX = System.currentTimeMillis(); - tdS = tdX - tdS; // swapBuffers - } - } else { - if(res == GLContext.CONTEXT_CURRENT_NEW) { - throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); - } - if( listeners.size() > 0 && null != disposeAutoDrawable ) { - disposeAllGLEventListener(disposeAutoDrawable, false); - } + perThreadInitAction.set(initAction); + if (res == GLContext.CONTEXT_CURRENT_NEW) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); + } + initAction.run(); + } + tdR = System.currentTimeMillis(); + tdA = tdR - t0; // makeCurrent + runnable.run(); + tdS = System.currentTimeMillis(); + tdR = tdS - tdR; // render time + if (autoSwapBufferMode) { + drawable.swapBuffers(); + tdX = System.currentTimeMillis(); + tdS = tdX - tdS; // swapBuffers } } } finally { try { - if(isDisposeAction) { - context.destroy(); - flushGLRunnables(); - ctxDestroyed = true; - } else if( res != GLContext.CONTEXT_NOT_CURRENT && - (null == skipContextReleaseThread || currentThread != skipContextReleaseThread) ) { + if( res != GLContext.CONTEXT_NOT_CURRENT && + (null == skipContextReleaseThread || currentThread != skipContextReleaseThread) ) { context.release(); ctxReleased = true; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 35c919f28..8527a0200 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -320,32 +320,41 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { - determineIfApplet(); - try { - final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); - adevice.lock(); + if( !component.isDisplayable() ) { + // W/o native peer, we cannot utilize JAWT for locking. + surfaceLock.unlock(); + if(DEBUG) { + System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component); + Thread.dumpStack(); + } + } else { + determineIfApplet(); try { - if(null == jawt) { // no need to re-fetch for each frame - jawt = fetchJAWTImpl(); - isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); - } - res = lockSurfaceImpl(); - if(LOCK_SUCCESS == res && drawable_old != drawable) { - res = LOCK_SURFACE_CHANGED; - if(DEBUG) { - System.err.println("JAWTWindow: surface change 0x"+Long.toHexString(drawable_old)+" -> 0x"+Long.toHexString(drawable)); - // Thread.dumpStack(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); + adevice.lock(); + try { + if(null == jawt) { // no need to re-fetch for each frame + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); + } + res = lockSurfaceImpl(); + if(LOCK_SUCCESS == res && drawable_old != drawable) { + res = LOCK_SURFACE_CHANGED; + if(DEBUG) { + System.err.println("JAWTWindow: surface change 0x"+Long.toHexString(drawable_old)+" -> 0x"+Long.toHexString(drawable)); + // Thread.dumpStack(); + } + } + } finally { + if (LOCK_SURFACE_NOT_READY >= res) { + adevice.unlock(); } } } finally { if (LOCK_SURFACE_NOT_READY >= res) { - adevice.unlock(); + surfaceLock.unlock(); } } - } finally { - if (LOCK_SURFACE_NOT_READY >= res) { - surfaceLock.unlock(); - } } } return res; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 5fd242247..449121be1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -119,13 +119,11 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SURFACE_NOT_READY; - if(null == ds) { - ds = getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; } int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; @@ -141,21 +139,19 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { ret = NativeWindow.LOCK_SURFACE_CHANGED; } - if(null == dsi) { - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); - } - if (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + if (firstLock) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + dsi = ds.GetDrawingSurfaceInfo(); + return null; + } + }); + } else { + dsi = ds.GetDrawingSurfaceInfo(); + } + if (dsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; } updateBounds(dsi.getBounds()); if (DEBUG && firstLock ) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock01AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock01AWT.java index c2b6f1551..c51972c39 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock01AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock01AWT.java @@ -33,6 +33,9 @@ import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLCanvas; + +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.VersionNumber; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.util.FPSAnimator; @@ -53,7 +56,21 @@ import org.junit.Assert; import org.junit.Assume; import org.junit.Test; - +/** + * BUG on OSX/CALayer w/ Java6: + * If frame.setTitle() is issued right after initialization the call hangs in + * <pre> + * at apple.awt.CWindow._setTitle(Native Method) + * at apple.awt.CWindow.setTitle(CWindow.java:765) [1.6.0_37, build 1.6.0_37-b06-434-11M3909] + * </pre> + * <p> + * OSX/CALayer is forced by using an Applet component in this unit test. + * </p> + * <p> + * Similar deadlock has been experienced w/ other mutable operation on an AWT Container owning a GLCanvas child, + * e.g. setResizable*(). + * </p> + */ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { static long durationPerTest = 1000; // ms static final int width = 512; @@ -87,6 +104,14 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { public void test02FPSAnimator_RestartOnCurrentThread() throws InterruptedException { testImpl(new FPSAnimator(30), 200, true); } */ + + private static void setFrameTitle(Frame frame, String msg) { + System.err.println("About to setTitle: <"+msg+"> CT "+Thread.currentThread().getName()+", "+ + frame+", displayable "+frame.isDisplayable()+ + ", valid "+frame.isValid()+", visible "+frame.isVisible()); + // Thread.dumpStack(); + frame.setTitle(msg); + } void testImpl(final AnimatorBase animator, int restartPeriod, boolean restartOnCurrentThread) throws InterruptedException { final Frame frame1 = new Frame("Frame 1"); @@ -94,6 +119,13 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { private static final long serialVersionUID = 1L; }; + final VersionNumber version170 = new VersionNumber(1, 7, 0); + final boolean osxCALayerAWTModBug = Platform.OSType.MACOS == Platform.getOSType() && + 0 > Platform.getJavaVersionNumber().compareTo(version170); + System.err.println("OSX CALayer AWT-Mod Bug "+osxCALayerAWTModBug); + System.err.println("OSType "+Platform.getOSType()); + System.err.println("Java Version "+Platform.getJavaVersionNumber()); + Assert.assertNotNull(frame1); frame1.setLayout(null); frame1.pack(); @@ -109,7 +141,7 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { frame1.setLocation(0, 0); frame1.setTitle("Generic Title"); frame1.add(applet1); - + frame1.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(frame1, applet1); @@ -122,34 +154,36 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { @Override public void init(GLAutoDrawable drawable) { justInitialized = true; + if( !osxCALayerAWTModBug ) { + System.err.println("*Init*: CT "+Thread.currentThread().getName()); + setFrameTitle(frame1, "INIT"); + frame1.setResizable(false); + } } @Override public void dispose(GLAutoDrawable drawable) { + System.err.println("*Dispose*: CT "+Thread.currentThread().getName()); + setFrameTitle(frame1, "DISPOSE"); } @Override public void display(GLAutoDrawable drawable) { - if(!justInitialized) { - // BUG on OSX/CALayer: If frame.setTitle() is issued right after initialization - // the call hangs in - // at apple.awt.CWindow._setTitle(Native Method) - // at apple.awt.CWindow.setTitle(CWindow.java:765) [1.6.0_37, build 1.6.0_37-b06-434-11M3909] - // - final String msg = "f "+frameCount+", fps "+( null != animator ? animator.getLastFPS() : 0); - System.err.println("About to setTitle: CT "+Thread.currentThread().getName()+", "+msg+ - frame1+", displayable "+frame1.isDisplayable()+ - ", valid "+frame1.isValid()+", visible "+frame1.isVisible()); - // Thread.dumpStack(); - frame1.setTitle(msg); - + if( !osxCALayerAWTModBug || !justInitialized ) { + System.err.println("*Display*: CT "+Thread.currentThread().getName()); + setFrameTitle(frame1, "f "+frameCount+", fps "+( null != animator ? animator.getLastFPS() : 0)); + frame1.setResizable(false); } frameCount++; - justInitialized=false; + justInitialized = false; } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + if( !osxCALayerAWTModBug || !justInitialized ) { + System.err.println("*Reshape*: CT "+Thread.currentThread().getName()); + setFrameTitle(frame1, "RESHAPE"); + } } }; gle2 = new GearsES2(); @@ -188,7 +222,7 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { glCanvas.display(); } if(0 < restartPeriod) { - glCanvas = restart(frame1, applet1, glCanvas, restartOnCurrentThread); + glCanvas = restart(applet1, glCanvas, restartOnCurrentThread); } Thread.sleep(sleep); @@ -234,7 +268,7 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { } } - GLCanvas restart(final Frame frame, final Applet applet, GLCanvas glCanvas, boolean restartOnCurrentThread) throws InterruptedException { + GLCanvas restart(final Applet applet, GLCanvas glCanvas, boolean restartOnCurrentThread) throws InterruptedException { glCanvas.disposeGLEventListener(gle1, true); glCanvas.disposeGLEventListener(gle2, true); detachGLCanvas(applet, glCanvas, restartOnCurrentThread); @@ -253,7 +287,7 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { if( restartOnCurrentThread ) { applet.setLayout(new BorderLayout()); applet.add(glCanvas, BorderLayout.CENTER); - applet.validate(); + applet.validate(); } else { try { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { @@ -274,7 +308,7 @@ public class TestGLCanvasAWTActionDeadlock01AWT extends UITestCase { System.err.println("*** detachGLCanvas.0 on-current-thread "+restartOnCurrentThread+", currentThread "+Thread.currentThread().getName()); if( restartOnCurrentThread ) { applet.remove(glCanvas); - applet.validate(); + applet.validate(); } else { try { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock02AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock02AWT.java index a74286232..d8f25868b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock02AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestGLCanvasAWTActionDeadlock02AWT.java @@ -53,12 +53,31 @@ import javax.media.opengl.awt.GLCanvas; import org.junit.Assume; import org.junit.Test; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.VersionNumber; import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; -// Sample program that relies on JOGL's mechanism to handle the OpenGL context -// and rendering loop when using an AWT canvas attached to an Applet. +/** + * Sample program that relies on JOGL's mechanism to handle the OpenGL context + * and rendering loop when using an AWT canvas attached to an Applet. + * <p> + * BUG on OSX/CALayer w/ Java6: + * If frame.setTitle() is issued right after initialization the call hangs in + * <pre> + * at apple.awt.CWindow._setTitle(Native Method) + * at apple.awt.CWindow.setTitle(CWindow.java:765) [1.6.0_37, build 1.6.0_37-b06-434-11M3909] + * </pre> + * </p> + * <p> + * OSX/CALayer is forced by using an Applet component in this unit test. + * </p> + * <p> + * Similar deadlock has been experienced w/ other mutable operation on an AWT Container owning a GLCanvas child, + * e.g. setResizable*(). + * </p> + */ public class TestGLCanvasAWTActionDeadlock02AWT extends UITestCase { static int framesPerTest = 240; // frames @@ -109,7 +128,9 @@ public class TestGLCanvasAWTActionDeadlock02AWT extends UITestCase { private long frameRatePeriod = 1000000000L / frameRate; private boolean initialized = false; - + private boolean osxCALayerAWTModBug = false; + boolean justInitialized = true; + private double theta = 0; private double s = 0; private double c = 0; @@ -161,6 +182,13 @@ public class TestGLCanvasAWTActionDeadlock02AWT extends UITestCase { millisOffset = System.currentTimeMillis(); + final VersionNumber version170 = new VersionNumber(1, 7, 0); + osxCALayerAWTModBug = Platform.OSType.MACOS == Platform.getOSType() && + 0 > Platform.getJavaVersionNumber().compareTo(version170); + System.err.println("OSX CALayer AWT-Mod Bug "+osxCALayerAWTModBug); + System.err.println("OSType "+Platform.getOSType()); + System.err.println("Java Version "+Platform.getJavaVersionNumber()); + // Frame setup ---------------------------------------------------------- width = 300; @@ -328,16 +356,9 @@ public class TestGLCanvasAWTActionDeadlock02AWT extends UITestCase { }}); } } - - boolean justInitialized = true; - + void draw(GL2 gl) { - if(!justInitialized) { - // BUG on OSX/CALayer: If frame.setTitle() is issued right after initialization - // the call hangs in - // at apple.awt.CWindow._setTitle(Native Method) - // at apple.awt.CWindow.setTitle(CWindow.java:765) [1.6.0_37, build 1.6.0_37-b06-434-11M3909] - // + if( !osxCALayerAWTModBug || !justInitialized ) { frame.setTitle("frame " + frameCount); } @@ -441,15 +462,15 @@ public class TestGLCanvasAWTActionDeadlock02AWT extends UITestCase { class SimpleListener implements GLEventListener { @Override public void display(GLAutoDrawable drawable) { - draw(drawable.getGL().getGL2()); - justInitialized = false; + draw(drawable.getGL().getGL2()); + justInitialized = false; } @Override public void dispose(GLAutoDrawable drawable) { } @Override - public void init(GLAutoDrawable drawable) { + public void init(GLAutoDrawable drawable) { justInitialized = true; } |