aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xmake/scripts/tests-x64.bat3
-rwxr-xr-xmake/scripts/tests.sh10
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java8
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java116
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java32
-rw-r--r--src/jogl/classes/javax/media/opengl/GLContext.java23
-rw-r--r--src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java13
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java24
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDrawableHelper.java31
-rw-r--r--src/jogl/classes/jogamp/opengl/GLEventListenerState.java267
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java7
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java11
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java19
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java12
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java3
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java12
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java2
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java17
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java19
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java6
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java27
-rw-r--r--src/nativewindow/native/x11/Xmisc.c2
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java18
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java9
-rw-r--r--src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java10
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java (renamed from src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java)46
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java352
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/GLEventListenerCounter.java65
28 files changed, 925 insertions, 239 deletions
diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat
index b66f8b8ab..8bee4c6dd 100755
--- a/make/scripts/tests-x64.bat
+++ b/make/scripts/tests-x64.bat
@@ -12,7 +12,8 @@ REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedCon
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile02NEWT %*
-REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT %*
+scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT %*
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT %*
REM scripts\java-win64.bat com.jogamp.opengl.test.junit.jogl.acore.TestGPUMemSec01NEWT %*
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 80e418056..9625519b9 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -89,6 +89,7 @@ function jrun() {
#D_ARGS="-Djogl.debug.FBObject"
#D_ARGS="-Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.GLSLCode -Djogl.debug.DebugGL -Djogl.debug.TraceGL"
+ #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLContext.TraceSwitch"
#D_ARGS="-Djogl.debug.GLContext.TraceSwitch"
#D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLCode"
#D_ARGS="-Djogl.debug.FixedFuncPipeline -Djogl.debug.GLSLState"
@@ -105,6 +106,7 @@ function jrun() {
#D_ARGS="-Djogamp.debug=all"
#D_ARGS="-Djogamp.debug=all -Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all"
#D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all"
+ #D_ARGS="-Dnativewindow.debug.X11Util"
#D_ARGS="-Djogl.debug.Animator"
#D_ARGS="-Djogl.debug=all -Dnewt.debug=all"
#D_ARGS="-Djogl.debug.GLDrawable -Djogl.debug.GLContext -Djogl.debug.GLCanvas"
@@ -284,7 +286,8 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES1NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $*
-#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch02NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLPointsNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug651NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLMesaBug658NEWT $*
@@ -303,6 +306,9 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch01NEWT $*
+testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitch11NEWT $*
+
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer01GLCanvasAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.acore.TestOffscreenLayer02NewtCanvasAWT $*
@@ -399,7 +405,7 @@ function testawtswt() {
#
# newt.awt (testawt)
#
-testawt com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $*
+#testawt com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper $*
#testawt com.jogamp.opengl.test.junit.newt.TestEventSourceNotAWTBug
#testawt com.jogamp.opengl.test.junit.newt.TestFocus01SwingAWTRobot $*
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
index 38a8deef8..38315dc72 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawableDelegate.java
@@ -65,7 +65,10 @@ import jogamp.opengl.GLDrawableImpl;
public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAutoDrawable {
/**
* @param drawable a valid and already realized {@link GLDrawable}
- * @param context a valid {@link GLContext}, may not be made current (created) yet.
+ * @param context a valid {@link GLContext},
+ * may not have been made current (created) yet,
+ * may not be associated w/ <code>drawable<code> yet,
+ * may be <code>null</code> for lazy initialization
* @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}.
* @param ownDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued,
* otherwise pass <code>false</code>. Closing the device is required in case
@@ -78,9 +81,6 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase implements GLAuto
if(null == drawable) {
throw new IllegalArgumentException("null drawable");
}
- if(null == context) {
- throw new IllegalArgumentException("null context");
- }
if(!drawable.isRealized()) {
throw new IllegalArgumentException("drawable not realized");
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
index cc81e4820..c03e4bfa4 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLDrawableUtil.java
@@ -27,17 +27,14 @@
*/
package com.jogamp.opengl.util;
-import java.util.ArrayList;
-import java.util.List;
-
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLEventListener;
-import javax.media.opengl.GLRunnable;
import jogamp.opengl.Debug;
+import jogamp.opengl.GLEventListenerState;
/**
* Providing utility functions dealing w/ {@link GLDrawable}s, {@link GLAutoDrawable} and their {@link GLEventListener}.
@@ -83,7 +80,7 @@ public class GLDrawableUtil {
dest.addGLEventListener(listener);
if(preserveInitState && initialized) {
dest.setGLEventListenerInitState(listener, true);
- dest.invoke(false, new ReshapeGLEventListener(listener));
+ dest.invoke(false, new GLEventListenerState.ReshapeGLEventListener(listener));
} // else .. !init state is default
}
@@ -121,108 +118,13 @@ public class GLDrawableUtil {
* @param b
*/
public static final void swapGLContextAndAllGLEventListener(GLAutoDrawable a, GLAutoDrawable b) {
- final List<GLRunnable> aGLCmds = new ArrayList<GLRunnable>();
- final List<GLRunnable> bGLCmds = new ArrayList<GLRunnable>();
- final GLAnimatorControl aAnim = a.getAnimator();
- final GLAnimatorControl bAnim = b.getAnimator();
- final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause();
- final boolean bIsPaused = isAnimatorAnimatingOnOtherThread(bAnim) && bAnim.pause();
-
- //
- // remove and cache all GLEventListener and their init-state
- //
- final int aSz = a.getGLEventListenerCount();
- final GLEventListener[] aGLE = new GLEventListener[aSz];
- final boolean[] aInit = new boolean[aSz];
- for(int i=0; i<aSz; i++) {
- final GLEventListener l = a.getGLEventListener(0);
- aInit[i] = a.getGLEventListenerInitState(l);
- aGLE[i] = a.removeGLEventListener( l );
- }
- final int bSz = b.getGLEventListenerCount();
- final GLEventListener[] bGLE = new GLEventListener[bSz];
- final boolean[] bInit = new boolean[bSz];
- for(int i=0; i<bSz; i++) {
- final GLEventListener l = b.getGLEventListener(0);
- bInit[i] = b.getGLEventListenerInitState(l);
- bGLE[i] = b.removeGLEventListener( l );
- }
-
- //
- // trigger glFinish to sync GL ctx
- //
- a.invoke(true, glFinish);
- b.invoke(true, glFinish);
-
- //
- // switch context and
- // trigger GL-Viewport reset and reshape of all initialized GLEventListeners
- //
- b.setContext( a.setContext( b.getContext() ) );
- aGLCmds.add(setViewport);
- bGLCmds.add(setViewport);
- for(int i=0; i<aSz; i++) {
- if( aInit[i] ) {
- bGLCmds.add(new ReshapeGLEventListener(aGLE[i]));
- }
- }
- for(int i=0; i<bSz; i++) {
- if( bInit[i] ) {
- aGLCmds.add(new ReshapeGLEventListener(bGLE[i]));
- }
- }
- aGLCmds.add(glFinish);
- bGLCmds.add(glFinish);
- a.invoke(true, aGLCmds);
- b.invoke(true, bGLCmds);
-
- // add all cached GLEventListener to their destination and fix their init-state
- for(int i=0; i<bSz; i++) {
- final GLEventListener l = bGLE[i];
- a.addGLEventListener( l );
- if( bInit[i] ) {
- a.setGLEventListenerInitState(l, true);
- } // else uninitialized is default after add
- }
- for(int i=0; i<aSz; i++) {
- final GLEventListener l = aGLE[i];
- b.addGLEventListener( l );
- if( aInit[i] ) {
- b.setGLEventListenerInitState(l, true);
- } // else uninitialized is default after add
- }
+ final GLEventListenerState gllsA = GLEventListenerState.moveFrom(a);
+ final GLEventListenerState gllsB = GLEventListenerState.moveFrom(b);
- if(aIsPaused) { aAnim.resume(); }
- if(bIsPaused) { bAnim.resume(); }
+ gllsA.moveTo(b);
+ gllsB.moveTo(a);
}
- static GLRunnable setViewport = new GLRunnable() {
- @Override
- public boolean run(GLAutoDrawable drawable) {
- drawable.getGL().glViewport(0, 0, drawable.getWidth(), drawable.getHeight());
- return true;
- }
- };
- static GLRunnable glFinish = new GLRunnable() {
- @Override
- public boolean run(GLAutoDrawable drawable) {
- drawable.getGL().glFinish();
- return true;
- }
- };
-
- private static class ReshapeGLEventListener implements GLRunnable {
- private GLEventListener listener;
- ReshapeGLEventListener(GLEventListener listener) {
- this.listener = listener;
- }
- @Override
- public boolean run(GLAutoDrawable drawable) {
- listener.reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight());
- return true;
- }
- }
-
/**
* Swaps the {@link GLContext} of given {@link GLAutoDrawable}
* and {@link GLAutoDrawable#disposeGLEventListener(GLEventListener, boolean) disposes}
@@ -251,11 +153,11 @@ public class GLDrawableUtil {
}
dest.setContext( src.setContext( dest.getContext() ) );
- src.invoke(true, setViewport);
- dest.invoke(true, setViewport);
+ src.invoke(true, GLEventListenerState.setViewport);
+ dest.invoke(true, GLEventListenerState.setViewport);
if(aIsPaused) { aAnim.resume(); }
if(bIsPaused) { bAnim.resume(); }
}
-
+
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index a7db3f3fd..612ff6bdb 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -130,37 +130,35 @@ public interface GLAutoDrawable extends GLDrawable {
public GLContext getContext();
/**
- * Associate a new context to this drawable and also propagates the context/drawable switch by
- * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- * <code>drawable</code> might be an inner GLDrawable instance if using a delegation pattern,
- * or this GLAutoDrawable instance.
+ * Associate the new context, <code>newtCtx</code>, to this auto-drawable.
* <p>
- * If the old or new context was current on this thread, it is being released before switching the drawable.
+ * The current context will be dis-associated from this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first.
+ * </p>
+ * <p>
+ * The new context will be associated with this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
+ * </p>
+ * <p>
+ * If the old or new context was current on this thread, it is being released before switching the association.
* The new context will be made current afterwards, if it was current before.
* However the user shall take extra care that no other thread
* attempts to make this context current.
* </p>
* <p>
- * Be aware that the old context is still bound to the drawable,
- * and that one context can only be bound to one drawable at one time!
- * </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 before setting the new context, i.e.:
+ * not assigning it to another drawable, it shall be
+ * destroyed, i.e.:
* <pre>
- GLContext oldCtx = glad.getContext();
+ GLContext oldCtx = glad.setContext(newCtx);
if(null != oldCtx) {
oldCtx.destroy();
}
- glad.setContext(newCtx);
* </pre>
- * This is required, since a context must have a valid drawable at all times
- * and this API shall not restrict the user in any way.
* </p>
*
- * @param newCtx the new context
- * @return the replaced GLContext, maybe <code>null</code>
+ * @param newCtx the new context, maybe <code>null</code> for dis-association.
+ * @return the previous GLContext, maybe <code>null</code>
*
* @see GLContext#setGLDrawable(GLDrawable, boolean)
* @see GLContext#setGLReadDrawable(GLDrawable)
diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java
index 455f2d70d..4817add4d 100644
--- a/src/jogl/classes/javax/media/opengl/GLContext.java
+++ b/src/jogl/classes/javax/media/opengl/GLContext.java
@@ -217,15 +217,20 @@ public abstract class GLContext {
/**
* Sets the read/write drawable for framebuffer operations.
* <p>
+ * If the arguments reflect the current state of this context
+ * this method is a no-operation and returns the old and current {@link GLDrawable}.
+ * </p>
+ * <p>
* If the context was current on this thread, it is being released before switching the drawable
* and made current afterwards. However the user shall take extra care that not other thread
* attempts to make this context current. Otherwise a race condition may happen.
* </p>
- * @param readWrite the read/write drawable for framebuffer operations.
- * @param setWriteOnly if <code>true</code> and if the current read-drawable differs
- * from the write-drawable ({@link #setGLReadDrawable(GLDrawable)}),
- * only change the write-drawable. Otherwise set both drawables.
- * @return the replaced read/write drawable
+ * @param readWrite The read/write drawable for framebuffer operations, maybe <code>null</code> to remove association.
+ * @param setWriteOnly Only change the write-drawable, if <code>setWriteOnly</code> is <code>true</code> and
+ * if the {@link #getGLReadDrawable() read-drawable} differs
+ * from the {@link #getGLDrawable() write-drawable}.
+ * Otherwise set both drawables, read and write.
+ * @return The previous read/write drawable
*
* @throws GLException in case <code>null</code> is being passed or
* this context is made current on another thread.
@@ -239,6 +244,12 @@ public abstract class GLContext {
/**
* Returns the write-drawable this context uses for framebuffer operations.
+ * <p>
+ * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)},
+ * it equals to the write-drawable (default).
+ * </p>
+ * @see #setGLDrawable(GLDrawable, boolean)
+ * @see #setGLReadDrawable(GLDrawable)
*/
public abstract GLDrawable getGLDrawable();
@@ -259,7 +270,7 @@ public abstract class GLContext {
*
* @param read the read-drawable for read framebuffer operations.
* If null is passed, the default write drawable will be set.
- * @return the replaced read-drawable
+ * @return the previous read-drawable
*
* @throws GLException in case a read drawable is not supported or
* this context is made current on another thread.
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index eadd59559..c20197e72 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -74,8 +74,12 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking
/**
- * @param drawable upstream {@link GLDrawableImpl} instance, may be null for lazy initialization
- * @param context upstream {@link GLContextImpl} instance, may be null for lazy initialization
+ * @param drawable upstream {@link GLDrawableImpl} instance,
+ * may be <code>null</code> for lazy initialization
+ * @param context upstream {@link GLContextImpl} instance,
+ * may not have been made current (created) yet,
+ * may not be associated w/ <code>drawable<code> yet,
+ * may be <code>null</code> for lazy initialization
* @param ownsDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued,
* otherwise pass <code>false</code>. Closing the device is required in case
* the drawable is created w/ it's own new instance, e.g. offscreen drawables,
@@ -85,6 +89,9 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
this.drawable = drawable;
this.context = context;
this.ownsDevice = ownsDevice;
+ if(null != context && null != drawable) {
+ context.setGLDrawable(drawable, false);
+ }
resetFPSCounter();
}
@@ -326,7 +333,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
final GLContext oldCtx = context;
final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
- if(newCtxCurrent) {
+ if(newCtxCurrent) { // implies null != newCtx
context.makeCurrent();
}
return oldCtx;
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index f2c2cfada..2a2b6a8fd 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
@@ -203,8 +203,8 @@ public abstract class GLContextImpl extends GLContext {
@Override
public final GLDrawable setGLDrawable(GLDrawable readWrite, boolean setWriteOnly) {
- if(null==readWrite) {
- throw new GLException("Null read/write drawable not allowed");
+ if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) {
+ return drawable; // no change.
}
final boolean lockHeld = lock.isOwner(Thread.currentThread());
if(lockHeld) {
@@ -212,16 +212,20 @@ public abstract class GLContextImpl extends GLContext {
} else if(lock.isLockedByOtherThread()) { // still could glitch ..
throw new GLException("GLContext current by other thread ("+lock.getOwner()+"), operation not allowed.");
}
- if(!setWriteOnly || drawableRead==drawable) { // if !setWriteOnly || !explicitReadDrawable
+ if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable
drawableRead = (GLDrawableImpl) readWrite;
}
final GLDrawableImpl old = drawable;
- old.associateContext(this, false);
- drawableRetargeted = null != drawable;
+ if( null != old ) {
+ old.associateContext(this, false);
+ }
+ drawableRetargeted |= null != drawable && readWrite != drawable;
drawable = (GLDrawableImpl) readWrite ;
- drawable.associateContext(this, true);
- if(lockHeld) {
- makeCurrent();
+ if( null != drawable ) {
+ drawable.associateContext(this, true);
+ if( lockHeld ) {
+ makeCurrent();
+ }
}
return old;
}
@@ -334,7 +338,7 @@ public abstract class GLContextImpl extends GLContext {
", surf "+toHexString(drawable.getHandle())+", isShared "+GLContextShareSet.isShared(this)+" - "+lock);
}
if (contextHandle != 0) {
- int lockRes = drawable.lockSurface();
+ final int lockRes = drawable.lockSurface();
if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
// this would be odd ..
throw new GLException("Surface not ready to lock: "+drawable);
@@ -408,7 +412,7 @@ public abstract class GLContextImpl extends GLContext {
throw new GLException("Destination OpenGL context has not been created");
}
- int lockRes = drawable.lockSurface();
+ final int lockRes = drawable.lockSurface();
if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
// this would be odd ..
throw new GLException("Surface not ready to lock");
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index f8c58ee34..5d113ff83 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -131,30 +131,36 @@ public class GLDrawableHelper {
}
/**
- * Associate a new context to the drawable and also propagates the context/drawable switch by
- * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- * <p>
- * If the old or new context was current on this thread, it is being released before switching the drawable.
+ * Switch {@link GLContext} / {@link GLDrawable} association.
+ * <p>
+ * Dis-associate <code>oldCtx</code> from <code>drawable</code>
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}.
* </p>
* <p>
- * Be aware that the old context is still bound to the drawable,
- * and that one context can only bound to one drawable at one time!
+ * Re-associate <code>newCtx</code> with <code>drawable</code>
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
+ * </p>
+ * <p>
+ * If the old or new context was current on this thread, it is being released before switching the drawable.
* </p>
* <p>
* No locking is being performed on the drawable, caller is required to take care of it.
* </p>
*
* @param drawable the drawable which context is changed
- * @param oldCtx the old context
- * @param newCtx the new context
+ * @param oldCtx the old context, maybe <code>null</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)
*/
public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) {
- if( null != oldCtx && oldCtx.isCurrent() ) {
- oldCtx.release();
+ if( null != oldCtx ) {
+ if( oldCtx.isCurrent() ) {
+ oldCtx.release();
+ }
+ oldCtx.setGLDrawable(null, true); // dis-associate old pair
}
final boolean newCtxCurrent;
if(null!=newCtx) {
@@ -163,8 +169,8 @@ public class GLDrawableHelper {
newCtx.release();
}
newCtx.setContextCreationFlags(newCtxCreationFlags);
- newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch
- } else {
+ newCtx.setGLDrawable(drawable, true); // re-associate new pair
+ } else {
newCtxCurrent = false;
}
return newCtxCurrent;
@@ -203,6 +209,7 @@ public class GLDrawableHelper {
}
context.getGL().glFinish();
context.release();
+ context.setGLDrawable(null, true); // dis-associate
}
if(null != proxySurface) {
diff --git a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java
new file mode 100644
index 000000000..dea2bc85b
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java
@@ -0,0 +1,267 @@
+/**
+ * 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 jogamp.opengl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.AbstractGraphicsScreen;
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.VisualIDHolder;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLRunnable;
+
+import com.jogamp.nativewindow.MutableGraphicsConfiguration;
+
+/**
+ * GLEventListenerState is holding {@link GLAutoDrawable} components crucial
+ * to relocating all its {@link GLEventListener} w/ their operating {@link GLContext}, etc.
+ * The components are:
+ * <ul>
+ * <li>{@link AbstractGraphicsScreen}</li>
+ * <li>{@link GLCapabilitiesImmutable}</li>
+ * <li>{@link GLContext} operating all {@link GLEventListener}</li>
+ * <li>All {@link GLEventListener}</li>
+ * <li>All {@link GLEventListener}'s init state</li>
+ * <li>{@link GLAnimatorControl}</li>
+ * </ul>
+ * <p>
+ * A GLEventListenerState instance can be created while components are {@link #moveFrom(GLAutoDrawable) moved from} a {@link GLAutoDrawable}
+ * to the new instance, which gains {@link #isOwner() ownership} of the moved components.
+ * </p>
+ * <p>
+ * A GLEventListenerState instance's components can be {@link #moveTo(GLAutoDrawable) moved to} a {@link GLAutoDrawable},
+ * while loosing {@link #isOwner() ownership} of the moved components.
+ * </p>
+ * <p>
+ */
+public class GLEventListenerState {
+ private GLEventListenerState(AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, GLContext context, int count, GLAnimatorControl anim) {
+ this.screen = screen;
+ this.caps = caps;
+ this.context = context;
+ this.listeners = new GLEventListener[count];
+ this.listenersInit = new boolean[count];
+ this.anim = anim;
+ this.owner = true;
+ }
+ /**
+ * Returns <code>true</code>, if this instance is the current owner of the components,
+ * otherwise <code>false</code>.
+ * <p>
+ * Ownership is lost if {@link #moveTo(GLAutoDrawable)} is being called successfully
+ * and all components are transferred to the new {@link GLAutoDrawable}.
+ * </p>
+ */
+ public final boolean isOwner() { return owner; }
+
+ public final int listenerCount() { return listeners.length; }
+
+ public final AbstractGraphicsScreen screen;
+ public final GLCapabilitiesImmutable caps;
+ public final GLContext context;
+ public final GLEventListener[] listeners;
+ public final boolean[] listenersInit;
+ public final GLAnimatorControl anim;
+
+ private boolean owner;
+
+ /**
+ * Last resort to destroy and loose ownership
+ */
+ public void destroy() {
+ if( owner ) {
+ final int aSz = listenerCount();
+ for(int i=0; i<aSz; i++) {
+ listeners[i] = null;
+ }
+ // context.destroy(); - NPE (null drawable)
+ screen.getDevice().close();
+ owner = false;
+ }
+ }
+
+ /**
+ * Moves all GLEventListenerState components from the given {@link GLAutoDrawable}
+ * to a newly created instance.
+ * <p>
+ * Note that all components are removed from the {@link GLAutoDrawable},
+ * i.e. the {@link GLContext}, all {@link GLEventListener}.
+ * </p>
+ * <p>
+ * If the {@link GLAutoDrawable} was added to a {@link GLAnimatorControl}, it is removed
+ * and the {@link GLAnimatorControl} added to the GLEventListenerState.
+ * </p>
+ * <p>
+ * The returned GLEventListenerState instance is the {@link #isOwner() owner of the components}.
+ * </p>
+ *
+ * @param a {@link GLAutoDrawable} source to move components from
+ * @return new GLEventListenerState instance {@link #isOwner() owning} moved components.
+ *
+ * @see #moveTo(GLAutoDrawable)
+ */
+ public static GLEventListenerState moveFrom(GLAutoDrawable a) {
+ final int aSz = a.getGLEventListenerCount();
+
+ // Create new AbstractGraphicsScreen w/ cloned AbstractGraphicsDevice for future GLAutoDrawable
+ // allowing this AbstractGraphicsDevice to loose ownership -> not closing display/device!
+ final AbstractGraphicsConfiguration aCfg1 = a.getNativeSurface().getGraphicsConfiguration();
+ final GLCapabilitiesImmutable caps1 = (GLCapabilitiesImmutable) aCfg1.getChosenCapabilities();
+ final AbstractGraphicsScreen aScreen1 = aCfg1.getScreen();
+ final AbstractGraphicsDevice aDevice1 = aScreen1.getDevice();
+ final AbstractGraphicsDevice aDevice2 = (AbstractGraphicsDevice) aDevice1.clone();
+ final AbstractGraphicsScreen aScreen2 = NativeWindowFactory.createScreen( NativeWindowFactory.getNativeWindowType(false), aDevice2, aScreen1.getIndex() );
+
+ final GLAnimatorControl aAnim = a.getAnimator();
+ if( null != aAnim ) {
+ aAnim.remove(a); // also handles ECT
+ }
+
+ final GLEventListenerState glls = new GLEventListenerState(aScreen2, caps1, a.getContext(), aSz, aAnim);
+
+ //
+ // remove and cache all GLEventListener and their init-state
+ //
+ for(int i=0; i<aSz; i++) {
+ final GLEventListener l = a.getGLEventListener(0);
+ glls.listenersInit[i] = a.getGLEventListenerInitState(l);
+ glls.listeners[i] = a.removeGLEventListener( l );
+ }
+
+ //
+ // trigger glFinish to sync GL ctx
+ //
+ a.invoke(true, glFinish);
+
+ a.setContext( null );
+ aDevice1.clearHandleOwner(); // don't close handle
+
+ return glls;
+ }
+
+ /**
+ * Moves all GLEventListenerState components to the given {@link GLAutoDrawable}
+ * from this instance, while loosing {@link #isOwner() ownership}.
+ * <p>
+ * If the previous {@link GLAutoDrawable} was removed from a {@link GLAnimatorControl} by previous {@link #moveFrom(GLAutoDrawable)},
+ * the given {@link GLAutoDrawable} is added to the cached {@link GLAnimatorControl}.
+ * This operation is skipped, if the given {@link GLAutoDrawable} is already added to a {@link GLAnimatorControl} instance.
+ * </p>
+ * <p>
+ * Note: After this operation, the GLEventListenerState reference should be released.
+ * </p>
+ *
+ * @param a {@link GLAutoDrawable} destination to move GLEventListenerState components to
+ *
+ * @throws GLException if the {@link GLAutoDrawable}'s configuration is incompatible, i.e. different {@link GLCapabilitiesImmutable}.
+ *
+ * @see #moveFrom(GLAutoDrawable)
+ * @see #isOwner()
+ */
+ public final void moveTo(GLAutoDrawable a) {
+ final List<GLRunnable> aGLCmds = new ArrayList<GLRunnable>();
+ final int aSz = listenerCount();
+
+ final MutableGraphicsConfiguration aCfg = (MutableGraphicsConfiguration) a.getNativeSurface().getGraphicsConfiguration();
+ final GLCapabilitiesImmutable aCaps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities();
+ if( caps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) != aCaps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) ) {
+ throw new GLException("XXX: Incompatible - Prev Holder: "+caps+", New Holder "+caps);
+ }
+ final GLContext prevContext = a.getContext();
+ if( null != prevContext) {
+ prevContext.destroy();
+ }
+ final AbstractGraphicsScreen preScreen = aCfg.getScreen();
+ aCfg.setScreen( screen );
+ preScreen.getDevice().close();
+ a.setContext( context );
+ owner = false;
+
+ //
+ // Trigger GL-Viewport reset and reshape of all initialized GLEventListeners
+ //
+ aGLCmds.add(setViewport);
+ for(int i=0; i<aSz; i++) {
+ if( listenersInit[i] ) {
+ aGLCmds.add(new ReshapeGLEventListener( listeners[i] ) );
+ }
+ }
+ aGLCmds.add(glFinish);
+ a.invoke(true, aGLCmds);
+
+ // add all cached GLEventListener to their destination and fix their init-state
+ for(int i=0; i<aSz; i++) {
+ final GLEventListener l = listeners[i];
+ a.addGLEventListener( l );
+ if( listenersInit[i] ) {
+ a.setGLEventListenerInitState(l, true);
+ } // else uninitialized is default after add
+ listeners[i] = null;
+ }
+
+ if( null != anim && null == a.getAnimator() ) {
+ anim.add(a); // also handles ECT
+ }
+ }
+
+ public static GLRunnable setViewport = new GLRunnable() {
+ @Override
+ public boolean run(GLAutoDrawable drawable) {
+ drawable.getGL().glViewport(0, 0, drawable.getWidth(), drawable.getHeight());
+ return true;
+ }
+ };
+
+ public static GLRunnable glFinish = new GLRunnable() {
+ @Override
+ public boolean run(GLAutoDrawable drawable) {
+ drawable.getGL().glFinish();
+ return true;
+ }
+ };
+
+ public static class ReshapeGLEventListener implements GLRunnable {
+ private GLEventListener listener;
+ public ReshapeGLEventListener(GLEventListener listener) {
+ this.listener = listener;
+ }
+ @Override
+ public boolean run(GLAutoDrawable drawable) {
+ listener.reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight());
+ return true;
+ }
+ }
+}
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java
index 2d5af86b9..eaad513aa 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java
@@ -37,7 +37,14 @@ public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration {
super(screen, capsChosen, capsRequested);
}
+ @Override
public void setChosenCapabilities(CapabilitiesImmutable caps) {
super.setChosenCapabilities(caps);
}
+
+ @Override
+ public void setScreen(AbstractGraphicsScreen screen) {
+ super.setScreen(screen);
+ }
+
}
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
index b824350ff..63200b393 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java
@@ -38,7 +38,7 @@ import javax.media.nativewindow.*;
*/
public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneable {
final long[] nativeDisplayID = new long[1];
- final EGLDisplayLifecycleCallback eglLifecycleCallback;
+ /* final */ EGLDisplayLifecycleCallback eglLifecycleCallback;
/**
* Hack to allow inject a EGL termination call.
@@ -113,8 +113,13 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl
}
@Override
- public String toString() {
- return "EGLGraphicsDevice[type EGL, connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", nativeDisplayID 0x"+Long.toHexString(nativeDisplayID[0])+", eglLifecycleCallback "+(null != eglLifecycleCallback)+"]";
+ public boolean isHandleOwner() {
+ return null != eglLifecycleCallback;
+ }
+ @Override
+ public void clearHandleOwner() {
+ eglLifecycleCallback = null;
}
+
}
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
index d3e339586..a2af83359 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java
@@ -395,27 +395,12 @@ public class SWTAccessor {
}
/**
- *
* @param device
* @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
* @return
- * @throws UnsupportedOperationException
*/
- public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) throws UnsupportedOperationException {
- if( isX11 ) {
- X11GraphicsDevice x11Device = (X11GraphicsDevice)device;
- if(0 > screen) {
- screen = x11Device.getDefaultScreen();
- }
- return new X11GraphicsScreen(x11Device, screen);
- }
- if(0 > screen) {
- screen = 0; // FIXME: Needs native API utilization
- }
- if( isWindows || isOSX ) {
- return new DefaultGraphicsScreen(device, screen);
- }
- throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
+ public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) {
+ return NativeWindowFactory.createScreen(nwt, device, screen);
}
public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) {
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
index 0f28ca67c..da3b31de4 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
@@ -45,7 +45,7 @@ import javax.media.nativewindow.ToolkitLock;
*/
public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable {
- final boolean handleOwner;
+ /* final */ boolean handleOwner;
final boolean isXineramaEnabled;
/** Constructs a new X11GraphicsDevice corresponding to the given connection and default
@@ -153,5 +153,13 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl
}
return super.close();
}
+
+ @Override
+ public boolean isHandleOwner() {
+ return handleOwner;
+ }
+ @Override
+ public void clearHandleOwner() {
+ handleOwner = false;
+ }
}
-
diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java
index ebdaf2fbb..4e45113d4 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java
@@ -42,8 +42,9 @@ package javax.media.nativewindow;
/** A marker interface describing a graphics configuration, visual, or
pixel format in a toolkit-independent manner. */
-
public interface AbstractGraphicsConfiguration extends VisualIDHolder, Cloneable {
+ public Object clone();
+
/**
* Return the screen this graphics configuration is valid for
*/
diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
index 8ecd5242d..585cd1f09 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
@@ -45,7 +45,6 @@ import jogamp.nativewindow.Debug;
/** A interface describing a graphics device in a
toolkit-independent manner.
*/
-
public interface AbstractGraphicsDevice extends Cloneable {
public static final boolean DEBUG = Debug.debug("GraphicsDevice");
@@ -58,6 +57,8 @@ public interface AbstractGraphicsDevice extends Cloneable {
/** Default unit id for the 1st device: 0 */
public static int DEFAULT_UNIT = 0;
+ public Object clone();
+
/**
* Returns the type of the underlying subsystem, ie
* NativeWindowFactory.TYPE_KD, NativeWindowFactory.TYPE_X11, ..
@@ -143,10 +144,17 @@ public interface AbstractGraphicsDevice extends Cloneable {
* <p>
* Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice}
* or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice}
- * issue the native close operation or skip it depending on the handles's ownership.
+ * issue the native close operation or skip it depending on the {@link #isHandleOwner() handles's ownership}.
* </p>
*
* @return true if the handle was not <code>null</code> and closing was successful, otherwise false.
*/
public boolean close();
+
+ /**
+ * @return <code>true</code> if instance owns the handle to issue {@link #close()}, otherwise <code>false</code>.
+ */
+ public boolean isHandleOwner();
+
+ public void clearHandleOwner();
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java
index eb2cc9120..acb98073b 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java
@@ -44,6 +44,8 @@ package javax.media.nativewindow;
*/
public interface AbstractGraphicsScreen extends Cloneable {
+ public Object clone();
+
/**
* Return the device this graphics configuration is valid for
*/
diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java
index a33c3792a..6b23172e1 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java
@@ -93,25 +93,26 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics
/**
* Set the capabilities to a new value.
*
+ * <p>
* The use case for setting the Capabilities at a later time is
- * a change of the graphics device in a multi-screen environment.<br>
- *
+ * a change or re-validation of capabilities.
+ * </p>
* @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen)
*/
protected void setChosenCapabilities(CapabilitiesImmutable capsChosen) {
- capabilitiesChosen = capsChosen;
+ this.capabilitiesChosen = capsChosen;
}
/**
* Set a new screen.
*
+ * <p>
* the use case for setting a new screen at a later time is
- * a change of the graphics device in a multi-screen environment.<br>
- *
- * A copy of the passed object is being used.
+ * a change of the graphics device in a multi-screen environment.
+ * </p>
*/
- final protected void setScreen(DefaultGraphicsScreen screen) {
- this.screen = (AbstractGraphicsScreen) screen.clone();
+ protected void setScreen(AbstractGraphicsScreen screen) {
+ this.screen = screen;
}
@Override
diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
index 9288652d9..b3ae4628c 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
@@ -37,10 +37,10 @@ import jogamp.nativewindow.NativeWindowFactoryImpl;
public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice {
private static final String separator = "_";
- private String type;
- protected String connection;
- protected int unitID;
- protected String uniqueID;
+ private final String type;
+ protected final String connection;
+ protected final int unitID;
+ protected final String uniqueID;
protected long handle;
protected ToolkitLock toolkitLock;
@@ -171,8 +171,17 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
}
@Override
+ public boolean isHandleOwner() {
+ return false;
+ }
+
+ @Override
+ public void clearHandleOwner() {
+ }
+
+ @Override
public String toString() {
- return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", "+toolkitLock+"]";
+ return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", owner "+isHandleOwner()+", "+toolkitLock+"]";
}
/**
diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java
index f50bd0e14..9fa58c7a3 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java
@@ -33,8 +33,8 @@
package javax.media.nativewindow;
public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen {
- AbstractGraphicsDevice device;
- private int idx;
+ private final AbstractGraphicsDevice device;
+ private final int idx;
public DefaultGraphicsScreen(AbstractGraphicsDevice device, int idx) {
this.device = device;
@@ -57,7 +57,7 @@ public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen
public AbstractGraphicsDevice getDevice() {
return device;
}
-
+
public int getIndex() {
return idx;
}
diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
index d7f28a986..07702c762 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
@@ -48,6 +48,10 @@ import jogamp.nativewindow.ResourceToolkitLock;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
+import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
+import com.jogamp.nativewindow.x11.X11GraphicsDevice;
+import com.jogamp.nativewindow.x11.X11GraphicsScreen;
/** Provides a pluggable mechanism for arbitrary window toolkits to
adapt their components to the {@link NativeWindow} interface,
@@ -428,6 +432,29 @@ public abstract class NativeWindowFactory {
return NativeWindowFactoryImpl.getNullToolkitLock();
}
+ /**
+ * @param device
+ * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
+ * @return newly created AbstractGraphicsScreen of given native type
+ */
+ public static AbstractGraphicsScreen createScreen(String type, AbstractGraphicsDevice device, int screen) {
+ if( TYPE_X11 == type ) {
+ final X11GraphicsDevice x11Device = (X11GraphicsDevice)device;
+ if(0 > screen) {
+ screen = x11Device.getDefaultScreen();
+ }
+ return new X11GraphicsScreen(x11Device, screen);
+ }
+ if(0 > screen) {
+ screen = 0; // FIXME: Needs native API utilization
+ }
+ if( TYPE_AWT == type ) {
+ final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) device;
+ return new AWTGraphicsScreen(awtDevice);
+ }
+ return new DefaultGraphicsScreen(device, screen);
+ }
+
/** Returns the appropriate NativeWindowFactory to handle window
objects of the given type. The windowClass might be {@link
NativeWindow NativeWindow}, in which case the client has
diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c
index a8d45f288..017c52df2 100644
--- a/src/nativewindow/native/x11/Xmisc.c
+++ b/src/nativewindow/native/x11/Xmisc.c
@@ -180,7 +180,7 @@ static int errorHandlerThrowException = 0;
static int x11ErrorHandler(Display *dpy, XErrorEvent *e)
{
- if(!errorHandlerQuiet) {
+ if( !errorHandlerQuiet || errorHandlerDebug ) {
const char * errnoStr = strerror(errno);
char errCodeStr[80];
char reqCodeStr[80];
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index 96d0f6e3b..7fccb6622 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -458,24 +458,22 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind
} else {
t0 = 0;
}
-
- /* if (nativeWindowCreated && null != context) {
- throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)");
- } */
- if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) {
- NativeWindow nw;
+
+ if (null == drawable && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) {
+ if( ( null != context ) ) {
+ throw new InternalError("GLWindow.LifecycleHook.setVisiblePost: "+WindowImpl.getThreadName()+" - Null drawable, but valid context - "+GLWindow.this);
+ }
+ final NativeWindow nw;
if (window.getWrappedWindow() != null) {
nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getPrivateGraphicsConfiguration());
} else {
nw = window;
}
- GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities();
+ final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities();
if(null==factory) {
factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
}
- if(null==drawable) {
- drawable = (GLDrawableImpl) factory.createGLDrawable(nw);
- }
+ drawable = (GLDrawableImpl) factory.createGLDrawable(nw);
drawable.setRealized(true);
context = (GLContextImpl) drawable.createContext(sharedContext);
context.setContextCreationFlags(additionalCtxCreationFlags);
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 88fbfc951..d033a8794 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -629,10 +629,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
@Override
- public long getDisplayHandle() {
- // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle();
- return screen.getDisplay().getHandle(); // shortcut
- }
+ public final long getDisplayHandle() {
+ return config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
+ }
@Override
public final int getScreenIndex() {
@@ -880,6 +879,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if( isNativeValid() ) {
screen.removeScreenModeListener(screenModeListenerImpl);
closeNativeImpl();
+ config.getScreen().getDevice().close();
+ setGraphicsConfiguration(null);
removeScreenReference();
}
Display dpy = screen.getDisplay();
diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
index 8cea76ca5..c55fddd07 100644
--- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java
@@ -72,7 +72,7 @@ public class WindowDriver extends WindowImpl {
// Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering
final long renderDeviceHandle = X11Util.openDisplay(edtDevice.getConnection());
if( 0 == renderDeviceHandle ) {
- throw new RuntimeException("Error creating display(EDT): "+edtDevice.getConnection());
+ throw new RuntimeException("Error creating display(GfxCfg/Render): "+edtDevice.getConnection());
}
renderDevice = new X11GraphicsDevice(renderDeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */);
final AbstractGraphicsScreen renderScreen = new X11GraphicsScreen(renderDevice, screen.getIndex());
@@ -132,12 +132,6 @@ public class WindowDriver extends WindowImpl {
}
}
- @Override
- public long getDisplayHandle() {
- // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle();
- return renderDevice.getHandle(); // shortcut
- }
-
protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("X11Window reconfig: "+x+"/"+y+" "+width+"x"+height+", "+
@@ -304,5 +298,5 @@ public class WindowDriver extends WindowImpl {
private static native void warpPointer0(long display, long windowHandle, int x, int y);
private long windowHandleClose;
- private X11GraphicsDevice renderDevice;
+ private X11GraphicsDevice renderDevice;
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java
index 270322891..08a0857a9 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitchNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch01NEWT.java
@@ -59,7 +59,11 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-public class TestGLContextDrawableSwitchNEWT extends UITestCase {
+/**
+ * Test re-association (switching) of GLContext/GLDrawables,
+ * i.e. ctx1/draw1, ctx2/draw2 -> ctx1/draw2, ctx2/draw1.
+ */
+public class TestGLContextDrawableSwitch01NEWT extends UITestCase {
static GLProfile glp;
static GLCapabilities caps;
static int width, height;
@@ -72,7 +76,6 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
height = 256;
}
- /** Note: No GLContext is attached w/ this implementation ! */
private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException {
final Window window = NewtFactory.createWindow(caps);
Assert.assertNotNull(window);
@@ -128,21 +131,23 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter);
// create single context using glad1 and assign it to glad1,
- // after destroying the prev. context!
+ // destroy the prev. context afterwards.
{
- final GLContext oldCtx = glad1.getContext();
+ final GLContext newCtx = glad1.createContext(null);
+ Assert.assertNotNull(newCtx);
+ final GLContext oldCtx = glad1.setContext(newCtx);
Assert.assertNotNull(oldCtx);
oldCtx.destroy();
- final GLContext singleCtx = glad1.createContext(null);
- Assert.assertNotNull(singleCtx);
- int res = singleCtx.makeCurrent();
+ final int res = newCtx.makeCurrent();
Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res);
- singleCtx.release();
- glad1.setContext(singleCtx);
+ newCtx.release();
}
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
GearsES2 gears = new GearsES2(1);
glad1.addGLEventListener(gears);
+ glad1.addGLEventListener(snapshotGLEventListener);
+ snapshotGLEventListener.setMakeSnapshot();
Animator animator = new Animator();
animator.add(glad1);
@@ -174,7 +179,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
@Test(timeout=30000)
public void testSwitch2GLWindowOneDemo() throws InterruptedException {
- GearsES2 gears = new GearsES2(1);
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ final GearsES2 gears = new GearsES2(1);
final QuitAdapter quitAdapter = new QuitAdapter();
GLWindow glWindow1 = GLWindow.create(caps);
@@ -182,6 +188,7 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
glWindow1.setSize(width, height);
glWindow1.setPosition(64, 64);
glWindow1.addGLEventListener(0, gears);
+ glWindow1.addGLEventListener(snapshotGLEventListener);
glWindow1.addWindowListener(quitAdapter);
GLWindow glWindow2 = GLWindow.create(caps);
@@ -198,6 +205,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
glWindow1.setVisible(true);
glWindow2.setVisible(true);
+ snapshotGLEventListener.setMakeSnapshot();
+
int s = 0;
long t0 = System.currentTimeMillis();
long t1 = t0;
@@ -215,6 +224,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
System.err.println(s+" - switch - END "+ ( t1 - t0 ));
+
+ snapshotGLEventListener.setMakeSnapshot();
}
Thread.sleep(100);
t1 = System.currentTimeMillis();
@@ -228,15 +239,18 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
@Test(timeout=30000)
public void testSwitch2GLWindowEachWithOwnDemo() throws InterruptedException {
- GearsES2 gears = new GearsES2(1);
- RedSquareES2 rsquare = new RedSquareES2(1);
+ final GearsES2 gears = new GearsES2(1);
+ final RedSquareES2 rsquare = new RedSquareES2(1);
final QuitAdapter quitAdapter = new QuitAdapter();
+ final SnapshotGLEventListener snapshotGLEventListener1 = new SnapshotGLEventListener();
+ final SnapshotGLEventListener snapshotGLEventListener2 = new SnapshotGLEventListener();
GLWindow glWindow1 = GLWindow.create(caps);
glWindow1.setTitle("win1");
glWindow1.setSize(width, height);
glWindow1.setPosition(64, 64);
glWindow1.addGLEventListener(0, gears);
+ glWindow1.addGLEventListener(snapshotGLEventListener1);
glWindow1.addWindowListener(quitAdapter);
GLWindow glWindow2 = GLWindow.create(caps);
@@ -244,6 +258,7 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
glWindow2.setSize(width+100, height+100);
glWindow2.setPosition(2*64+width, 64);
glWindow2.addGLEventListener(0, rsquare);
+ glWindow2.addGLEventListener(snapshotGLEventListener2);
glWindow2.addWindowListener(quitAdapter);
Animator animator = new Animator();
@@ -254,6 +269,9 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
glWindow1.setVisible(true);
glWindow2.setVisible(true);
+ snapshotGLEventListener1.setMakeSnapshot();
+ snapshotGLEventListener2.setMakeSnapshot();
+
int s = 0;
long t0 = System.currentTimeMillis();
long t1 = t0;
@@ -268,6 +286,8 @@ public class TestGLContextDrawableSwitchNEWT extends UITestCase {
System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle()));
System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle()));
System.err.println(s+" - switch - END "+ ( t1 - t0 ));
+ snapshotGLEventListener1.setMakeSnapshot();
+ snapshotGLEventListener2.setMakeSnapshot();
}
Thread.sleep(100);
t1 = System.currentTimeMillis();
@@ -305,6 +325,6 @@ public class TestGLContextDrawableSwitchNEWT 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(TestGLContextDrawableSwitchNEWT.class.getName());
+ org.junit.runner.JUnitCore.main(TestGLContextDrawableSwitch01NEWT.class.getName());
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java
new file mode 100644
index 000000000..cd308e165
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextDrawableSwitch11NEWT.java
@@ -0,0 +1,352 @@
+/**
+ * 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;
+
+import java.io.IOException;
+
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.event.WindowListener;
+import com.jogamp.newt.event.WindowUpdateEvent;
+import com.jogamp.newt.opengl.GLWindow;
+
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLProfile;
+
+import jogamp.opengl.GLEventListenerState;
+
+import com.jogamp.opengl.GLAutoDrawableDelegate;
+import com.jogamp.opengl.util.Animator;
+
+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.QuitAdapter;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test re-association of GLContext/GLDrawables,
+ * here GLContext's survival of GLDrawable desctruction
+ * and reuse w/ new or recreated GLDrawable.
+ * <p>
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
+ * </p>
+ */
+public class TestGLContextDrawableSwitch11NEWT extends UITestCase {
+ static GLProfile glp;
+ static GLCapabilities caps;
+ static int width, height;
+
+ @BeforeClass
+ public static void initClass() {
+ glp = GLProfile.getGL2ES2();
+ caps = new GLCapabilities(glp);
+ width = 256;
+ height = 256;
+ }
+
+ private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException {
+ final Window window = NewtFactory.createWindow(caps);
+ Assert.assertNotNull(window);
+ window.setPosition(x, y);
+ window.setSize(width, height);
+ window.setVisible(true);
+ Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true));
+ Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true));
+
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+ final GLDrawable drawable = factory.createGLDrawable(window);
+ Assert.assertNotNull(drawable);
+
+ drawable.setRealized(true);
+ Assert.assertTrue(drawable.isRealized());
+
+ final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false, null) {
+ @Override
+ protected void destroyImplInLock() {
+ super.destroyImplInLock();
+ window.destroy(); // destroys the actual window
+ }
+ };
+
+ // add basic window interaction
+ window.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowRepaint(WindowUpdateEvent e) {
+ glad.windowRepaintOp();
+ }
+ @Override
+ public void windowResized(WindowEvent e) {
+ glad.windowResizedOp(window.getWidth(), window.getHeight());
+ }
+ @Override
+ public void windowDestroyNotify(WindowEvent e) {
+ glad.windowDestroyNotifyOp();
+ }
+ });
+ window.addWindowListener(wl);
+
+ return glad;
+ }
+
+ @Test(timeout=30000)
+ public void test01() throws InterruptedException {
+ final QuitAdapter quitAdapter = new QuitAdapter();
+
+ final GLEventListenerCounter glelCounter = new GLEventListenerCounter();
+ final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener();
+ final Animator animator = new Animator();
+ animator.start();
+
+ final long t0 = System.currentTimeMillis();
+ final GLEventListenerState glls1;
+
+ // - create glad1 w/o context
+ // - create context using glad1 and assign it to glad1
+ {
+ final GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter);
+ final GLContext context1 = glad1.createContext(null);
+ glad1.setContext(context1);
+ animator.add(glad1);
+
+ glad1.addGLEventListener(glelCounter);
+ glad1.addGLEventListener(new GearsES2(1));
+ glad1.addGLEventListener(snapshotGLEventListener);
+ snapshotGLEventListener.setMakeSnapshot();
+
+ long t1 = System.currentTimeMillis();
+
+ while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) {
+ Thread.sleep(100);
+ t1 = System.currentTimeMillis();
+ }
+
+ // - dis-associate context from glad1
+ // - destroy glad1
+ Assert.assertEquals(1, glelCounter.initCount);
+ Assert.assertTrue(1 <= glelCounter.reshapeCount);
+ Assert.assertTrue(1 <= glelCounter.displayCount);
+ Assert.assertEquals(0, glelCounter.disposeCount);
+ Assert.assertEquals(context1, glad1.getContext());
+ Assert.assertEquals(3, glad1.getGLEventListenerCount());
+ Assert.assertEquals(context1.getGLReadDrawable(), glad1.getDelegatedDrawable());
+ Assert.assertEquals(context1.getGLDrawable(), glad1.getDelegatedDrawable());
+
+ glls1 = GLEventListenerState.moveFrom(glad1);
+
+ Assert.assertEquals(1, glelCounter.initCount);
+ Assert.assertTrue(1 <= glelCounter.reshapeCount);
+ Assert.assertTrue(1 <= glelCounter.displayCount);
+ Assert.assertEquals(0, glelCounter.disposeCount);
+ Assert.assertEquals(context1, glls1.context);
+ Assert.assertNull(context1.getGLReadDrawable());
+ Assert.assertNull(context1.getGLDrawable());
+ Assert.assertEquals(3, glls1.listenerCount());
+ Assert.assertEquals(true, glls1.isOwner());
+ Assert.assertEquals(null, glad1.getContext());
+ Assert.assertEquals(0, glad1.getGLEventListenerCount());
+
+ glad1.destroy();
+ Assert.assertEquals(1, glelCounter.initCount);
+ Assert.assertTrue(1 <= glelCounter.reshapeCount);
+ Assert.assertTrue(1 <= glelCounter.displayCount);
+ Assert.assertEquals(0, glelCounter.disposeCount);
+ }
+
+ // - create glad2 w/ survived context
+ {
+ final GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter);
+ snapshotGLEventListener.setMakeSnapshot();
+
+ Assert.assertEquals(null, glad2.getContext());
+ Assert.assertEquals(0, glad2.getGLEventListenerCount());
+
+ glls1.moveTo(glad2);
+
+ Assert.assertEquals(1, glelCounter.initCount);
+ Assert.assertTrue(1 <= glelCounter.reshapeCount);
+ Assert.assertTrue(1 <= glelCounter.displayCount);
+ Assert.assertEquals(0, glelCounter.disposeCount);
+ Assert.assertEquals(glls1.context, glad2.getContext());
+ Assert.assertEquals(3, glad2.getGLEventListenerCount());
+ Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable());
+ Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable());
+ Assert.assertEquals(false, glls1.isOwner());
+
+ long t1 = System.currentTimeMillis();
+
+ while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/1 ) {
+ Thread.sleep(100);
+ t1 = System.currentTimeMillis();
+ }
+
+ glad2.destroy();
+ Assert.assertEquals(1, glelCounter.initCount);
+ Assert.assertTrue(1 <= glelCounter.reshapeCount);
+ Assert.assertTrue(1 <= glelCounter.displayCount);
+ Assert.assertEquals(1, glelCounter.disposeCount);
+ }
+ animator.stop();
+ }
+
+ @Test(timeout=30000)
+ public void test02() 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);
+ glad1.setVisible(true);
+ animator.add(glad1);
+
+ glad1.addGLEventListener(glelTracker);
+ glad1.addGLEventListener(new GearsES2(1));
+ glad1.addGLEventListener(snapshotGLEventListener);
+ snapshotGLEventListener.setMakeSnapshot();
+
+ long t1 = System.currentTimeMillis();
+
+ while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration/2 ) {
+ Thread.sleep(100);
+ t1 = System.currentTimeMillis();
+ }
+
+ // - 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);
+ glad2.setVisible(true);
+ snapshotGLEventListener.setMakeSnapshot();
+
+ 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")) {
+ 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(TestGLContextDrawableSwitch11NEWT.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/GLEventListenerCounter.java b/src/test/com/jogamp/opengl/test/junit/util/GLEventListenerCounter.java
new file mode 100644
index 000000000..b121a4c2a
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/util/GLEventListenerCounter.java
@@ -0,0 +1,65 @@
+/**
+ * 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.util;
+
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+
+public class GLEventListenerCounter implements GLEventListener {
+ public int initCount = 0;
+ public int displayCount = 0;
+ public int reshapeCount = 0;
+ public int disposeCount = 0;
+
+ public void reset() {
+ initCount = 0;
+ displayCount = 0;
+ reshapeCount = 0;
+ disposeCount = 0;
+ }
+
+ @Override
+ public void init(GLAutoDrawable drawable) {
+ initCount++;
+ }
+
+ @Override
+ public void dispose(GLAutoDrawable drawable) {
+ disposeCount++;
+ }
+
+ @Override
+ public void display(GLAutoDrawable drawable) {
+ displayCount++;
+ }
+
+ @Override
+ public void reshape(GLAutoDrawable d, int x, int y, int width, int height) {
+ reshapeCount++;
+ }
+} \ No newline at end of file