From c225285e09f0a29fca418601bf1aa07cafb54339 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 13 Mar 2013 06:35:30 +0100 Subject: Bug 665: Allow re-association of GLContext/GLEventListener to a GLDrawable (Part 4) Note: - GLEventListenerState preservs the GLAutoDrawable state, i.e. GLContext, all GLEventListener and the GLAnimatorControl association. - GLEventListenerState may be utilized to move the state from a dying GLAutoDrawable, to be moved to a new created GLAutoDrawable at a later time. - GLEventListenerState will be made public soon. +++ Exessive unit tests cover the new feature, tested manually on GNU/Linux/X11 and OSX(Java6/Java7). +++ - GLAutoDrawable - Change 'setContext(..)' to allow the destruction of the unbound old context: 'setContext(GLContext newCtx)' -> 'setContext(GLContext newCtx, boolean destroyPrevCtx)' - Implementations: Properly implement 'setRealized(..)' incl. obeying threading constraints if exists. Method is being utilized at least for GLEventListenerState.moveTo(..) to unrealize and realize the drawable resources. +++ Fix propagation of GLContext/GLDrawable association change (Bottom -> Top): GLDrawableImpl.associateContext GLContextImpl.associateDrawable GLContextImpl.makeCurrent GLContextImpl.destroy GLContext.setGLDrawable ... GLDrawableHelper.switchContext GLAutoDrawble.setContext associateDrawable(..)/associateContext(..) unifies and hence: - GLContextImpl.contextRealized() (removed) - GLDrawableImpl.contextRealized() (removed) - GLDrawableImpl.associateContext(..) (merged) - MacOSXCGLContext.drawableChangedNotify(..) (removed) +++ - EGLUpstreamSurfaceHook.evalUpstreamSurface() validates the surface's device for reusage, which is valid in case of GLEventListenerState.moveTo(..) - MacOSXCGLContext.NSOpenGLImpl: pixelFormat replaces NSOpenGLLayerPfmt and has simplified lifecycle [create..destroy], while native NSOpenGLLayer code only holds the reference until released. --- make/scripts/tests.sh | 45 ++- .../com/jogamp/opengl/GLAutoDrawableDelegate.java | 5 - .../classes/com/jogamp/opengl/swt/GLCanvas.java | 7 +- .../com/jogamp/opengl/util/GLDrawableUtil.java | 2 +- .../classes/javax/media/opengl/GLAutoDrawable.java | 21 +- .../classes/javax/media/opengl/awt/GLCanvas.java | 90 ++--- .../classes/javax/media/opengl/awt/GLJPanel.java | 7 +- .../classes/jogamp/opengl/GLAutoDrawableBase.java | 25 +- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 59 ++-- .../classes/jogamp/opengl/GLDrawableHelper.java | 45 +-- src/jogl/classes/jogamp/opengl/GLDrawableImpl.java | 40 +-- .../jogamp/opengl/GLEventListenerState.java | 55 +-- .../classes/jogamp/opengl/GLFBODrawableImpl.java | 14 +- src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 10 +- .../jogamp/opengl/egl/EGLUpstreamSurfaceHook.java | 53 ++- .../jogamp/opengl/macosx/cgl/MacOSXCGLContext.java | 132 +++---- .../opengl/macosx/cgl/MacOSXCGLDrawable.java | 1 - .../macosx/MacOSXWindowSystemInterface-calayer.m | 17 +- .../acore/TestGLContextDrawableSwitch01NEWT.java | 374 -------------------- .../acore/TestGLContextDrawableSwitch11NEWT.java | 386 --------------------- .../acore/glels/GLContextDrawableSwitchBase.java | 276 +++++++++++++++ .../glels/TestGLContextDrawableSwitch01NEWT.java | 374 ++++++++++++++++++++ .../glels/TestGLContextDrawableSwitch10NEWT.java | 274 +++++++++++++++ .../TestGLContextDrawableSwitch11NewtAWT.java | 118 +++++++ .../glels/TestGLContextDrawableSwitch12AWT.java | 144 ++++++++ .../TestGLContextDrawableSwitch21Newt2AWT.java | 165 +++++++++ .../demos/es2/newt/TestGearsES2NewtCanvasAWT.java | 31 +- .../jogamp/opengl/test/junit/util/QuitAdapter.java | 19 +- 28 files changed, 1730 insertions(+), 1059 deletions(-) delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/GLContextDrawableSwitchBase.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch10NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch11NewtAWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch12AWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch21Newt2AWT.java diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 5d259d6be..8cc3fd84a 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -106,10 +106,11 @@ function jrun() { #D_ARGS="-Djogamp.debug=all" #D_ARGS="-Djogamp.debug=all -Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" #D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" - #D_ARGS="-Dnativewindow.debug.X11Util -Djogl.debug.EGLDisplayUtil -Djogl.debug.GLDrawable" + #D_ARGS="-Dnativewindow.debug.X11Util -Dnativewindow.debug.X11Util.TraceDisplayLifecycle -Djogl.debug.EGLDisplayUtil -Djogl.debug.GLDrawable" #D_ARGS="-Dnativewindow.debug.X11Util" #D_ARGS="-Djogl.debug.Animator" #D_ARGS="-Djogl.debug=all -Dnewt.debug=all" + #D_ARGS="-Djogl.debug.EGLDisplayUtil -Djogl.debug.GLDrawable" #D_ARGS="-Djogl.debug.GLDrawable -Djogl.debug.GLContext -Djogl.debug.GLCanvas" #D_ARGS="-Djogl.debug.GLDrawable" #D_ARGS="-Djogl.fbo.force.none" @@ -194,7 +195,6 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Dnewt.debug=all -Djogamp.debug.Lock -Djogamp.common.utils.locks.Lock.timeout=10000" #D_ARGS="-Djogl.debug.GLContext -Dnewt.debug=all" #D_ARGS="-Dnewt.debug=all" - #D_ARGS="-Dnewt.debug=all" #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.GLJPanel" #X_ARGS="-Dsun.java2d.noddraw=True -Dsun.java2d.opengl=True -Dsun.java2d.xrender=false" #X_ARGS="-Dsun.java2d.noddraw=True -Dsun.java2d.opengl=false -Dsun.java2d.xrender=false" @@ -312,17 +312,9 @@ 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.TestGLContextDrawableSwitch01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch02NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLPointsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug651NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug658NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimNEWT $* -#testawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext02FPSAnimNEWT $* -#testawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext02FPSAnimAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext11VSyncAnimNEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext12FPSAnimNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestAddRemove01GLCanvasSwingAWT $* @@ -339,15 +331,27 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT $* - #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableFactoryNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* -testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1DemoES2NEWT $* +#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 $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimNEWT $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext01VSyncAnimAWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext02FPSAnimNEWT $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext02FPSAnimAWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext11VSyncAnimNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.ect.TestExclusiveContext12FPSAnimNEWT $* + +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch10NEWT $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch11NewtAWT $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch12AWT $* +testawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch21Newt2AWT $* + +#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $* + #testawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableDeadlockAWT $* #testawt com.jogamp.opengl.test.junit.jogl.awt.TestBug461FBOSupersamplingSwingAWT @@ -560,9 +564,6 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1D # Child too low #testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT $* -# NPE: -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT $* - # test rotation change #testnoawt com.jogamp.opengl.test.junit.newt.TestScreenMode02NEWT @@ -580,5 +581,15 @@ testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1D # ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed. #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* +# NEW +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOAutoDrawableFactoryNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.caps.TestBug605FlippedImageNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.caps.TestBug605FlippedImageAWT $* + +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.glels.TestGLContextDrawableSwitch11NEWT $* + +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* + + $spath/count-edt-start.sh java-run.log diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java index 0f0f03ac4..bec05a0bd 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java +++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java @@ -169,11 +169,6 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAuto return drawable.getFactory(); } - @Override - public final void setRealized(boolean realized) { - drawable.setRealized(realized); - } - @Override public final void swapBuffers() throws GLException { defaultSwapBuffers(); diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 80e1aa80d..169266152 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -705,16 +705,13 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } @Override - public GLContext setContext(GLContext newCtx) { + public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) { final RecursiveLock _lock = lock; _lock.lock(); try { final GLContext oldCtx = context; - final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; - if(newCtxCurrent) { - context.makeCurrent(); - } return oldCtx; } finally { _lock.unlock(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java index c03e4bfa4..83414ddb0 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java @@ -151,7 +151,7 @@ public class GLDrawableUtil { for(int i = dest.getGLEventListenerCount() - 1; 0 <= i; i--) { dest.disposeGLEventListener(dest.getGLEventListener(i), false); } - dest.setContext( src.setContext( dest.getContext() ) ); + dest.setContext( src.setContext( dest.getContext(), false ), false ); src.invoke(true, GLEventListenerState.setViewport); dest.invoke(true, GLEventListenerState.setViewport); diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index 6abe4308b..bdbbd96a5 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -132,7 +132,8 @@ public interface GLAutoDrawable extends GLDrawable { /** * Associate the new context, newtCtx, to this auto-drawable. *

- * The current context will be dis-associated from this auto-drawable + * The current context will be destroyed if destroyPrevCtx is true, + * otherwise it will be dis-associated from this auto-drawable * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first. *

*

@@ -145,26 +146,16 @@ public interface GLAutoDrawable extends GLDrawable { * However the user shall take extra care that no other thread * attempts to make this context current. *

- *

- * In case you do not intend to use the old context anymore, i.e. - * not assigning it to another drawable, it shall be - * destroyed, i.e.: - *

-            GLContext oldCtx = glad.setContext(newCtx);
-            if(null != oldCtx) {
-                oldCtx.destroy();
-            }
-   * 
- *

* * @param newCtx the new context, maybe null for dis-association. + * @param destroyPrevCtx if true, destroy the previous context if exists * @return the previous GLContext, maybe null * * @see GLContext#setGLDrawable(GLDrawable, boolean) * @see GLContext#setGLReadDrawable(GLDrawable) - * @see jogamp.opengl.GLDrawableHelper#switchContext(GLDrawable, GLContext, GLContext, int) + * @see jogamp.opengl.GLDrawableHelper#switchContext(GLDrawable, GLContext, boolean, GLContext, int) */ - public GLContext setContext(GLContext newCtx); + public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx); /** * Adds the given {@link GLEventListener listener} to the end of this drawable queue. @@ -500,7 +491,7 @@ public interface GLAutoDrawable extends GLDrawable { *

* This GLAutoDrawable implementation holds it's own GLContext reference, * thus created a GLContext using this methods won't replace it implicitly. - * To replace or set this GLAutoDrawable's GLContext you need to call {@link #setContext(GLContext)}. + * To replace or set this GLAutoDrawable's GLContext you need to call {@link #setContext(GLContext, boolean)}. *

*

* The GLAutoDrawable implementation shall also set the diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index ebc25e2ad..63c18db5d 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -429,8 +429,29 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } + private final void setRealizedImpl(boolean realized) { + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final GLDrawable _drawable = drawable; + if( null == _drawable || realized && ( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) ) { + return; + } + _drawable.setRealized(realized); + if( realized && _drawable.isRealized() ) { + sendReshape=true; // ensure a reshape is being send .. + } + } finally { + _lock.unlock(); + } + } + private final Runnable realizeOnEDTAction = new Runnable() { public void run() { setRealizedImpl(true); } }; + private final Runnable unrealizeOnEDTAction = new Runnable() { public void run() { setRealizedImpl(false); } }; + @Override - public void setRealized(boolean realized) { + public final void setRealized(boolean realized) { + // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! + AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, realized ? realizeOnEDTAction : unrealizeOnEDTAction); } @Override @@ -595,46 +616,28 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } private boolean validateGLDrawable() { - if( Beans.isDesignTime() || !isDisplayable() ) { - return false; // early out! - } - final GLDrawable _drawable = drawable; - if ( null != _drawable ) { - if( _drawable.isRealized() ) { - return true; - } - if( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { - return false; // early out! - } - // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! - final boolean res0 = AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, setRealizedOnEDTAction); - final boolean res1 = res0 && _drawable.isRealized(); - if(DEBUG) { - System.err.println(getThreadName()+": Realized Drawable: invoked "+res0+", probedIsRealized "+res1+", "+_drawable.toString()); - Thread.dumpStack(); - } - return res1; - } - return false; - } - private Runnable setRealizedOnEDTAction = new Runnable() { - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLDrawable _drawable = drawable; - if( null == _drawable || 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { - return; - } - _drawable.setRealized(true); - if( _drawable.isRealized() ) { - sendReshape=true; // ensure a reshape is being send .. - } - } finally { - _lock.unlock(); + if( Beans.isDesignTime() || !isDisplayable() ) { + return false; // early out! + } + final GLDrawable _drawable = drawable; + if ( null != _drawable ) { + if( _drawable.isRealized() ) { + return true; } - } }; - + if( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { + return false; // early out! + } + setRealized(true); + final boolean res = _drawable.isRealized(); + if(DEBUG) { + System.err.println(getThreadName()+": Realized Drawable: isRealized "+res+", "+_drawable.toString()); + Thread.dumpStack(); + } + return res; + } + return false; + } + /**

Overridden to track when this component is removed from a container. Subclasses which override this method must call super.removeNotify() in their removeNotify() method in order to @@ -791,16 +794,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } @Override - public GLContext setContext(GLContext newCtx) { + public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) { final RecursiveLock _lock = lock; _lock.lock(); try { final GLContext oldCtx = context; - final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; - if(newCtxCurrent) { - context.makeCurrent(); - } return oldCtx; } finally { _lock.unlock(); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 8d9493cbf..d62967d7f 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -519,16 +519,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } @Override - public GLContext setContext(GLContext newCtx) { + public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) { if (backend == null) { return null; } final GLContext oldCtx = backend.getContext(); - final boolean newCtxCurrent = GLDrawableHelper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags); + GLDrawableHelper.switchContext(backend.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); backend.setContext(newCtx); - if(newCtxCurrent) { - newCtx.makeCurrent(); - } return oldCtx; } diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index c20197e72..ad67f8281 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -326,16 +326,13 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } @Override - public final GLContext setContext(GLContext newCtx) { + public final GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) { final RecursiveLock lock = getLock(); lock.lock(); try { final GLContext oldCtx = context; - final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; - if(newCtxCurrent) { // implies null != newCtx - context.makeCurrent(); - } return oldCtx; } finally { lock.unlock(); @@ -530,6 +527,24 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } } + @Override + public final void setRealized(boolean realized) { + final RecursiveLock _lock = getLock(); + _lock.lock(); + try { + final GLDrawable _drawable = drawable; + if( null == _drawable || realized && ( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) ) { + return; + } + _drawable.setRealized(realized); + if( realized && _drawable.isRealized() ) { + sendReshape=true; // ensure a reshape is being send .. + } + } finally { + _lock.unlock(); + } + } + @Override public final boolean isRealized() { final GLDrawable _drawable = drawable; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 42364dbfd..4121e8f77 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -133,9 +133,6 @@ public abstract class GLContextImpl extends GLContext { GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this); this.drawable = drawable; - if(null != drawable) { - drawable.associateContext(this, true); - } this.drawableRead = drawable; this.glDebugHandler = new GLDebugMessageHandler(this); @@ -207,25 +204,36 @@ public abstract class GLContextImpl extends GLContext { return drawable; // no change. } final Thread currentThread = Thread.currentThread(); + if( lock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } final boolean lockHeld = lock.isOwner(currentThread); + if( lockHeld && lock.getHoldCount() > 1 ) { + // would need to makeCurrent * holdCount + throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); + } + final GLDrawableImpl old = drawable; + if( isCreated() && null != old && old.isRealized() ) { + if(!lockHeld) { + makeCurrent(); + } + associateDrawable(false); + if(!lockHeld) { + release(); + } + } if(lockHeld) { release(); - } else if(lock.isLockedByOtherThread()) { // still could glitch .. - throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); - } + } if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable drawableRead = (GLDrawableImpl) readWrite; } - final GLDrawableImpl old = drawable; - if( null != old ) { - old.associateContext(this, false); - } drawableRetargeted |= null != drawable && readWrite != drawable; drawable = (GLDrawableImpl) readWrite ; - if( null != drawable ) { - drawable.associateContext(this, true); - if( lockHeld ) { - makeCurrent(); + if( isCreated() && null != drawable && drawable.isRealized() ) { + makeCurrent(true); // implicit: associateDrawable(true) + if( !lockHeld ) { + release(); } } return old; @@ -363,8 +371,7 @@ public abstract class GLContextImpl extends GLContext { makeCurrent(); } try { - contextRealized(false); - drawable.associateContext(this, false); + associateDrawable(false); } catch (Throwable t) { drawableContextRealizedException = t; } @@ -467,7 +474,11 @@ public abstract class GLContextImpl extends GLContext { * @see #destroyContextARBImpl */ @Override - public int makeCurrent() throws GLException { + public final int makeCurrent() throws GLException { + return makeCurrent(false); + } + + protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException { if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock); } @@ -561,7 +572,11 @@ public abstract class GLContextImpl extends GLContext { gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } - contextRealized(true); + forceDrawableAssociation = true; + } + + if( forceDrawableAssociation ) { + associateDrawable(true); } contextMadeCurrent(true); @@ -662,14 +677,14 @@ public abstract class GLContextImpl extends GLContext { protected abstract void makeCurrentImpl() throws GLException; /** - * @see GLDrawableImpl#contextRealized(GLContext, boolean) + * Calls {@link GLDrawableImpl#associateContext(GLContext, boolean)} */ - protected void contextRealized(boolean realized) { - drawable.contextRealized(this, realized); + protected void associateDrawable(boolean bound) { + drawable.associateContext(this, bound); } /** - * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean) + * Calls {@link GLDrawableImpl#contextMadeCurrent(GLContext, boolean)} */ protected void contextMadeCurrent(boolean current) { drawable.contextMadeCurrent(this, current); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 3eedf918e..1caa942ba 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -59,7 +59,7 @@ import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLRunnable; /** Encapsulates the implementation of most of the GLAutoDrawable's - methods to be able to share it between GLCanvas and GLJPanel. */ + methods to be able to share it between GLAutoDrawable implementations like GLAutoDrawableBase, GLCanvas and GLJPanel. */ public class GLDrawableHelper { /** true if property jogl.debug.GLDrawable.PerfStats is defined. */ private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); @@ -113,6 +113,9 @@ public class GLDrawableHelper { return sb.toString(); } + /** Limit release calls of {@link #forceNativeRelease(GLContext)} to {@value}. */ + private static final int MAX_RELEASE_ITER = 512; + /** * Since GLContext's {@link GLContext#makeCurrent()} and {@link GLContext#release()} * is recursive, a call to {@link GLContext#release()} may not natively release the context. @@ -122,18 +125,25 @@ public class GLDrawableHelper { * @param ctx */ public static final void forceNativeRelease(GLContext ctx) { + int releaseCount = 0; do { ctx.release(); + releaseCount++; if (DEBUG) { - System.err.println("GLDrawableHelper.forceNativeRelease() -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent()); + System.err.println("GLDrawableHelper.forceNativeRelease() #"+releaseCount+" -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent()); } - } while( ctx == GLContext.getCurrent() ); + } while( MAX_RELEASE_ITER > releaseCount && ctx.isCurrent() ); + + if( ctx.isCurrent() ) { + throw new GLException("Context still current after "+MAX_RELEASE_ITER+" releases: "+ctx); + } } /** * Switch {@link GLContext} / {@link GLDrawable} association. *

- * Dis-associate oldCtx from drawable + * The oldCtx will be destroyed if destroyPrevCtx is true, + * otherwise dis-associate oldCtx from drawable * via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}. *

*

@@ -149,31 +159,25 @@ public class GLDrawableHelper { * * @param drawable the drawable which context is changed * @param oldCtx the old context, maybe null. + * @param destroyOldCtx if true, destroy the oldCtx * @param newCtx the new context, maybe null for dis-association. * @param newCtxCreationFlags additional creation flags if newCtx is not null and not been created yet, see {@link GLContext#setContextCreationFlags(int)} - * @return true if the new context was current, otherwise false * - * @see GLAutoDrawable#setContext(GLContext) + * @see GLAutoDrawable#setContext(GLContext, boolean) */ - public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) { + public static final void switchContext(GLDrawable drawable, GLContext oldCtx, boolean destroyOldCtx, GLContext newCtx, int newCtxCreationFlags) { if( null != oldCtx ) { - if( oldCtx.isCurrent() ) { - oldCtx.release(); + if( destroyOldCtx ) { + oldCtx.destroy(); + } else { + oldCtx.setGLDrawable(null, true); // dis-associate old pair } - oldCtx.setGLDrawable(null, true); // dis-associate old pair } - final boolean newCtxCurrent; + if(null!=newCtx) { - newCtxCurrent = newCtx.isCurrent(); - if(newCtxCurrent) { - newCtx.release(); - } newCtx.setContextCreationFlags(newCtxCreationFlags); - newCtx.setGLDrawable(drawable, true); // re-associate new pair - } else { - newCtxCurrent = false; + newCtx.setGLDrawable(drawable, true); // re-associate new pair } - return newCtxCurrent; } /** @@ -208,7 +212,6 @@ public class GLDrawableHelper { context.makeCurrent(); } context.getGL().glFinish(); - context.release(); context.setGLDrawable(null, true); // dis-associate } @@ -837,7 +840,7 @@ public class GLDrawableHelper { if( null != exclusiveContextThread ) { throw new GLException("Release current exclusive Context Thread "+exclusiveContextThread+" first"); } - if( null != context && GLContext.getCurrent() == context ) { + if( null != context && context.isCurrent() ) { try { forceNativeRelease(context); } catch (Throwable ex) { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index c0c28a5f2..d0c1461a9 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -164,13 +164,14 @@ public abstract class GLDrawableImpl implements GLDrawable { @Override public final void setRealized(boolean realizedArg) { if ( realized != realizedArg ) { // volatile: OK (locked below) + final boolean isProxySurface = surface instanceof ProxySurface; if(DEBUG) { - System.err.println(getThreadName() + ": setRealized: "+getClass().getSimpleName()+" "+realized+" -> "+realizedArg); + System.err.println(getThreadName() + ": setRealized: drawable "+getClass().getSimpleName()+", surface "+surface.getClass().getSimpleName()+", isProxySurface "+isProxySurface+": "+realized+" -> "+realizedArg); Thread.dumpStack(); } AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice(); if(realizedArg) { - if(surface instanceof ProxySurface) { + if(isProxySurface) { ((ProxySurface)surface).createNotify(); } if(NativeSurface.LOCK_SURFACE_NOT_READY >= lockSurface()) { @@ -195,7 +196,7 @@ public abstract class GLDrawableImpl implements GLDrawable { unlockSurface(); } else { aDevice.unlock(); - if(surface instanceof ProxySurface) { + if(isProxySurface) { ((ProxySurface)surface).destroyNotify(); } } @@ -210,18 +211,26 @@ public abstract class GLDrawableImpl implements GLDrawable { */ protected abstract void setRealizedImpl(); - /** - * Callback for special implementations, allowing GLContext to trigger GL related lifecycle: construct, destroy. + /** + * Callback for special implementations, allowing + *

*

- * If realized is true, the context has just been created and made current. + * If bound is true, the context is current and being newly associated w/ this drawable. *

*

- * If realized is false, the context is still current and will be released and destroyed after this method returns. + * If bound is false, the context is still current and will be unbound (released and destroyed, or simply disassociated). *

*

- * @see #contextMadeCurrent(GLContext, boolean) + * Being called by {@link GLContextImpl#associateDrawable(boolean)}. + *

+ * @param ctx the just bounded or unbounded context + * @param bound if true create an association, otherwise remove it */ - protected void contextRealized(GLContext glc, boolean realized) {} + protected void associateContext(GLContext ctx, boolean bound) { } /** * Callback for special implementations, allowing GLContext to trigger GL related lifecycle: makeCurrent, release. @@ -232,21 +241,12 @@ public abstract class GLDrawableImpl implements GLDrawable { * If current is false, the context is still current and will be release after this method returns. *

*

- * Note: Will also be called after {@link #contextRealized(GLContext, boolean) contextRealized(ctx, true)} - * but not at context destruction, i.e. {@link #contextRealized(GLContext, boolean) contextRealized(ctx, false)}. + * Being called by {@link GLContextImpl#contextMadeCurrent(boolean)}. *

- * @see #contextRealized(GLContext, boolean) + * @see #associateContext(GLContext, boolean) */ protected void contextMadeCurrent(GLContext glc, boolean current) { } - /** - * Callback for special implementations, allowing to associate bound context to this drawable (bound == true) - * or to remove such association (bound == false). - * @param ctx the just bounded or unbounded context - * @param bound if true create an association, otherwise remove it - */ - protected void associateContext(GLContext ctx, boolean bound) { } - /** Callback for special implementations, allowing GLContext to fetch a custom default render framebuffer. Defaults to zero.*/ protected int getDefaultDrawFramebuffer() { return 0; } /** Callback for special implementations, allowing GLContext to fetch a custom default read framebuffer. Defaults to zero. */ diff --git a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java index 7a2569850..2385460fe 100644 --- a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java +++ b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java @@ -45,7 +45,6 @@ import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; import javax.media.opengl.GLRunnable; -import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.nativewindow.MutableGraphicsConfiguration; /** @@ -71,11 +70,12 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration; *

*/ public class GLEventListenerState { - private static final boolean DEBUG = true; + private static final boolean DEBUG = GLDrawableImpl.DEBUG; - private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, + private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, boolean proxyOwnsUpstreamDevice, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, GLContext context, int count, GLAnimatorControl anim) { this.upstreamScreen = upstreamScreen; + this.proxyOwnsUpstreamDevice = proxyOwnsUpstreamDevice; this.screen = screen; this.caps = caps; this.context = context; @@ -97,6 +97,7 @@ public class GLEventListenerState { public final int listenerCount() { return listeners.length; } public final AbstractGraphicsScreen upstreamScreen; + public final boolean proxyOwnsUpstreamDevice; public final AbstractGraphicsScreen screen; public final GLCapabilitiesImmutable caps; public final GLContext context; @@ -161,25 +162,30 @@ public class GLEventListenerState { } aScreen1.getDevice().clearHandleOwner(); // don't close device handle - final AbstractGraphicsScreen aUpScreen2; + final AbstractGraphicsScreen aUpScreen2; + final boolean proxyOwnsUpstreamDevice; { AbstractGraphicsScreen _aUpScreen2=null; if(aSurface instanceof ProxySurface) { final ProxySurface aProxy = (ProxySurface)aSurface; + proxyOwnsUpstreamDevice = aProxy.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); - if(null != aUpSurface) { + if(DEBUG && null != aUpSurface) { System.err.println("X00 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); } - aProxy.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); // don't close device handle if(null != aUpSurface) { final AbstractGraphicsScreen aUpScreen1 = aUpSurface.getGraphicsConfiguration().getScreen(); _aUpScreen2 = cloneScreen(aUpScreen1); if(null != aUpScreen1) { aUpScreen1.getDevice().clearHandleOwner(); // don't close device handle } - System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); - System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if(DEBUG) { + System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + } } + } else { + proxyOwnsUpstreamDevice = false; } aUpScreen2=_aUpScreen2; } @@ -189,7 +195,7 @@ public class GLEventListenerState { aAnim.remove(a); // also handles ECT } - final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, aScreen2, caps, a.getContext(), aSz, aAnim); + final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, proxyOwnsUpstreamDevice, aScreen2, caps, a.getContext(), aSz, aAnim); // // remove and cache all GLEventListener and their init-state @@ -205,7 +211,7 @@ public class GLEventListenerState { // a.invoke(true, glFinish); - a.setContext( null ); + a.setContext( null, false ); return glls; } @@ -241,13 +247,7 @@ public class GLEventListenerState { throw new GLException("Incompatible Capabilities - Prev-Holder: "+caps+", New-Holder "+caps); } // Destroy and remove currently associated GLContext, if any (will be replaced) - { - final GLContext ctx = a.getContext(); - if( null != ctx) { - ctx.destroy(); - } - a.setContext( null ); - } + a.setContext( null, true ); final boolean aRealized = a.isRealized(); if( aRealized ) { a.setRealized(false); @@ -260,8 +260,11 @@ public class GLEventListenerState { final AbstractGraphicsScreen aScreen1 = aCfg.getScreen(); aCfg.setScreen( screen ); aScreen1.getDevice().close(); - System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + if( DEBUG ) { + System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + } } + // If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it { boolean upstreamSet = false; @@ -270,13 +273,19 @@ public class GLEventListenerState { final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); if(null != aUpSurface) { final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration(); - final AbstractGraphicsScreen aUpScreen1 = aUpCfg.getScreen(); if( null != upstreamScreen ) { - System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if( DEBUG ) { + System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString()); + } + aUpCfg.getScreen().getDevice().close(); aUpCfg.setScreen( upstreamScreen ); - aUpScreen1.getDevice().close(); + if( proxyOwnsUpstreamDevice ) { + aProxy.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } upstreamSet = true; - System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if( DEBUG ) { + System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString()); + } } else { throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true"); } @@ -292,7 +301,7 @@ public class GLEventListenerState { } final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface(); try { - a.setContext( context ); + a.setContext( context, false ); } finally { if( surfaceLocked ) { aSurface.unlockSurface(); diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 86cfa4f4c..51ec7dda6 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -38,6 +38,7 @@ import com.jogamp.opengl.JoglVersion; */ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); + protected static final boolean DEBUG_SWAP = Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true); private final GLDrawableImpl parent; private GLCapabilitiesImmutable origParentChosenCaps; @@ -92,6 +93,9 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } private final void initialize(boolean realize, GL gl) { + if( initialized == realize ) { + throw new InternalError("Already set to initialize := "+realize+": "+this); + } if(realize) { final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true) @@ -323,8 +327,8 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } @Override - protected final void contextRealized(GLContext glc, boolean realized) { - initialize(realized, glc.getGL()); + protected void associateContext(GLContext glc, boolean bound) { + initialize(bound, glc.getGL()); } @Override @@ -338,7 +342,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { swapFBOImpl(glc); swapFBOImplPost(glc); fboBound=false; - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(@release): done"); } } @@ -354,7 +358,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { swapFBOImpl(ctx); doPostSwap = true; fboBound=false; - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(@swap): done"); } } @@ -406,7 +410,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer()); } */ - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length); } } diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index b438131bc..ddc6d5917 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -86,9 +86,10 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { // @Override - public final void setRealized(boolean realized) { + public final void swapBuffers() throws GLException { + defaultSwapBuffers(); } - + // // GLAutoDrawable completion // @@ -125,11 +126,6 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { } } - @Override - public final void swapBuffers() throws GLException { - defaultSwapBuffers(); - } - //---------------------------------------------------------------------- // Internals only below this point // diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java index 342c4c417..77e9dc173 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java @@ -47,7 +47,7 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { public final void create(ProxySurface surface) { final String dbgPrefix; if(DEBUG) { - dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): "; + dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create( up "+upstreamSurface.getClass().getSimpleName()+" -> this "+surface.getClass().getSimpleName()+" ): "; System.err.println(dbgPrefix+this); } else { dbgPrefix = null; @@ -76,24 +76,51 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { boolean isEGLSurfaceValid = true; // assume yes - final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration(); - final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); - final EGLGraphicsDevice eglDevice; - if( aDevice instanceof EGLGraphicsDevice ) { - eglDevice = (EGLGraphicsDevice) aDevice; + final AbstractGraphicsConfiguration aConfig; + { + final AbstractGraphicsConfiguration surfaceConfig = surface.getGraphicsConfiguration(); + final AbstractGraphicsDevice surfaceDevice = null != surfaceConfig ? surfaceConfig.getScreen().getDevice() : null; + if(DEBUG) { + System.err.println(dbgPrefix+"SurfaceDevice: "+surfaceDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceDevice.hashCode())+", "+surfaceDevice); + System.err.println(dbgPrefix+"SurfaceConfig: "+surfaceConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceConfig.hashCode())+", "+surfaceConfig); + } + + final AbstractGraphicsConfiguration upstreamConfig = upstreamSurface.getGraphicsConfiguration(); + final AbstractGraphicsDevice upstreamDevice = upstreamConfig.getScreen().getDevice(); if(DEBUG) { - System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice); + System.err.println(dbgPrefix+"UpstreamDevice: "+upstreamDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamDevice.hashCode())+", "+upstreamDevice); + System.err.println(dbgPrefix+"UpstreamConfig: "+upstreamConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamConfig.hashCode())+", "+upstreamConfig); } - if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { - eglDevice.open(); + + if( surfaceDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) surfaceDevice; + aConfig = surfaceConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing this eglDevice: "+eglDevice+", using this config "+aConfig.getClass().getSimpleName()+" "+aConfig); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else if( upstreamDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) upstreamDevice; + aConfig = upstreamConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing upstream eglDevice: "+eglDevice+", using upstream config "+aConfig.getClass().getSimpleName()+" "+aConfig); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else { + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + aConfig = upstreamConfig; isEGLSurfaceValid = false; surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } - } else { - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); - isEGLSurfaceValid = false; - surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 3825f855c..a03850043 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -85,10 +85,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGL-based or CGL-based) protected interface GLBackendImpl { boolean isNSContext(); - void drawableChangedNotify(); long create(long share, int ctp, int major, int minor); boolean destroy(long ctx); - boolean contextRealized(boolean realized); + void associateDrawable(boolean bound); boolean copyImpl(long src, int mask); boolean makeCurrent(long ctx); boolean release(long ctx); @@ -328,20 +327,15 @@ public abstract class MacOSXCGLContext extends GLContextImpl } @Override - protected void contextRealized(boolean realized) { + protected void associateDrawable(boolean bound) { // context stuff depends on drawable stuff - if(realized) { - super.contextRealized(true); // 1) init drawable stuff - impl.contextRealized(true); // 2) init context stuff + System.err.println("MaxOSXCGLContext.associateDrawable: "+bound); + if(bound) { + super.associateDrawable(true); // 1) init drawable stuff + impl.associateDrawable(true); // 2) init context stuff } else { - impl.contextRealized(false); // 1) free context stuff - super.contextRealized(false); // 2) free drawable stuff - } - } - - /* pp */ void drawableChangedNotify() { - if( 0 != contextHandle) { - impl.drawableChangedNotify(); + impl.associateDrawable(false); // 1) free context stuff + super.associateDrawable(false); // 2) free drawable stuff } } @@ -467,9 +461,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { - private OffscreenLayerSurface backingLayerHost = null; - private long nsOpenGLLayer = 0; - private long nsOpenGLLayerPFmt = 0; // lifecycle: [create - contextRealized] + private long pixelFormat = 0; // lifecycle: [create - destroy] + private long nsOpenGLLayer = 0; // lifecycle: [associateDrawable_true - associateDrawable_false] private float screenVSyncTimeout; // microSec private int vsyncTimeout; // microSec - for nsOpenGLLayer mode private int lastWidth=0, lastHeight=0; // allowing to detect size change @@ -479,18 +472,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean isNSContext() { return true; } - @Override - public void drawableChangedNotify() { - backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); - if( null == backingLayerHost ) { - boolean[] isPBuffer = { false }; - boolean[] isFBO = { false }; - CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); - } else { - nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer(); - } - } - private long getNSViewHandle(boolean[] isPBuffer, boolean[] isFBO) { final long nsViewHandle; if(drawable instanceof GLFBODrawableImpl) { @@ -549,13 +530,12 @@ public abstract class MacOSXCGLContext extends GLContextImpl isPBuffer = _isPBuffer[0]; isFBO = _isFBO[0]; } - backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); boolean incompleteView = null != backingLayerHost; if( !incompleteView && surface instanceof ProxySurface ) { incompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); } - long pixelFormat; { final GLCapabilitiesImmutable targetCaps; if( isFBO ) { @@ -606,48 +586,54 @@ public abstract class MacOSXCGLContext extends GLContextImpl } config.setChosenCapabilities(fixedCaps); - try { - final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1); - // Try to allocate a context with this - ctx = CGL.createContext(share, - nsViewHandle, incompleteView, - pixelFormat, - chosenCaps.isBackgroundOpaque(), - viewNotReady); - if (0 == ctx) { - if(DEBUG) { - System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0))); - } - return 0; + final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1); + // Try to allocate a context with this + ctx = CGL.createContext(share, nsViewHandle, incompleteView, + pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady); + if (0 == ctx) { + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0))); } + return 0; + } - if(null != backingLayerHost) { - nsOpenGLLayerPFmt = pixelFormat; - pixelFormat = 0; - } - - if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { - // Set the context opacity - CGL.setContextOpacity(ctx, 0); - } - } finally { - if(0!=pixelFormat) { - CGL.deletePixelFormat(pixelFormat); - pixelFormat = 0; - } + if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { + // Set the context opacity + CGL.setContextOpacity(ctx, 0); } return ctx; } @Override public boolean destroy(long ctx) { + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + pixelFormat = 0; + } return CGL.deleteContext(ctx, true); + } @Override - public boolean contextRealized(boolean realized) { - if( realized ) { + public void associateDrawable(boolean bound) { + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); + + if(DEBUG) { + System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+", hasBackingLayerHost "+(null!=backingLayerHost)); + } + + if( bound ) { + if( null != backingLayerHost ) { + + if( 0 != nsOpenGLLayer ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set local: "+nsOpenGLLayer+", "+this); + } + nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer(); + if( 0 != nsOpenGLLayer ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set on backingLayerHost: "+nsOpenGLLayer+", "+this); + } + // // handled layered surface // @@ -700,8 +686,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } final boolean ctxUnlocked = CGL.kCGLNoError == CGL.CGLUnlockContext(cglCtx); try { - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, nsOpenGLLayerPFmt, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); - nsOpenGLLayerPFmt = 0; // NSOpenGLLayer will release pfmt + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); if (DEBUG) { System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); } @@ -718,17 +703,22 @@ public abstract class MacOSXCGLContext extends GLContextImpl } else { lastWidth = drawable.getWidth(); lastHeight = drawable.getHeight(); + boolean[] isPBuffer = { false }; + boolean[] isFBO = { false }; + CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); } } else { if( 0 != nsOpenGLLayer ) { - final NativeSurface surface = drawable.getNativeSurface(); + if( null == backingLayerHost ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=false, hasNSOpneGLLayer=true, but 'backingLayerHost' is null local: "+nsOpenGLLayer+", "+this); + } + if (DEBUG) { System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable); } - final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - if(null != ols && ols.isSurfaceLayerAttached()) { + if( backingLayerHost.isSurfaceLayerAttached() ) { // still having a valid OLS attached to surface (parent OLS could have been removed) - ols.detachSurfaceLayer(); + backingLayerHost.detachSurfaceLayer(); } CGL.releaseNSOpenGLLayer(nsOpenGLLayer); if( null != gl3ShaderProgram ) { @@ -738,8 +728,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl nsOpenGLLayer = 0; } } - backingLayerHost = null; - return true; } private final void validatePBufferConfig(long ctx) { @@ -888,11 +876,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean isNSContext() { return false; } - @Override - public void drawableChangedNotify() { - // FIXME - } - @Override public long create(long share, int ctp, int major, int minor) { long ctx = 0; @@ -947,8 +930,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } @Override - public boolean contextRealized(boolean realized) { - return true; + public void associateDrawable(boolean bound) { } @Override diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index ff1772860..0f282d33f 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -119,7 +119,6 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { if(bound) { final MacOSXCGLContext osxCtx = (MacOSXCGLContext)ctx; createdContexts.add(new WeakReference(osxCtx)); - osxCtx.drawableChangedNotify(); } else { for(int i=0; i ref = createdContexts.get(i); diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m index 2cf74380c..abc9d7958 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m @@ -275,7 +275,7 @@ static const GLfloat gl_verts[] = { vboBufTexCoord = 0; vertAttrLoc = 0; texCoordAttrLoc = 0; - parentPixelFmt = _parentPixelFmt; + parentPixelFmt = [_parentPixelFmt retain]; // until destruction swapInterval = 1; // defaults to on (as w/ new GL profiles) swapIntervalCounter = 0; timespec_now(&lastWaitTime); @@ -338,13 +338,13 @@ static const GLfloat gl_verts[] = { #ifdef VERBOSE_ON CGRect lRect = [self bounds]; if(NULL != pbuffer) { - DBG_PRINT("MyNSOpenGLLayer::init (pbuffer) %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, bounds: %lf/%lf %lfx%lf (refcnt %d)\n", + DBG_PRINT("MyNSOpenGLLayer::init (pbuffer) %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, bounds: %lf/%lf %lfx%lf, displayLink %p (refcnt %d)\n", self, parentCtx, parentPixelFmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, - lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, displayLink, (int)[self retainCount]); } else { - DBG_PRINT("MyNSOpenGLLayer::init (texture) %p, ctx %p, pfmt %p, opaque %d, tex[id %d, %dx%d], bounds: %lf/%lf %lfx%lf (refcnt %d)\n", + DBG_PRINT("MyNSOpenGLLayer::init (texture) %p, ctx %p, pfmt %p, opaque %d, tex[id %d, %dx%d], bounds: %lf/%lf %lfx%lf, displayLink %p (refcnt %d)\n", self, parentCtx, parentPixelFmt, opaque, (int)textureID, texWidth, texHeight, - lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, displayLink, (int)[self retainCount]); } #endif return self; @@ -498,7 +498,10 @@ static const GLfloat gl_verts[] = { myCtx = NULL; } parentCtx = NULL; - [parentPixelFmt release]; + if( NULL != parentPixelFmt ) { + [parentPixelFmt release]; + parentPixelFmt = NULL; + } pthread_mutex_unlock(&renderLock); [self release]; DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p\n", self); @@ -623,7 +626,7 @@ static const GLfloat gl_verts[] = { { DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask: %p (refcnt %d) - parent-pfmt %p -> new-pfmt %p\n", self, (int)[self retainCount], parentPixelFmt, parentPixelFmt); - // We simply take over ownership of parent PixelFormat .. + // We simply take over ownership of parent PixelFormat until releaseLayer.. return parentPixelFmt; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java deleted file mode 100644 index cce4149ba..000000000 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java +++ /dev/null @@ -1,374 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * 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 - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * 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. - */ - -package com.jogamp.opengl.test.junit.jogl.acore; - -import java.io.IOException; - -import com.jogamp.newt.NewtFactory; -import com.jogamp.newt.Window; -import com.jogamp.newt.event.WindowAdapter; -import com.jogamp.newt.event.WindowEvent; -import com.jogamp.newt.event.WindowListener; -import com.jogamp.newt.event.WindowUpdateEvent; -import com.jogamp.newt.opengl.GLWindow; - -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLContext; -import javax.media.opengl.GLDrawable; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLProfile; - -import com.jogamp.opengl.GLAutoDrawableDelegate; -import com.jogamp.opengl.util.Animator; -import com.jogamp.opengl.util.GLDrawableUtil; - -import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; -import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; -import com.jogamp.opengl.test.junit.util.AWTRobotUtil; -import com.jogamp.opengl.test.junit.util.QuitAdapter; -import com.jogamp.opengl.test.junit.util.UITestCase; - -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * Test re-association (switching) of GLContext/GLDrawables, - * i.e. ctx1/draw1, ctx2/draw2 -> ctx1/draw2, ctx2/draw1. - */ -public class TestGLContextDrawableSwitch01NEWT extends UITestCase { - static int width, height; - - static GLCapabilities getCaps(String profile) { - if( !GLProfile.isAvailable(profile) ) { - System.err.println("Profile "+profile+" n/a"); - return null; - } - return new GLCapabilities(GLProfile.get(profile)); - } - - @BeforeClass - public static void initClass() { - width = 256; - height = 256; - } - - private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { - final Window window = NewtFactory.createWindow(caps); - Assert.assertNotNull(window); - window.setPosition(x, y); - window.setSize(width, height); - window.setVisible(true); - Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); - Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); - - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - final GLDrawable drawable = factory.createGLDrawable(window); - Assert.assertNotNull(drawable); - - drawable.setRealized(true); - Assert.assertTrue(drawable.isRealized()); - - final GLContext context = drawable.createContext(null); - Assert.assertNotNull(context); - - final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) { - @Override - protected void destroyImplInLock() { - super.destroyImplInLock(); - window.destroy(); // destroys the actual window - } - }; - - window.setWindowDestroyNotifyAction( new Runnable() { - public void run() { - glad.windowDestroyNotifyOp(); - } } ); - - // add basic window interaction - window.addWindowListener(new WindowAdapter() { - @Override - public void windowRepaint(WindowUpdateEvent e) { - glad.windowRepaintOp(); - } - @Override - public void windowResized(WindowEvent e) { - glad.windowResizedOp(window.getWidth(), window.getHeight()); - } - }); - window.addWindowListener(wl); - - return glad; - } - - @Test(timeout=30000) - public void testSwitch2WindowSingleContextGL2ES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); - if(null == reqGLCaps) return; - testSwitch2WindowSingleContextImpl(reqGLCaps); - } - - @Test(timeout=30000) - public void testSwitch2WindowSingleContextGLES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); - if(null == reqGLCaps) return; - testSwitch2WindowSingleContextImpl(reqGLCaps); - } - - private void testSwitch2WindowSingleContextImpl(GLCapabilities caps) throws InterruptedException { - final QuitAdapter quitAdapter = new QuitAdapter(); - - GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); - GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); - - // create single context using glad1 and assign it to glad1, - // destroy the prev. context afterwards. - { - final GLContext newCtx = glad1.createContext(null); - Assert.assertNotNull(newCtx); - final GLContext oldCtx = glad1.setContext(newCtx); - Assert.assertNotNull(oldCtx); - oldCtx.destroy(); - final int res = newCtx.makeCurrent(); - Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); - newCtx.release(); - } - - final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); - GearsES2 gears = new GearsES2(1); - glad1.addGLEventListener(gears); - glad1.addGLEventListener(snapshotGLEventListener); - snapshotGLEventListener.setMakeSnapshot(); - - Animator animator = new Animator(); - animator.add(glad1); - animator.add(glad2); - animator.start(); - - int s = 0; - long t0 = System.currentTimeMillis(); - long t1 = t0; - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { - if( ( t1 - t0 ) / period > s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - - // switch context _and_ the demo synchronously - GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2); - - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - glad1.destroy(); - glad2.destroy(); - } - - @Test(timeout=30000) - public void testSwitch2GLWindowOneDemoGL2ES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); - if(null == reqGLCaps) return; - testSwitch2GLWindowOneDemoImpl(reqGLCaps); - } - - @Test(timeout=30000) - public void testSwitch2GLWindowOneDemoGLES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); - if(null == reqGLCaps) return; - testSwitch2GLWindowOneDemoImpl(reqGLCaps); - } - - private void testSwitch2GLWindowOneDemoImpl(GLCapabilities caps) throws InterruptedException { - final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); - final GearsES2 gears = new GearsES2(1); - final QuitAdapter quitAdapter = new QuitAdapter(); - - GLWindow glWindow1 = GLWindow.create(caps); - glWindow1.setTitle("win1"); - glWindow1.setSize(width, height); - glWindow1.setPosition(64, 64); - glWindow1.addGLEventListener(0, gears); - glWindow1.addGLEventListener(snapshotGLEventListener); - glWindow1.addWindowListener(quitAdapter); - - GLWindow glWindow2 = GLWindow.create(caps); - glWindow2.setTitle("win2"); - glWindow2.setSize(width+100, height+100); - glWindow2.setPosition(2*64+width, 64); - glWindow2.addWindowListener(quitAdapter); - - Animator animator = new Animator(); - animator.add(glWindow1); - animator.add(glWindow2); - animator.start(); - - glWindow1.setVisible(true); - glWindow2.setVisible(true); - - snapshotGLEventListener.setMakeSnapshot(); - - int s = 0; - long t0 = System.currentTimeMillis(); - long t1 = t0; - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { - if( ( t1 - t0 ) / period > s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - - // switch context _and_ the demo synchronously - GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); - - System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - - snapshotGLEventListener.setMakeSnapshot(); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - glWindow1.destroy(); - glWindow2.destroy(); - - } - - @Test(timeout=30000) - public void testSwitch2GLWindowEachWithOwnDemoGL2ES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); - if(null == reqGLCaps) return; - testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); - } - - @Test(timeout=30000) - public void testSwitch2GLWindowEachWithOwnDemoGLES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); - if(null == reqGLCaps) return; - testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); - } - - public void testSwitch2GLWindowEachWithOwnDemoImpl(GLCapabilities caps) throws InterruptedException { - final GearsES2 gears = new GearsES2(1); - final RedSquareES2 rsquare = new RedSquareES2(1); - final QuitAdapter quitAdapter = new QuitAdapter(); - final SnapshotGLEventListener snapshotGLEventListener1 = new SnapshotGLEventListener(); - final SnapshotGLEventListener snapshotGLEventListener2 = new SnapshotGLEventListener(); - - GLWindow glWindow1 = GLWindow.create(caps); - glWindow1.setTitle("win1"); - glWindow1.setSize(width, height); - glWindow1.setPosition(64, 64); - glWindow1.addGLEventListener(0, gears); - glWindow1.addGLEventListener(snapshotGLEventListener1); - glWindow1.addWindowListener(quitAdapter); - - GLWindow glWindow2 = GLWindow.create(caps); - glWindow2.setTitle("win2"); - glWindow2.setSize(width+100, height+100); - glWindow2.setPosition(2*64+width, 64); - glWindow2.addGLEventListener(0, rsquare); - glWindow2.addGLEventListener(snapshotGLEventListener2); - glWindow2.addWindowListener(quitAdapter); - - Animator animator = new Animator(); - animator.add(glWindow1); - animator.add(glWindow2); - animator.start(); - - glWindow1.setVisible(true); - glWindow2.setVisible(true); - - snapshotGLEventListener1.setMakeSnapshot(); - snapshotGLEventListener2.setMakeSnapshot(); - - int s = 0; - long t0 = System.currentTimeMillis(); - long t1 = t0; - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { - if( ( t1 - t0 ) / period > s) { - s++; - System.err.println(s+" - switch - START "+ ( t1 - t0 )); - System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); - System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); - System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); - System.err.println(s+" - switch - END "+ ( t1 - t0 )); - snapshotGLEventListener1.setMakeSnapshot(); - snapshotGLEventListener2.setMakeSnapshot(); - } - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - animator.stop(); - // System.err.println("pre -del-w1: w1: "+glWindow1); - // System.err.println("pre -del-w1: w2: "+glWindow2); - glWindow1.destroy(); - // System.err.println("post-del-w1: w1: "+glWindow1); - // System.err.println("post-del-w1: w2: "+glWindow2); - glWindow2.destroy(); - - } - - // default timing for 2 switches - static long duration = 2200; // ms - static long period = 1000; // ms - - public static void main(String args[]) throws IOException { - for(int i=0; i - * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. - *

- */ -public class TestGLContextDrawableSwitch11NEWT extends UITestCase { - static int width, height; - - static GLCapabilities getCaps(String profile) { - if( !GLProfile.isAvailable(profile) ) { - System.err.println("Profile "+profile+" n/a"); - return null; - } - return new GLCapabilities(GLProfile.get(profile)); - } - - @BeforeClass - public static void initClass() { - width = 256; - height = 256; - } - - private GLAutoDrawable createGLAutoDrawableWithoutContext(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { - final Window window = NewtFactory.createWindow(caps); - Assert.assertNotNull(window); - window.setPosition(x, y); - window.setSize(width, height); - window.setVisible(true); - Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); - Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); - - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - final GLDrawable drawable = factory.createGLDrawable(window); - Assert.assertNotNull(drawable); - - drawable.setRealized(true); - Assert.assertTrue(drawable.isRealized()); - - final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false, null) { - @Override - protected void destroyImplInLock() { - super.destroyImplInLock(); - window.destroy(); // destroys the actual window - } - }; - - window.setWindowDestroyNotifyAction( new Runnable() { - public void run() { - glad.windowDestroyNotifyOp(); - } } ); - - // add basic window interaction - window.addWindowListener(new WindowAdapter() { - @Override - public void windowRepaint(WindowUpdateEvent e) { - glad.windowRepaintOp(); - } - @Override - public void windowResized(WindowEvent e) { - glad.windowResizedOp(window.getWidth(), window.getHeight()); - } - }); - window.addWindowListener(wl); - - return glad; - } - - @Test(timeout=30000) - public void test01GLADDelegateGL2ES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); - if(null == reqGLCaps) return; - test01GLADDelegateImpl(reqGLCaps); - } - - @Test(timeout=30000) - public void test01GLADDelegateGLES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); - if(null == reqGLCaps) return; - test01GLADDelegateImpl(reqGLCaps); - } - - private void test01GLADDelegateImpl(GLCapabilities caps) throws InterruptedException { - final QuitAdapter quitAdapter = new QuitAdapter(); - - final GLEventListenerCounter glelCounter = new GLEventListenerCounter(); - final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); - final Animator animator = new Animator(); - animator.start(); - - final long t0 = System.currentTimeMillis(); - final GLEventListenerState glls1; - - // - create glad1 w/o context - // - create context using glad1 and assign it to glad1 - { - final GLAutoDrawable glad1 = createGLAutoDrawableWithoutContext(caps, 64, 64, width, height, quitAdapter); - final GLContext context1 = glad1.createContext(null); - glad1.setContext(context1); - animator.add(glad1); - - glad1.addGLEventListener(glelCounter); - glad1.addGLEventListener(new GearsES2(1)); - glad1.addGLEventListener(snapshotGLEventListener); - snapshotGLEventListener.setMakeSnapshot(); - - long t1 = System.currentTimeMillis(); - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) { - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - Assert.assertEquals(1, glelCounter.initCount); - Assert.assertTrue(1 <= glelCounter.reshapeCount); - Assert.assertTrue(1 <= glelCounter.displayCount); - Assert.assertEquals(0, glelCounter.disposeCount); - Assert.assertEquals(context1, glad1.getContext()); - Assert.assertEquals(3, glad1.getGLEventListenerCount()); - Assert.assertEquals(context1.getGLReadDrawable(), glad1.getDelegatedDrawable()); - Assert.assertEquals(context1.getGLDrawable(), glad1.getDelegatedDrawable()); - - // - dis-associate context from glad1 - // - destroy glad1 - glls1 = GLEventListenerState.moveFrom(glad1); - - Assert.assertEquals(1, glelCounter.initCount); - Assert.assertTrue(1 <= glelCounter.reshapeCount); - Assert.assertTrue(1 <= glelCounter.displayCount); - Assert.assertEquals(0, glelCounter.disposeCount); - Assert.assertEquals(context1, glls1.context); - Assert.assertNull(context1.getGLReadDrawable()); - Assert.assertNull(context1.getGLDrawable()); - Assert.assertEquals(3, glls1.listenerCount()); - Assert.assertEquals(true, glls1.isOwner()); - Assert.assertEquals(null, glad1.getContext()); - Assert.assertEquals(0, glad1.getGLEventListenerCount()); - - glad1.destroy(); - Assert.assertEquals(1, glelCounter.initCount); - Assert.assertTrue(1 <= glelCounter.reshapeCount); - Assert.assertTrue(1 <= glelCounter.displayCount); - Assert.assertEquals(0, glelCounter.disposeCount); - } - - // - create glad2 w/ survived context - { - final GLAutoDrawable glad2 = createGLAutoDrawableWithoutContext(caps, 2*64+width, 64, width+100, height+100, quitAdapter); - snapshotGLEventListener.setMakeSnapshot(); - - Assert.assertEquals(null, glad2.getContext()); - Assert.assertEquals(0, glad2.getGLEventListenerCount()); - - glls1.moveTo(glad2); - - Assert.assertTrue(glad2.isRealized()); - - Assert.assertEquals(1, glelCounter.initCount); - Assert.assertTrue(1 <= glelCounter.reshapeCount); - Assert.assertTrue(1 <= glelCounter.displayCount); - Assert.assertEquals(0, glelCounter.disposeCount); - Assert.assertEquals(glls1.context, glad2.getContext()); - Assert.assertEquals(3, glad2.getGLEventListenerCount()); - Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); - Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); - Assert.assertEquals(false, glls1.isOwner()); - - long t1 = System.currentTimeMillis(); - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) { - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - glad2.destroy(); - Assert.assertEquals(1, glelCounter.initCount); - Assert.assertTrue(1 <= glelCounter.reshapeCount); - Assert.assertTrue(1 <= glelCounter.displayCount); - Assert.assertEquals(1, glelCounter.disposeCount); - } - animator.stop(); - } - - @Test(timeout=30000) - public void test02GLWindowGL2ES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); - if(null == reqGLCaps) return; - test02GLWindowImpl(reqGLCaps); - } - - @Test(timeout=30000) - public void test02GLWindowGLES2() throws InterruptedException { - final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); - if(null == reqGLCaps) return; - test02GLWindowImpl(reqGLCaps); - } - - private void test02GLWindowImpl(GLCapabilities caps) throws InterruptedException { - final QuitAdapter quitAdapter = new QuitAdapter(); - - final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); - final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); - final Animator animator = new Animator(); - animator.start(); - - final long t0 = System.currentTimeMillis(); - final GLEventListenerState glls1; - - // - create glad1 w/o context - // - create context using glad1 and assign it to glad1 - { - final GLWindow glad1 = GLWindow.create(caps); - glad1.setSize(width, height); - glad1.setPosition(64, 64); - glad1.addWindowListener(quitAdapter); - animator.add(glad1); - - glad1.addGLEventListener(glelTracker); - glad1.addGLEventListener(new GearsES2(1)); - glad1.addGLEventListener(snapshotGLEventListener); - snapshotGLEventListener.setMakeSnapshot(); - - glad1.setVisible(true); - - long t1 = System.currentTimeMillis(); - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) { - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - // - dis-associate context from glad1 - // - destroy glad1 - Assert.assertEquals(1, glelTracker.initCount); - Assert.assertTrue(1 <= glelTracker.reshapeCount); - Assert.assertTrue(1 <= glelTracker.displayCount); - Assert.assertEquals(0, glelTracker.disposeCount); - Assert.assertEquals(3, glad1.getGLEventListenerCount()); - Assert.assertEquals(glad1.getContext().getGLReadDrawable(), glad1.getDelegatedDrawable()); - Assert.assertEquals(glad1.getContext().getGLDrawable(), glad1.getDelegatedDrawable()); - - final GLContext context1 = glad1.getContext(); - glls1 = GLEventListenerState.moveFrom(glad1); - - Assert.assertEquals(1, glelTracker.initCount); - Assert.assertTrue(1 <= glelTracker.reshapeCount); - Assert.assertTrue(1 <= glelTracker.displayCount); - Assert.assertEquals(0, glelTracker.disposeCount); - Assert.assertEquals(context1, glls1.context); - Assert.assertNull(context1.getGLReadDrawable()); - Assert.assertNull(context1.getGLDrawable()); - Assert.assertEquals(3, glls1.listenerCount()); - Assert.assertEquals(true, glls1.isOwner()); - Assert.assertEquals(null, glad1.getContext()); - Assert.assertEquals(0, glad1.getGLEventListenerCount()); - - glad1.destroy(); - Assert.assertEquals(1, glelTracker.initCount); - Assert.assertTrue(1 <= glelTracker.reshapeCount); - Assert.assertTrue(1 <= glelTracker.displayCount); - Assert.assertEquals(0, glelTracker.disposeCount); - } - - // - create glad2 w/ survived context - { - final GLWindow glad2 = GLWindow.create(caps); - glad2.setSize(width+100, height+100); - glad2.setPosition(2*64+width, 64); - glad2.addWindowListener(quitAdapter); - snapshotGLEventListener.setMakeSnapshot(); - glad2.setVisible(true); - - Assert.assertNotNull(glad2.getContext()); - Assert.assertEquals(0, glad2.getGLEventListenerCount()); - - glls1.moveTo(glad2); - - Assert.assertEquals(1, glelTracker.initCount); - Assert.assertTrue(1 <= glelTracker.reshapeCount); - Assert.assertTrue(1 <= glelTracker.displayCount); - Assert.assertEquals(0, glelTracker.disposeCount); - Assert.assertEquals(glls1.context, glad2.getContext()); - Assert.assertEquals(3, glad2.getGLEventListenerCount()); - Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); - Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); - Assert.assertEquals(false, glls1.isOwner()); - - long t1 = System.currentTimeMillis(); - - while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) { - Thread.sleep(100); - t1 = System.currentTimeMillis(); - } - - glad2.destroy(); - Assert.assertEquals(1, glelTracker.initCount); - Assert.assertTrue(1 <= glelTracker.reshapeCount); - Assert.assertTrue(1 <= glelTracker.displayCount); - Assert.assertEquals(1, glelTracker.disposeCount); - } - animator.stop(); - } - - // default timing for 2 switches - static long duration = 2200; // ms - - public static void main(String args[]) throws IOException { - for(int i=0; i + * Test utilizes {@link GLEventListenerState} for preserving the + * GLAutoDrawable state, i.e. GLContext, all GLEventListener + * and the GLAnimatorControl association. + *

+ *

+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public abstract class GLContextDrawableSwitchBase extends UITestCase { + static protected enum GLADType { GLCanvasOnscreen, GLCanvasOffscreen, GLWindow, GLOffscreen }; + + // default period for 1 GLAD cycle + static long duration = 1000; // ms + + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + static void setGLCanvasSize(final GLCanvas glc, final Dimension new_sz) { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + glc.setMinimumSize(new_sz); + glc.setPreferredSize(new_sz); + glc.setSize(new_sz); + } } ); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + static void setFrameVisible(final Frame frame) throws InterruptedException { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.pack(); + frame.setVisible(true); + }}); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + static void destroyFrame(final Frame frame) throws InterruptedException { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.dispose(); + }}); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + private GLOffscreenAutoDrawable createGLOffscreenAutoDrawable(GLCapabilities caps, int width, int height) throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + return factory.createOffscreenAutoDrawable(null, caps, null, width, height, null); + } + + protected static boolean validateOnOffscreenLayer(GLADType gladType1, GLADType gladType2) { + final boolean useOffscreenLayer = GLADType.GLCanvasOffscreen == gladType1 || GLADType.GLCanvasOffscreen == gladType2 ; + final boolean useOnscreenLayer = GLADType.GLCanvasOnscreen == gladType1 || GLADType.GLCanvasOnscreen == gladType2 ; + if( useOffscreenLayer ) { + if( !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("Platform doesn't support offscreen rendering."); + return false; + } + } else if( useOnscreenLayer ) { + if( JAWTUtil.isOffscreenLayerRequired() ) { + System.err.println("Platform requires offscreen rendering."); + return false; + } + } + return true; + } + + protected void testGLADOneLifecycle(GLCapabilities caps, GLADType gladType, int width, int height, + GLEventListenerCounter glelTracker, SnapshotGLEventListener snapshotGLEventListener, + GLEventListenerState glelsIn, GLEventListenerState glelsOut[], GLAnimatorControl animator) + throws InterruptedException { + + final Frame frame; + final GLAutoDrawable glad; + if( GLADType.GLCanvasOnscreen == gladType ) { + if( jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerRequired() ) { + throw new InternalError("Platform requires offscreen rendering, but onscreen requested: "+gladType); + } + frame = new Frame("AWT GLCanvas"); + + glad = new GLCanvas(caps); + setGLCanvasSize((GLCanvas)glad, new Dimension(width, height)); + frame.add((GLCanvas)glad); + } else if( GLADType.GLCanvasOffscreen == gladType ) { + if( !jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerSupported() ) { + throw new InternalError("Platform doesn't support offscreen rendering: "+gladType); + } + frame = new Frame("AWT GLCanvas"); + + glad = new GLCanvas(caps); + ((GLCanvas)glad).setShallUseOffscreenLayer(true); + setGLCanvasSize((GLCanvas)glad, new Dimension(width, height)); + frame.add((GLCanvas)glad); + } else if( GLADType.GLWindow == gladType ) { + frame = null; + + glad = GLWindow.create(caps); + ((GLWindow)glad).setTitle("Newt GLWindow"); + ((GLWindow)glad).setSize(width, height); + } else if( GLADType.GLOffscreen == gladType ) { + frame = null; + + glad = this.createGLOffscreenAutoDrawable(caps, width, height); + } else { + throw new InternalError("Unsupported: "+gladType); + } + + if( null == glelsIn ) { + if( null != animator ) { + animator.add(glad); + } + glad.addGLEventListener(glelTracker); + glad.addGLEventListener(new GearsES2(1)); + glad.addGLEventListener(snapshotGLEventListener); + } + snapshotGLEventListener.setMakeSnapshot(); + + if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) { + setFrameVisible(frame); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + } else if( GLADType.GLWindow == gladType ) { + ((GLWindow)glad).setVisible(true); + } + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, true)); + Assert.assertNotNull(glad.getContext()); + Assert.assertTrue(glad.isRealized()); + + if( null != glelsIn ) { + Assert.assertEquals(0, glad.getGLEventListenerCount()); + glelsIn.moveTo(glad); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + Assert.assertEquals(3, glad.getGLEventListenerCount()); + + Assert.assertEquals(glelsIn.context, glad.getContext()); + Assert.assertEquals(glelsIn.listenerCount(), glad.getGLEventListenerCount()); + Assert.assertEquals(glelsIn.context.getGLReadDrawable(), glad.getDelegatedDrawable()); + Assert.assertEquals(glelsIn.context.getGLDrawable(), glad.getDelegatedDrawable()); + Assert.assertEquals(false, glelsIn.isOwner()); + } + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + + if( null != glelsOut ) { + final GLContext context1 = glad.getContext(); + final GLEventListenerState _gllsOut = GLEventListenerState.moveFrom(glad); + + Assert.assertEquals(context1, _gllsOut.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, _gllsOut.listenerCount()); + Assert.assertEquals(true, _gllsOut.isOwner()); + Assert.assertEquals(null, glad.getContext()); + Assert.assertEquals(0, glad.getGLEventListenerCount()); + + glelsOut[0] = _gllsOut; + } + if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) { + destroyFrame(frame); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, false)); + } else if( GLADType.GLWindow == gladType ) { + glad.destroy(); + } else if( GLADType.GLOffscreen == gladType ) { + glad.destroy(); + } + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, false)); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + if( null != glelsOut ) { + Assert.assertEquals(0, glelTracker.disposeCount); + } else { + Assert.assertEquals(1, glelTracker.disposeCount); + } + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java new file mode 100644 index 000000000..5f2b9fb53 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java @@ -0,0 +1,374 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * 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 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * 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. + */ + +package com.jogamp.opengl.test.junit.jogl.acore.glels; + +import java.io.IOException; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.WindowUpdateEvent; +import com.jogamp.newt.opengl.GLWindow; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLProfile; + +import com.jogamp.opengl.GLAutoDrawableDelegate; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLDrawableUtil; + +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.test.junit.util.UITestCase; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test re-association (switching) of GLContext/GLDrawables, + * i.e. ctx1/draw1, ctx2/draw2 -> ctx1/draw2, ctx2/draw1. + */ +public class TestGLContextDrawableSwitch01NEWT extends UITestCase { + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLContext context = drawable.createContext(null); + Assert.assertNotNull(context); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + window.setWindowDestroyNotifyAction( new Runnable() { + public void run() { + glad.windowDestroyNotifyOp(); + } } ); + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void testSwitch2WindowSingleContextGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2WindowSingleContextImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2WindowSingleContextGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2WindowSingleContextImpl(reqGLCaps); + } + + private void testSwitch2WindowSingleContextImpl(GLCapabilities caps) throws InterruptedException { + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); + GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + + // create single context using glad1 and assign it to glad1, + // destroy the prev. context afterwards. + { + final GLContext newCtx = glad1.createContext(null); + Assert.assertNotNull(newCtx); + final GLContext oldCtx = glad1.setContext(newCtx, true); + Assert.assertNotNull(oldCtx); + Assert.assertFalse(oldCtx.isCreated()); + final int res = newCtx.makeCurrent(); + Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); + newCtx.release(); + } + + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + GearsES2 gears = new GearsES2(1); + glad1.addGLEventListener(gears); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + Animator animator = new Animator(); + animator.add(glad1); + animator.add(glad2); + animator.start(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2); + + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glad1.destroy(); + glad2.destroy(); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowOneDemoGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowOneDemoImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowOneDemoGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowOneDemoImpl(reqGLCaps); + } + + private void testSwitch2GLWindowOneDemoImpl(GLCapabilities caps) throws InterruptedException { + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GearsES2 gears = new GearsES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + + snapshotGLEventListener.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glWindow1.destroy(); + glWindow2.destroy(); + + } + + @Test(timeout=30000) + public void testSwitch2GLWindowEachWithOwnDemoGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowEachWithOwnDemoGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); + } + + public void testSwitch2GLWindowEachWithOwnDemoImpl(GLCapabilities caps) throws InterruptedException { + final GearsES2 gears = new GearsES2(1); + final RedSquareES2 rsquare = new RedSquareES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + final SnapshotGLEventListener snapshotGLEventListener1 = new SnapshotGLEventListener(); + final SnapshotGLEventListener snapshotGLEventListener2 = new SnapshotGLEventListener(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener1); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addGLEventListener(0, rsquare); + glWindow2.addGLEventListener(snapshotGLEventListener2); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + // System.err.println("pre -del-w1: w1: "+glWindow1); + // System.err.println("pre -del-w1: w2: "+glWindow2); + glWindow1.destroy(); + // System.err.println("post-del-w1: w1: "+glWindow1); + // System.err.println("post-del-w1: w2: "+glWindow2); + glWindow2.destroy(); + + } + + // default timing for 2 switches + static long duration = 2200; // ms + static long period = 1000; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i + * Test utilizes {@link GLEventListenerState} for preserving the + * GLAutoDrawable state, i.e. GLContext, all GLEventListener + * and the GLAnimatorControl association. + *

+ *

+ * This test is using NEWT's plain Window w/ GLAutoDrawableDelegate. + *

+ *

+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public class TestGLContextDrawableSwitch10NEWT extends UITestCase { + // default period for 1 GLAD cycle + static long duration = 1000; // ms + + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawableWithoutContext(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + window.setWindowDestroyNotifyAction( new Runnable() { + public void run() { + glad.windowDestroyNotifyOp(); + } } ); + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void test01GLADDelegateGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLADDelegateImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void test02GLADDelegateGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLADDelegateImpl(reqGLCaps); + } + + private void testGLADDelegateImpl(GLCapabilities caps) throws InterruptedException { + final GLEventListenerCounter glelCounter = new GLEventListenerCounter(); + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glls1; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + final QuitAdapter quitAdapter = new QuitAdapter(); + final GLAutoDrawable glad1 = createGLAutoDrawableWithoutContext(caps, 64, 64, width, height, quitAdapter); + final GLContext context1 = glad1.createContext(null); + glad1.setContext(context1, true); + animator.add(glad1); + + glad1.addGLEventListener(glelCounter); + glad1.addGLEventListener(new GearsES2(1)); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glad1.getContext()); + Assert.assertEquals(3, glad1.getGLEventListenerCount()); + Assert.assertEquals(context1.getGLReadDrawable(), glad1.getDelegatedDrawable()); + Assert.assertEquals(context1.getGLDrawable(), glad1.getDelegatedDrawable()); + + // - dis-associate context from glad1 + // - destroy glad1 + glls1 = GLEventListenerState.moveFrom(glad1); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glls1.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, glls1.listenerCount()); + Assert.assertEquals(true, glls1.isOwner()); + Assert.assertEquals(null, glad1.getContext()); + Assert.assertEquals(0, glad1.getGLEventListenerCount()); + + glad1.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + } + + // - create glad2 w/ survived context + { + final QuitAdapter quitAdapter = new QuitAdapter(); + final GLAutoDrawable glad2 = createGLAutoDrawableWithoutContext(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + snapshotGLEventListener.setMakeSnapshot(); + + Assert.assertEquals(null, glad2.getContext()); + Assert.assertEquals(0, glad2.getGLEventListenerCount()); + + glls1.moveTo(glad2); + + Assert.assertTrue(glad2.isRealized()); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(glls1.context, glad2.getContext()); + Assert.assertEquals(3, glad2.getGLEventListenerCount()); + Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(false, glls1.isOwner()); + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + glad2.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(1, glelCounter.disposeCount); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i + * Test utilizes {@link GLEventListenerState} for preserving the + * GLAutoDrawable state, i.e. GLContext, all GLEventListener + * and the GLAnimatorControl association. + *

+ *

+ * This test is using JOGL's NEWT GLWindow. + *

+ *

+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public class TestGLContextDrawableSwitch11NewtAWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test21GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLWindowImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void test22GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLWindowImpl(reqGLCaps); + } + + private void testGLWindowImpl(GLCapabilities caps) throws InterruptedException { + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, GLADType.GLWindow, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, GLADType.GLWindow, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i + * Test utilizes {@link GLEventListenerState} for preserving the + * GLAutoDrawable state, i.e. GLContext, all GLEventListener + * and the GLAnimatorControl association. + *

+ *

+ * This test is using JOGL's AWT GLCanvas + *

+ *

+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public class TestGLContextDrawableSwitch12AWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test01GLCanvasOnscreenGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, false); + } + + @Test(timeout=30000) + public void test02GLCanvasOnscreenGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, false); + } + + @Test(timeout=30000) + public void test11GLCanvasOffscreenGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, true); + } + + @Test(timeout=30000) + public void test12GLCanvasOffscreenGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, true); + } + + private void testGLCanvasImpl(GLCapabilities caps, boolean offscreenLayer) throws InterruptedException { + if( offscreenLayer ) { + if( !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("Platform doesn't support offscreen rendering."); + return; + } + } else { + if( JAWTUtil.isOffscreenLayerRequired() ) { + System.err.println("Platform requires offscreen rendering."); + return; + } + } + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, offscreenLayer ? GLADType.GLCanvasOffscreen : GLADType.GLCanvasOnscreen, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, offscreenLayer ? GLADType.GLCanvasOffscreen : GLADType.GLCanvasOnscreen, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i + * Test utilizes {@link GLEventListenerState} for preserving the + * GLAutoDrawable state, i.e. GLContext, all GLEventListener + * and the GLAnimatorControl association. + *

+ *

+ * This test moves the {@link GLEventListenerState} from a + * NEWT GLWindow before it's destruction to an AWT GLCanvas after it's creation + * and vice versa + *

+ *

+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *

+ */ +public class TestGLContextDrawableSwitch21Newt2AWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test01GLCanvasOnScrn2GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOnscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test02GLCanvasOnScrn2GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOnscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test11GLWindow2GLCanvasOnScrnGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOnscreen); + } + + @Test(timeout=30000) + public void test12GLWindow2GLCanvasOnScrnGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOnscreen); + } + + @Test(timeout=30000) + public void test21GLCanvasOffScrn2GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOffscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test22GLCanvasOffScrn2GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOffscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test31GLWindow2GLCanvasOffScrnGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOffscreen); + } + + @Test(timeout=30000) + public void test32GLWindow2GLCanvasOffScrnGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOffscreen); + } + + private void testGLCanvas2GLWindowImpl(GLCapabilities caps, GLADType gladType1, GLADType gladType2) throws InterruptedException { + if( !validateOnOffscreenLayer(gladType1, gladType2) ) { + return; + } + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, gladType1, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, gladType2, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets()); } - while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()