summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-03-13 06:35:30 +0100
committerSven Gothel <[email protected]>2013-03-13 06:35:30 +0100
commitc225285e09f0a29fca418601bf1aa07cafb54339 (patch)
tree5cf619ad3b51db76511c3809d32ef29156eb71dd /src
parent8457bf35fee253d9af29ff1150a9671f6896fc17 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java5
-rw-r--r--src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java7
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java2
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java21
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java90
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java7
-rw-r--r--src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java25
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java59
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDrawableHelper.java45
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDrawableImpl.java40
-rw-r--r--src/jogl/classes/jogamp/opengl/GLEventListenerState.java55
-rw-r--r--src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java14
-rw-r--r--src/jogl/classes/jogamp/opengl/GLPbufferImpl.java10
-rw-r--r--src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java53
-rw-r--r--src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java132
-rw-r--r--src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java1
-rw-r--r--src/jogl/native/macosx/MacOSXWindowSystemInterface-calayer.m17
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/GLContextDrawableSwitchBase.java276
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java (renamed from src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java)6
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch10NEWT.java (renamed from src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java)168
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch11NewtAWT.java118
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch12AWT.java144
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch21Newt2AWT.java165
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java31
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/QuitAdapter.java19
25 files changed, 1085 insertions, 425 deletions
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
@@ -170,11 +170,6 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAuto
}
@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, <code>newtCtx</code>, to this auto-drawable.
* <p>
- * The current context will be dis-associated from this auto-drawable
+ * The current context will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>,
+ * otherwise it will be dis-associated from this auto-drawable
* via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first.
* </p>
* <p>
@@ -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.
* </p>
- * <p>
- * 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.:
- * <pre>
- GLContext oldCtx = glad.setContext(newCtx);
- if(null != oldCtx) {
- oldCtx.destroy();
- }
- * </pre>
- * </p>
*
* @param newCtx the new context, maybe <code>null</code> for dis-association.
+ * @param destroyPrevCtx if <code>true</code>, destroy the previous context if exists
* @return the previous GLContext, maybe <code>null</code>
*
* @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 {
* <p>
* 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)}.
* </p>
* <p>
* 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;
+ }
+
/** <p>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();
@@ -531,6 +528,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;
return null != _drawable ? _drawable.isRealized() : false;
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 <code>jogl.debug.GLDrawable.PerfStats</code> 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.
* <p>
- * Dis-associate <code>oldCtx</code> from <code>drawable</code>
+ * The <code>oldCtx</code> will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>,
+ * otherwise dis-associate <code>oldCtx</code> from <code>drawable</code>
* via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}.
* </p>
* <p>
@@ -149,31 +159,25 @@ public class GLDrawableHelper {
*
* @param drawable the drawable which context is changed
* @param oldCtx the old context, maybe <code>null</code>.
+ * @param destroyOldCtx if <code>true</code>, destroy the <code>oldCtx</code>
* @param newCtx the new context, maybe <code>null</code> 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: <code>construct</code>, <code>destroy</code>.
+ /**
+ * Callback for special implementations, allowing
+ * <ul>
+ * <li>to associate bound context to this drawable (bound == true)
+ * or to remove such association (bound == false).</li>
+ * <li>to trigger GLContext/GLDrawable related lifecycle: <code>construct</code>, <code>destroy</code>.</li>
+ * </ul>
* <p>
- * If <code>realized</code> is <code>true</code>, the context has just been created and made current.
+ * If <code>bound</code> is <code>true</code>, the context is current and being newly associated w/ this drawable.
* </p>
* <p>
- * If <code>realized</code> is <code>false</code>, the context is still current and will be released and destroyed after this method returns.
+ * If <code>bound</code> is <code>false</code>, the context is still current and will be unbound (released and destroyed, or simply disassociated).
* </p>
* <p>
- * @see #contextMadeCurrent(GLContext, boolean)
+ * Being called by {@link GLContextImpl#associateDrawable(boolean)}.
+ * </p>
+ * @param ctx the just bounded or unbounded context
+ * @param bound if <code>true</code> 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: <code>makeCurrent</code>, <code>release</code>.
@@ -232,21 +241,12 @@ public abstract class GLDrawableImpl implements GLDrawable {
* If <code>current</code> is <code>false</code>, the context is still current and will be release after this method returns.
* </p>
* <p>
- * 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)}.
* </p>
- * @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 <code>true</code> 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;
* <p>
*/
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) {
@@ -889,11 +877,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl
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;
MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration();
@@ -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<MacOSXCGLContext>(osxCtx));
- osxCtx.drawableChangedNotify();
} else {
for(int i=0; i<createdContexts.size(); ) {
final WeakReference<MacOSXCGLContext> 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/glels/GLContextDrawableSwitchBase.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/GLContextDrawableSwitchBase.java
new file mode 100644
index 000000000..f26a96a90
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/GLContextDrawableSwitchBase.java
@@ -0,0 +1,276 @@
+/**
+ * Copyright 2013 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.awt.Dimension;
+import java.awt.Frame;
+
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.awt.GLCanvas;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+import jogamp.opengl.GLEventListenerState;
+
+import com.jogamp.newt.opengl.GLWindow;
+
+import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
+import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+
+/**
+ * Test re-association of GLContext/GLDrawables,
+ * here GLContext's survival of GLDrawable destruction
+ * and reuse w/ new or recreated GLDrawable.
+ * <p>
+ * Test utilizes {@link GLEventListenerState} for preserving the
+ * GLAutoDrawable state, i.e. GLContext, all GLEventListener
+ * and the GLAnimatorControl association.
+ * </p>
+ * <p>
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
+ * </p>
+ */
+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/TestGLContextDrawableSwitch01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java
index cce4149ba..5f2b9fb53 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java
@@ -26,7 +26,7 @@
* or implied, of JogAmp Community.
*/
-package com.jogamp.opengl.test.junit.jogl.acore;
+package com.jogamp.opengl.test.junit.jogl.acore.glels;
import java.io.IOException;
@@ -153,9 +153,9 @@ public class TestGLContextDrawableSwitch01NEWT extends UITestCase {
{
final GLContext newCtx = glad1.createContext(null);
Assert.assertNotNull(newCtx);
- final GLContext oldCtx = glad1.setContext(newCtx);
+ final GLContext oldCtx = glad1.setContext(newCtx, true);
Assert.assertNotNull(oldCtx);
- oldCtx.destroy();
+ Assert.assertFalse(oldCtx.isCreated());
final int res = newCtx.makeCurrent();
Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
newCtx.release();
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch10NEWT.java
index 2ef797fba..a1611992e 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch10NEWT.java
@@ -26,7 +26,7 @@
* or implied, of JogAmp Community.
*/
-package com.jogamp.opengl.test.junit.jogl.acore;
+package com.jogamp.opengl.test.junit.jogl.acore.glels;
import java.io.IOException;
@@ -36,7 +36,6 @@ 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;
@@ -62,13 +61,24 @@ import org.junit.Test;
/**
* Test re-association of GLContext/GLDrawables,
- * here GLContext's survival of GLDrawable desctruction
+ * here GLContext's survival of GLDrawable destruction
* and reuse w/ new or recreated GLDrawable.
* <p>
+ * Test utilizes {@link GLEventListenerState} for preserving the
+ * GLAutoDrawable state, i.e. GLContext, all GLEventListener
+ * and the GLAnimatorControl association.
+ * </p>
+ * <p>
+ * This test is using NEWT's plain Window w/ GLAutoDrawableDelegate.
+ * </p>
+ * <p>
* See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
* </p>
*/
-public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
+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) {
@@ -134,33 +144,31 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
public void test01GLADDelegateGL2ES2() throws InterruptedException {
final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2);
if(null == reqGLCaps) return;
- test01GLADDelegateImpl(reqGLCaps);
+ testGLADDelegateImpl(reqGLCaps);
}
@Test(timeout=30000)
- public void test01GLADDelegateGLES2() throws InterruptedException {
+ public void test02GLADDelegateGLES2() throws InterruptedException {
final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2);
if(null == reqGLCaps) return;
- test01GLADDelegateImpl(reqGLCaps);
+ testGLADDelegateImpl(reqGLCaps);
}
- private void test01GLADDelegateImpl(GLCapabilities caps) throws InterruptedException {
- final QuitAdapter quitAdapter = new QuitAdapter();
-
+ 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 long t0 = System.currentTimeMillis();
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);
+ glad1.setContext(context1, true);
animator.add(glad1);
glad1.addGLEventListener(glelCounter);
@@ -168,9 +176,10 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
glad1.addGLEventListener(snapshotGLEventListener);
snapshotGLEventListener.setMakeSnapshot();
- long t1 = System.currentTimeMillis();
+ final long t0 = System.currentTimeMillis();
+ long t1 = t0;
- while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) {
+ while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) {
Thread.sleep(100);
t1 = System.currentTimeMillis();
}
@@ -209,6 +218,7 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
// - 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();
@@ -229,9 +239,10 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable());
Assert.assertEquals(false, glls1.isOwner());
- long t1 = System.currentTimeMillis();
+ final long t0 = System.currentTimeMillis();
+ long t1 = t0;
- while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) {
+ while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) {
Thread.sleep(100);
t1 = System.currentTimeMillis();
}
@@ -245,129 +256,6 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
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<args.length; i++) {
if(args[i].equals("-time")) {
@@ -381,6 +269,6 @@ public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
System.err.println("Press enter to continue");
System.err.println(stdin.readLine()); */
- org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch11NEWT.class.getName());
+ org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch10NEWT.class.getName());
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch11NewtAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch11NewtAWT.java
new file mode 100644
index 000000000..9ad89c4be
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch11NewtAWT.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright 2013 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 javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import jogamp.opengl.GLEventListenerState;
+
+import com.jogamp.opengl.util.Animator;
+
+import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
+
+import org.junit.Test;
+
+/**
+ * Test re-association of GLContext/GLDrawables,
+ * here GLContext's survival of GLDrawable destruction
+ * and reuse w/ new or recreated GLDrawable.
+ * <p>
+ * Test utilizes {@link GLEventListenerState} for preserving the
+ * GLAutoDrawable state, i.e. GLContext, all GLEventListener
+ * and the GLAnimatorControl association.
+ * </p>
+ * <p>
+ * This test is using JOGL's NEWT GLWindow.
+ * </p>
+ * <p>
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
+ * </p>
+ */
+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<args.length; i++) {
+ if(args[i].equals("-time")) {
+ i++;
+ try {
+ duration = Integer.parseInt(args[i]);
+ } catch (Exception ex) { ex.printStackTrace(); }
+ }
+ }
+ /**
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+ System.err.println("Press enter to continue");
+ System.err.println(stdin.readLine()); */
+ org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch11NewtAWT.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch12AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch12AWT.java
new file mode 100644
index 000000000..aa75fa1b1
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch12AWT.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright 2013 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 javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import jogamp.nativewindow.jawt.JAWTUtil;
+import jogamp.opengl.GLEventListenerState;
+
+import com.jogamp.opengl.util.Animator;
+
+import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
+
+import org.junit.Test;
+
+/**
+ * Test re-association of GLContext/GLDrawables,
+ * here GLContext's survival of GLDrawable destruction
+ * and reuse w/ new or recreated GLDrawable.
+ * <p>
+ * Test utilizes {@link GLEventListenerState} for preserving the
+ * GLAutoDrawable state, i.e. GLContext, all GLEventListener
+ * and the GLAnimatorControl association.
+ * </p>
+ * <p>
+ * This test is using JOGL's AWT GLCanvas
+ * </p>
+ * <p>
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
+ * </p>
+ */
+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<args.length; i++) {
+ if(args[i].equals("-time")) {
+ i++;
+ try {
+ duration = Integer.parseInt(args[i]);
+ } catch (Exception ex) { ex.printStackTrace(); }
+ }
+ }
+ /**
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+ System.err.println("Press enter to continue");
+ System.err.println(stdin.readLine()); */
+ org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch12AWT.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch21Newt2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch21Newt2AWT.java
new file mode 100644
index 000000000..d56054886
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch21Newt2AWT.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright 2013 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 javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import jogamp.opengl.GLEventListenerState;
+
+import com.jogamp.opengl.util.Animator;
+
+import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
+
+import org.junit.Test;
+
+/**
+ * Test re-association of GLContext/GLDrawables,
+ * here GLContext's survival of GLDrawable destruction
+ * and reuse w/ new or recreated GLDrawable.
+ * <p>
+ * Test utilizes {@link GLEventListenerState} for preserving the
+ * GLAutoDrawable state, i.e. GLContext, all GLEventListener
+ * and the GLAnimatorControl association.
+ * </p>
+ * <p>
+ * 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
+ * </p>
+ * <p>
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
+ * </p>
+ */
+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<args.length; i++) {
+ if(args[i].equals("-time")) {
+ i++;
+ try {
+ duration = Integer.parseInt(args[i]);
+ } catch (Exception ex) { ex.printStackTrace(); }
+ }
+ }
+ /**
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+ System.err.println("Press enter to continue");
+ System.err.println(stdin.readLine()); */
+ org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch21Newt2AWT.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java
index ad2165301..fd99b4f61 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java
@@ -57,6 +57,7 @@ import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import javax.media.nativewindow.util.Dimension;
+import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
import javax.media.nativewindow.util.PointImmutable;
import javax.media.nativewindow.util.DimensionImmutable;
@@ -247,7 +248,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
animator.setModeBits(false, Animator.MODE_EXPECT_AWT_RENDERING_THREAD);
animator.setExclusiveContext(exclusiveContext);
- QuitAdapter quitAdapter = new QuitAdapter();
+ final QuitAdapter quitAdapter = new QuitAdapter();
//glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter));
//glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter));
glWindow.addKeyListener(quitAdapter);
@@ -265,6 +266,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
glWindow.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
if(e.getKeyChar()=='f') {
+ quitAdapter.enable(false);
new Thread() {
public void run() {
final Thread t = glWindow.setExclusiveContextThread(null);
@@ -272,7 +274,32 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
glWindow.setFullscreen(!glWindow.isFullscreen());
System.err.println("[set fullscreen post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets());
glWindow.setExclusiveContextThread(t);
+ quitAdapter.clear();
+ quitAdapter.enable(true);
} }.start();
+ } else if(e.getKeyChar()=='r') {
+ quitAdapter.enable(false);
+ if(glWindow.getParent()==null) {
+ System.err.println("XXX glWin to home");
+ glWindow.reparentWindow(newtCanvasAWT.getNativeWindow());
+ } else {
+ final InsetsImmutable nInsets = glWindow.getInsets();
+ java.awt.Insets aInsets = frame.getInsets();
+ System.err.println("XXX glWin to TOP - insets " + nInsets + ", " + aInsets);
+ glWindow.reparentWindow(null);
+ int dx, dy;
+ if(nInsets.getTotalHeight()==0) {
+ dx = aInsets.left;
+ dy = aInsets.top;
+ } else {
+ dx = nInsets.getLeftWidth();
+ dy = nInsets.getTopHeight();
+ }
+ glWindow.setPosition(frame.getX()+frame.getWidth()+dx, frame.getY()+dy);
+ }
+ glWindow.requestFocus();
+ quitAdapter.clear();
+ quitAdapter.enable(true);
}
}
});
@@ -308,7 +335,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
System.err.println("window resize "+rwsize+" -> pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets());
}
- while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) {
+ while(!quitAdapter.shouldQuit() && animator.getTotalFPSDuration()<duration) {
Thread.sleep(100);
}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/QuitAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/QuitAdapter.java
index 42d68dadb..59e243171 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/QuitAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/QuitAdapter.java
@@ -32,18 +32,27 @@ import com.jogamp.newt.event.*;
public class QuitAdapter extends WindowAdapter implements WindowListener, KeyListener {
boolean shouldQuit = false;
+ boolean enabled = true;
+ public void enable(boolean v) { enabled = v; }
+
+ public void clear() { shouldQuit = false; }
+
public boolean shouldQuit() { return shouldQuit; }
public void windowDestroyNotify(WindowEvent e) {
- System.err.println("QUIT Window "+Thread.currentThread());
- shouldQuit = true;
+ if( enabled ) {
+ System.err.println("QUIT Window "+Thread.currentThread());
+ shouldQuit = true;
+ }
}
public void keyTyped(KeyEvent e) {
- if(e.getKeyChar()=='q') {
- System.err.println("QUIT Key "+Thread.currentThread());
- shouldQuit = true;
+ if( enabled ) {
+ if(e.getKeyChar()=='q') {
+ System.err.println("QUIT Key "+Thread.currentThread());
+ shouldQuit = true;
+ }
}
}
public void keyPressed(KeyEvent e) {}