From c225285e09f0a29fca418601bf1aa07cafb54339 Mon Sep 17 00:00:00 2001
From: Sven Gothel
- * The current context will be dis-associated from this auto-drawable
+ * The current context will be destroyed if
@@ -145,26 +146,16 @@ public interface GLAutoDrawable extends GLDrawable {
* However the user shall take extra care that no other thread
* attempts to make this context current.
*
- * In case you do not intend to use the old context anymore, i.e.
- * not assigning it to another drawable, it shall be
- * destroyed, i.e.:
- * newtCtx
, to this auto-drawable.
* destroyPrevCtx
is true
,
+ * otherwise it will be dis-associated from this auto-drawable
* via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first.
*
- GLContext oldCtx = glad.setContext(newCtx);
- if(null != oldCtx) {
- oldCtx.destroy();
- }
- *
- *
null
for dis-association.
+ * @param destroyPrevCtx if true
, destroy the previous context if exists
* @return the previous GLContext, maybe null
*
* @see GLContext#setGLDrawable(GLDrawable, boolean)
* @see GLContext#setGLReadDrawable(GLDrawable)
- * @see jogamp.opengl.GLDrawableHelper#switchContext(GLDrawable, GLContext, GLContext, int)
+ * @see jogamp.opengl.GLDrawableHelper#switchContext(GLDrawable, GLContext, boolean, GLContext, int)
*/
- public GLContext setContext(GLContext newCtx);
+ public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx);
/**
* Adds the given {@link GLEventListener listener} to the end of this drawable queue.
@@ -500,7 +491,7 @@ public interface GLAutoDrawable extends GLDrawable {
* * This GLAutoDrawable implementation holds it's own GLContext reference, * thus created a GLContext using this methods won't replace it implicitly. - * To replace or set this GLAutoDrawable's GLContext you need to call {@link #setContext(GLContext)}. + * To replace or set this GLAutoDrawable's GLContext you need to call {@link #setContext(GLContext, boolean)}. *
** The GLAutoDrawable implementation shall also set the diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index ebc25e2ad..63c18db5d 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -429,8 +429,29 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } + private final void setRealizedImpl(boolean realized) { + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final GLDrawable _drawable = drawable; + if( null == _drawable || realized && ( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) ) { + return; + } + _drawable.setRealized(realized); + if( realized && _drawable.isRealized() ) { + sendReshape=true; // ensure a reshape is being send .. + } + } finally { + _lock.unlock(); + } + } + private final Runnable realizeOnEDTAction = new Runnable() { public void run() { setRealizedImpl(true); } }; + private final Runnable unrealizeOnEDTAction = new Runnable() { public void run() { setRealizedImpl(false); } }; + @Override - public void setRealized(boolean realized) { + public final void setRealized(boolean realized) { + // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! + AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, realized ? realizeOnEDTAction : unrealizeOnEDTAction); } @Override @@ -595,46 +616,28 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } private boolean validateGLDrawable() { - if( Beans.isDesignTime() || !isDisplayable() ) { - return false; // early out! - } - final GLDrawable _drawable = drawable; - if ( null != _drawable ) { - if( _drawable.isRealized() ) { - return true; - } - if( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { - return false; // early out! - } - // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock! - final boolean res0 = AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, setRealizedOnEDTAction); - final boolean res1 = res0 && _drawable.isRealized(); - if(DEBUG) { - System.err.println(getThreadName()+": Realized Drawable: invoked "+res0+", probedIsRealized "+res1+", "+_drawable.toString()); - Thread.dumpStack(); - } - return res1; - } - return false; - } - private Runnable setRealizedOnEDTAction = new Runnable() { - public void run() { - final RecursiveLock _lock = lock; - _lock.lock(); - try { - final GLDrawable _drawable = drawable; - if( null == _drawable || 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { - return; - } - _drawable.setRealized(true); - if( _drawable.isRealized() ) { - sendReshape=true; // ensure a reshape is being send .. - } - } finally { - _lock.unlock(); + if( Beans.isDesignTime() || !isDisplayable() ) { + return false; // early out! + } + final GLDrawable _drawable = drawable; + if ( null != _drawable ) { + if( _drawable.isRealized() ) { + return true; } - } }; - + if( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) { + return false; // early out! + } + setRealized(true); + final boolean res = _drawable.isRealized(); + if(DEBUG) { + System.err.println(getThreadName()+": Realized Drawable: isRealized "+res+", "+_drawable.toString()); + Thread.dumpStack(); + } + return res; + } + return false; + } + /**
Overridden to track when this component is removed from a
container. Subclasses which override this method must call
super.removeNotify() in their removeNotify() method in order to
@@ -791,16 +794,13 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public GLContext setContext(GLContext newCtx) {
+ public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) {
final RecursiveLock _lock = lock;
_lock.lock();
try {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
- if(newCtxCurrent) {
- context.makeCurrent();
- }
return oldCtx;
} finally {
_lock.unlock();
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index 8d9493cbf..d62967d7f 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -519,16 +519,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
- public GLContext setContext(GLContext newCtx) {
+ public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) {
if (backend == null) {
return null;
}
final GLContext oldCtx = backend.getContext();
- final boolean newCtxCurrent = GLDrawableHelper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags);
+ GLDrawableHelper.switchContext(backend.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
backend.setContext(newCtx);
- if(newCtxCurrent) {
- newCtx.makeCurrent();
- }
return oldCtx;
}
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index c20197e72..ad67f8281 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -326,16 +326,13 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
@Override
- public final GLContext setContext(GLContext newCtx) {
+ public final GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) {
final RecursiveLock lock = getLock();
lock.lock();
try {
final GLContext oldCtx = context;
- final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags);
+ GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
context=(GLContextImpl)newCtx;
- if(newCtxCurrent) { // implies null != newCtx
- context.makeCurrent();
- }
return oldCtx;
} finally {
lock.unlock();
@@ -530,6 +527,24 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter {
}
}
+ @Override
+ public final void setRealized(boolean realized) {
+ final RecursiveLock _lock = getLock();
+ _lock.lock();
+ try {
+ final GLDrawable _drawable = drawable;
+ if( null == _drawable || realized && ( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) ) {
+ return;
+ }
+ _drawable.setRealized(realized);
+ if( realized && _drawable.isRealized() ) {
+ sendReshape=true; // ensure a reshape is being send ..
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+
@Override
public final boolean isRealized() {
final GLDrawable _drawable = drawable;
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index 42364dbfd..4121e8f77 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
@@ -133,9 +133,6 @@ public abstract class GLContextImpl extends GLContext {
GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this);
this.drawable = drawable;
- if(null != drawable) {
- drawable.associateContext(this, true);
- }
this.drawableRead = drawable;
this.glDebugHandler = new GLDebugMessageHandler(this);
@@ -207,25 +204,36 @@ public abstract class GLContextImpl extends GLContext {
return drawable; // no change.
}
final Thread currentThread = Thread.currentThread();
+ if( lock.isLockedByOtherThread() ) {
+ throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName());
+ }
final boolean lockHeld = lock.isOwner(currentThread);
+ if( lockHeld && lock.getHoldCount() > 1 ) {
+ // would need to makeCurrent * holdCount
+ throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)");
+ }
+ final GLDrawableImpl old = drawable;
+ if( isCreated() && null != old && old.isRealized() ) {
+ if(!lockHeld) {
+ makeCurrent();
+ }
+ associateDrawable(false);
+ if(!lockHeld) {
+ release();
+ }
+ }
if(lockHeld) {
release();
- } else if(lock.isLockedByOtherThread()) { // still could glitch ..
- throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName());
- }
+ }
if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable
drawableRead = (GLDrawableImpl) readWrite;
}
- final GLDrawableImpl old = drawable;
- if( null != old ) {
- old.associateContext(this, false);
- }
drawableRetargeted |= null != drawable && readWrite != drawable;
drawable = (GLDrawableImpl) readWrite ;
- if( null != drawable ) {
- drawable.associateContext(this, true);
- if( lockHeld ) {
- makeCurrent();
+ if( isCreated() && null != drawable && drawable.isRealized() ) {
+ makeCurrent(true); // implicit: associateDrawable(true)
+ if( !lockHeld ) {
+ release();
}
}
return old;
@@ -363,8 +371,7 @@ public abstract class GLContextImpl extends GLContext {
makeCurrent();
}
try {
- contextRealized(false);
- drawable.associateContext(this, false);
+ associateDrawable(false);
} catch (Throwable t) {
drawableContextRealizedException = t;
}
@@ -467,7 +474,11 @@ public abstract class GLContextImpl extends GLContext {
* @see #destroyContextARBImpl
*/
@Override
- public int makeCurrent() throws GLException {
+ public final int makeCurrent() throws GLException {
+ return makeCurrent(false);
+ }
+
+ protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException {
if( TRACE_SWITCH ) {
System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock);
}
@@ -561,7 +572,11 @@ public abstract class GLContextImpl extends GLContext {
gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) );
}
- contextRealized(true);
+ forceDrawableAssociation = true;
+ }
+
+ if( forceDrawableAssociation ) {
+ associateDrawable(true);
}
contextMadeCurrent(true);
@@ -662,14 +677,14 @@ public abstract class GLContextImpl extends GLContext {
protected abstract void makeCurrentImpl() throws GLException;
/**
- * @see GLDrawableImpl#contextRealized(GLContext, boolean)
+ * Calls {@link GLDrawableImpl#associateContext(GLContext, boolean)}
*/
- protected void contextRealized(boolean realized) {
- drawable.contextRealized(this, realized);
+ protected void associateDrawable(boolean bound) {
+ drawable.associateContext(this, bound);
}
/**
- * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean)
+ * Calls {@link GLDrawableImpl#contextMadeCurrent(GLContext, boolean)}
*/
protected void contextMadeCurrent(boolean current) {
drawable.contextMadeCurrent(this, current);
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index 3eedf918e..1caa942ba 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -59,7 +59,7 @@ import javax.media.opengl.GLFBODrawable;
import javax.media.opengl.GLRunnable;
/** Encapsulates the implementation of most of the GLAutoDrawable's
- methods to be able to share it between GLCanvas and GLJPanel. */
+ methods to be able to share it between GLAutoDrawable implementations like GLAutoDrawableBase, GLCanvas and GLJPanel. */
public class GLDrawableHelper {
/** true if property jogl.debug.GLDrawable.PerfStats
is defined. */
private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true);
@@ -113,6 +113,9 @@ public class GLDrawableHelper {
return sb.toString();
}
+ /** Limit release calls of {@link #forceNativeRelease(GLContext)} to {@value}. */
+ private static final int MAX_RELEASE_ITER = 512;
+
/**
* Since GLContext's {@link GLContext#makeCurrent()} and {@link GLContext#release()}
* is recursive, a call to {@link GLContext#release()} may not natively release the context.
@@ -122,18 +125,25 @@ public class GLDrawableHelper {
* @param ctx
*/
public static final void forceNativeRelease(GLContext ctx) {
+ int releaseCount = 0;
do {
ctx.release();
+ releaseCount++;
if (DEBUG) {
- System.err.println("GLDrawableHelper.forceNativeRelease() -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent());
+ System.err.println("GLDrawableHelper.forceNativeRelease() #"+releaseCount+" -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent());
}
- } while( ctx == GLContext.getCurrent() );
+ } while( MAX_RELEASE_ITER > releaseCount && ctx.isCurrent() );
+
+ if( ctx.isCurrent() ) {
+ throw new GLException("Context still current after "+MAX_RELEASE_ITER+" releases: "+ctx);
+ }
}
/**
* Switch {@link GLContext} / {@link GLDrawable} association.
*
- * Dis-associate oldCtx
from drawable
+ * The oldCtx
will be destroyed if destroyPrevCtx
is true
,
+ * otherwise dis-associate oldCtx
from drawable
* via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}.
*
@@ -149,31 +159,25 @@ public class GLDrawableHelper {
*
* @param drawable the drawable which context is changed
* @param oldCtx the old context, maybe null
.
+ * @param destroyOldCtx if true
, destroy the oldCtx
* @param newCtx the new context, maybe null
for dis-association.
* @param newCtxCreationFlags additional creation flags if newCtx is not null and not been created yet, see {@link GLContext#setContextCreationFlags(int)}
- * @return true if the new context was current, otherwise false
*
- * @see GLAutoDrawable#setContext(GLContext)
+ * @see GLAutoDrawable#setContext(GLContext, boolean)
*/
- public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) {
+ public static final void switchContext(GLDrawable drawable, GLContext oldCtx, boolean destroyOldCtx, GLContext newCtx, int newCtxCreationFlags) {
if( null != oldCtx ) {
- if( oldCtx.isCurrent() ) {
- oldCtx.release();
+ if( destroyOldCtx ) {
+ oldCtx.destroy();
+ } else {
+ oldCtx.setGLDrawable(null, true); // dis-associate old pair
}
- oldCtx.setGLDrawable(null, true); // dis-associate old pair
}
- final boolean newCtxCurrent;
+
if(null!=newCtx) {
- newCtxCurrent = newCtx.isCurrent();
- if(newCtxCurrent) {
- newCtx.release();
- }
newCtx.setContextCreationFlags(newCtxCreationFlags);
- newCtx.setGLDrawable(drawable, true); // re-associate new pair
- } else {
- newCtxCurrent = false;
+ newCtx.setGLDrawable(drawable, true); // re-associate new pair
}
- return newCtxCurrent;
}
/**
@@ -208,7 +212,6 @@ public class GLDrawableHelper {
context.makeCurrent();
}
context.getGL().glFinish();
- context.release();
context.setGLDrawable(null, true); // dis-associate
}
@@ -837,7 +840,7 @@ public class GLDrawableHelper {
if( null != exclusiveContextThread ) {
throw new GLException("Release current exclusive Context Thread "+exclusiveContextThread+" first");
}
- if( null != context && GLContext.getCurrent() == context ) {
+ if( null != context && context.isCurrent() ) {
try {
forceNativeRelease(context);
} catch (Throwable ex) {
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
index c0c28a5f2..d0c1461a9 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java
@@ -164,13 +164,14 @@ public abstract class GLDrawableImpl implements GLDrawable {
@Override
public final void setRealized(boolean realizedArg) {
if ( realized != realizedArg ) { // volatile: OK (locked below)
+ final boolean isProxySurface = surface instanceof ProxySurface;
if(DEBUG) {
- System.err.println(getThreadName() + ": setRealized: "+getClass().getSimpleName()+" "+realized+" -> "+realizedArg);
+ System.err.println(getThreadName() + ": setRealized: drawable "+getClass().getSimpleName()+", surface "+surface.getClass().getSimpleName()+", isProxySurface "+isProxySurface+": "+realized+" -> "+realizedArg);
Thread.dumpStack();
}
AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice();
if(realizedArg) {
- if(surface instanceof ProxySurface) {
+ if(isProxySurface) {
((ProxySurface)surface).createNotify();
}
if(NativeSurface.LOCK_SURFACE_NOT_READY >= lockSurface()) {
@@ -195,7 +196,7 @@ public abstract class GLDrawableImpl implements GLDrawable {
unlockSurface();
} else {
aDevice.unlock();
- if(surface instanceof ProxySurface) {
+ if(isProxySurface) {
((ProxySurface)surface).destroyNotify();
}
}
@@ -210,18 +211,26 @@ public abstract class GLDrawableImpl implements GLDrawable {
*/
protected abstract void setRealizedImpl();
- /**
- * Callback for special implementations, allowing GLContext to trigger GL related lifecycle: construct
, destroy
.
+ /**
+ * Callback for special implementations, allowing
+ *
construct
, destroy
.
- * If realized
is true
, the context has just been created and made current.
+ * If bound
is true
, the context is current and being newly associated w/ this drawable.
*
- * If realized
is false
, the context is still current and will be released and destroyed after this method returns.
+ * If bound
is false
, the context is still current and will be unbound (released and destroyed, or simply disassociated).
*
- * @see #contextMadeCurrent(GLContext, boolean) + * Being called by {@link GLContextImpl#associateDrawable(boolean)}. + *
+ * @param ctx the just bounded or unbounded context + * @param bound iftrue
create an association, otherwise remove it
*/
- protected void contextRealized(GLContext glc, boolean realized) {}
+ protected void associateContext(GLContext ctx, boolean bound) { }
/**
* Callback for special implementations, allowing GLContext to trigger GL related lifecycle: makeCurrent
, release
.
@@ -232,21 +241,12 @@ public abstract class GLDrawableImpl implements GLDrawable {
* If current
is false
, the context is still current and will be release after this method returns.
*
* - * Note: Will also be called after {@link #contextRealized(GLContext, boolean) contextRealized(ctx, true)} - * but not at context destruction, i.e. {@link #contextRealized(GLContext, boolean) contextRealized(ctx, false)}. + * Being called by {@link GLContextImpl#contextMadeCurrent(boolean)}. *
- * @see #contextRealized(GLContext, boolean) + * @see #associateContext(GLContext, boolean) */ protected void contextMadeCurrent(GLContext glc, boolean current) { } - /** - * Callback for special implementations, allowing to associate bound context to this drawable (bound == true) - * or to remove such association (bound == false). - * @param ctx the just bounded or unbounded context - * @param bound iftrue
create an association, otherwise remove it
- */
- protected void associateContext(GLContext ctx, boolean bound) { }
-
/** Callback for special implementations, allowing GLContext to fetch a custom default render framebuffer. Defaults to zero.*/
protected int getDefaultDrawFramebuffer() { return 0; }
/** Callback for special implementations, allowing GLContext to fetch a custom default read framebuffer. Defaults to zero. */
diff --git a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java
index 7a2569850..2385460fe 100644
--- a/src/jogl/classes/jogamp/opengl/GLEventListenerState.java
+++ b/src/jogl/classes/jogamp/opengl/GLEventListenerState.java
@@ -45,7 +45,6 @@ import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.GLRunnable;
-import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.nativewindow.MutableGraphicsConfiguration;
/**
@@ -71,11 +70,12 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration;
*
*/
public class GLEventListenerState {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = GLDrawableImpl.DEBUG;
- private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps,
+ private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, boolean proxyOwnsUpstreamDevice, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps,
GLContext context, int count, GLAnimatorControl anim) {
this.upstreamScreen = upstreamScreen;
+ this.proxyOwnsUpstreamDevice = proxyOwnsUpstreamDevice;
this.screen = screen;
this.caps = caps;
this.context = context;
@@ -97,6 +97,7 @@ public class GLEventListenerState {
public final int listenerCount() { return listeners.length; }
public final AbstractGraphicsScreen upstreamScreen;
+ public final boolean proxyOwnsUpstreamDevice;
public final AbstractGraphicsScreen screen;
public final GLCapabilitiesImmutable caps;
public final GLContext context;
@@ -161,25 +162,30 @@ public class GLEventListenerState {
}
aScreen1.getDevice().clearHandleOwner(); // don't close device handle
- final AbstractGraphicsScreen aUpScreen2;
+ final AbstractGraphicsScreen aUpScreen2;
+ final boolean proxyOwnsUpstreamDevice;
{
AbstractGraphicsScreen _aUpScreen2=null;
if(aSurface instanceof ProxySurface) {
final ProxySurface aProxy = (ProxySurface)aSurface;
+ proxyOwnsUpstreamDevice = aProxy.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
final NativeSurface aUpSurface = aProxy.getUpstreamSurface();
- if(null != aUpSurface) {
+ if(DEBUG && null != aUpSurface) {
System.err.println("X00 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface);
}
- aProxy.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); // don't close device handle
if(null != aUpSurface) {
final AbstractGraphicsScreen aUpScreen1 = aUpSurface.getGraphicsConfiguration().getScreen();
_aUpScreen2 = cloneScreen(aUpScreen1);
if(null != aUpScreen1) {
aUpScreen1.getDevice().clearHandleOwner(); // don't close device handle
}
- System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface);
- System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface);
+ if(DEBUG) {
+ System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface);
+ System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface);
+ }
}
+ } else {
+ proxyOwnsUpstreamDevice = false;
}
aUpScreen2=_aUpScreen2;
}
@@ -189,7 +195,7 @@ public class GLEventListenerState {
aAnim.remove(a); // also handles ECT
}
- final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, aScreen2, caps, a.getContext(), aSz, aAnim);
+ final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, proxyOwnsUpstreamDevice, aScreen2, caps, a.getContext(), aSz, aAnim);
//
// remove and cache all GLEventListener and their init-state
@@ -205,7 +211,7 @@ public class GLEventListenerState {
//
a.invoke(true, glFinish);
- a.setContext( null );
+ a.setContext( null, false );
return glls;
}
@@ -241,13 +247,7 @@ public class GLEventListenerState {
throw new GLException("Incompatible Capabilities - Prev-Holder: "+caps+", New-Holder "+caps);
}
// Destroy and remove currently associated GLContext, if any (will be replaced)
- {
- final GLContext ctx = a.getContext();
- if( null != ctx) {
- ctx.destroy();
- }
- a.setContext( null );
- }
+ a.setContext( null, true );
final boolean aRealized = a.isRealized();
if( aRealized ) {
a.setRealized(false);
@@ -260,8 +260,11 @@ public class GLEventListenerState {
final AbstractGraphicsScreen aScreen1 = aCfg.getScreen();
aCfg.setScreen( screen );
aScreen1.getDevice().close();
- System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface);
+ if( DEBUG ) {
+ System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface);
+ }
}
+
// If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it
{
boolean upstreamSet = false;
@@ -270,13 +273,19 @@ public class GLEventListenerState {
final NativeSurface aUpSurface = aProxy.getUpstreamSurface();
if(null != aUpSurface) {
final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration();
- final AbstractGraphicsScreen aUpScreen1 = aUpCfg.getScreen();
if( null != upstreamScreen ) {
- System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface);
+ if( DEBUG ) {
+ System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString());
+ }
+ aUpCfg.getScreen().getDevice().close();
aUpCfg.setScreen( upstreamScreen );
- aUpScreen1.getDevice().close();
+ if( proxyOwnsUpstreamDevice ) {
+ aProxy.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
upstreamSet = true;
- System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface);
+ if( DEBUG ) {
+ System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString());
+ }
} else {
throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true");
}
@@ -292,7 +301,7 @@ public class GLEventListenerState {
}
final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
try {
- a.setContext( context );
+ a.setContext( context, false );
} finally {
if( surfaceLocked ) {
aSurface.unlockSurface();
diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
index 86cfa4f4c..51ec7dda6 100644
--- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
@@ -38,6 +38,7 @@ import com.jogamp.opengl.JoglVersion;
*/
public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject");
+ protected static final boolean DEBUG_SWAP = Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true);
private final GLDrawableImpl parent;
private GLCapabilitiesImmutable origParentChosenCaps;
@@ -92,6 +93,9 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
}
private final void initialize(boolean realize, GL gl) {
+ if( initialized == realize ) {
+ throw new InternalError("Already set to initialize := "+realize+": "+this);
+ }
if(realize) {
final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true)
@@ -323,8 +327,8 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
}
@Override
- protected final void contextRealized(GLContext glc, boolean realized) {
- initialize(realized, glc.getGL());
+ protected void associateContext(GLContext glc, boolean bound) {
+ initialize(bound, glc.getGL());
}
@Override
@@ -338,7 +342,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
swapFBOImpl(glc);
swapFBOImplPost(glc);
fboBound=false;
- if(DEBUG) {
+ if(DEBUG_SWAP) {
System.err.println("Post FBO swap(@release): done");
}
}
@@ -354,7 +358,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
swapFBOImpl(ctx);
doPostSwap = true;
fboBound=false;
- if(DEBUG) {
+ if(DEBUG_SWAP) {
System.err.println("Post FBO swap(@swap): done");
}
}
@@ -406,7 +410,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer());
} */
- if(DEBUG) {
+ if(DEBUG_SWAP) {
System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
index b438131bc..ddc6d5917 100644
--- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java
@@ -86,9 +86,10 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
//
@Override
- public final void setRealized(boolean realized) {
+ public final void swapBuffers() throws GLException {
+ defaultSwapBuffers();
}
-
+
//
// GLAutoDrawable completion
//
@@ -125,11 +126,6 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer {
}
}
- @Override
- public final void swapBuffers() throws GLException {
- defaultSwapBuffers();
- }
-
//----------------------------------------------------------------------
// Internals only below this point
//
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
index 342c4c417..77e9dc173 100644
--- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
+++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java
@@ -47,7 +47,7 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize {
public final void create(ProxySurface surface) {
final String dbgPrefix;
if(DEBUG) {
- dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): ";
+ dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create( up "+upstreamSurface.getClass().getSimpleName()+" -> this "+surface.getClass().getSimpleName()+" ): ";
System.err.println(dbgPrefix+this);
} else {
dbgPrefix = null;
@@ -76,24 +76,51 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize {
boolean isEGLSurfaceValid = true; // assume yes
- final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration();
- final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice();
-
final EGLGraphicsDevice eglDevice;
- if( aDevice instanceof EGLGraphicsDevice ) {
- eglDevice = (EGLGraphicsDevice) aDevice;
+ final AbstractGraphicsConfiguration aConfig;
+ {
+ final AbstractGraphicsConfiguration surfaceConfig = surface.getGraphicsConfiguration();
+ final AbstractGraphicsDevice surfaceDevice = null != surfaceConfig ? surfaceConfig.getScreen().getDevice() : null;
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"SurfaceDevice: "+surfaceDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceDevice.hashCode())+", "+surfaceDevice);
+ System.err.println(dbgPrefix+"SurfaceConfig: "+surfaceConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceConfig.hashCode())+", "+surfaceConfig);
+ }
+
+ final AbstractGraphicsConfiguration upstreamConfig = upstreamSurface.getGraphicsConfiguration();
+ final AbstractGraphicsDevice upstreamDevice = upstreamConfig.getScreen().getDevice();
if(DEBUG) {
- System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice);
+ System.err.println(dbgPrefix+"UpstreamDevice: "+upstreamDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamDevice.hashCode())+", "+upstreamDevice);
+ System.err.println(dbgPrefix+"UpstreamConfig: "+upstreamConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamConfig.hashCode())+", "+upstreamConfig);
}
- if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) {
- eglDevice.open();
+
+ if( surfaceDevice instanceof EGLGraphicsDevice ) {
+ eglDevice = (EGLGraphicsDevice) surfaceDevice;
+ aConfig = surfaceConfig;
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Reusing this eglDevice: "+eglDevice+", using this config "+aConfig.getClass().getSimpleName()+" "+aConfig);
+ }
+ if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) {
+ eglDevice.open();
+ isEGLSurfaceValid = false;
+ surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ } else if( upstreamDevice instanceof EGLGraphicsDevice ) {
+ eglDevice = (EGLGraphicsDevice) upstreamDevice;
+ aConfig = upstreamConfig;
+ if(DEBUG) {
+ System.err.println(dbgPrefix+"Reusing upstream eglDevice: "+eglDevice+", using upstream config "+aConfig.getClass().getSimpleName()+" "+aConfig);
+ }
+ if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) {
+ eglDevice.open();
+ isEGLSurfaceValid = false;
+ surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ } else {
+ eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface);
+ aConfig = upstreamConfig;
isEGLSurfaceValid = false;
surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
}
- } else {
- eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface);
- isEGLSurfaceValid = false;
- surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
}
final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities();
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
index 3825f855c..a03850043 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
@@ -85,10 +85,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl
// NSOpenGL-based or CGL-based)
protected interface GLBackendImpl {
boolean isNSContext();
- void drawableChangedNotify();
long create(long share, int ctp, int major, int minor);
boolean destroy(long ctx);
- boolean contextRealized(boolean realized);
+ void associateDrawable(boolean bound);
boolean copyImpl(long src, int mask);
boolean makeCurrent(long ctx);
boolean release(long ctx);
@@ -328,20 +327,15 @@ public abstract class MacOSXCGLContext extends GLContextImpl
}
@Override
- protected void contextRealized(boolean realized) {
+ protected void associateDrawable(boolean bound) {
// context stuff depends on drawable stuff
- if(realized) {
- super.contextRealized(true); // 1) init drawable stuff
- impl.contextRealized(true); // 2) init context stuff
+ System.err.println("MaxOSXCGLContext.associateDrawable: "+bound);
+ if(bound) {
+ super.associateDrawable(true); // 1) init drawable stuff
+ impl.associateDrawable(true); // 2) init context stuff
} else {
- impl.contextRealized(false); // 1) free context stuff
- super.contextRealized(false); // 2) free drawable stuff
- }
- }
-
- /* pp */ void drawableChangedNotify() {
- if( 0 != contextHandle) {
- impl.drawableChangedNotify();
+ impl.associateDrawable(false); // 1) free context stuff
+ super.associateDrawable(false); // 2) free drawable stuff
}
}
@@ -467,9 +461,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl
// NSOpenGLContext-based implementation
class NSOpenGLImpl implements GLBackendImpl {
- private OffscreenLayerSurface backingLayerHost = null;
- private long nsOpenGLLayer = 0;
- private long nsOpenGLLayerPFmt = 0; // lifecycle: [create - contextRealized]
+ private long pixelFormat = 0; // lifecycle: [create - destroy]
+ private long nsOpenGLLayer = 0; // lifecycle: [associateDrawable_true - associateDrawable_false]
private float screenVSyncTimeout; // microSec
private int vsyncTimeout; // microSec - for nsOpenGLLayer mode
private int lastWidth=0, lastHeight=0; // allowing to detect size change
@@ -479,18 +472,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl
@Override
public boolean isNSContext() { return true; }
- @Override
- public void drawableChangedNotify() {
- backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true);
- if( null == backingLayerHost ) {
- boolean[] isPBuffer = { false };
- boolean[] isFBO = { false };
- CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO));
- } else {
- nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer();
- }
- }
-
private long getNSViewHandle(boolean[] isPBuffer, boolean[] isFBO) {
final long nsViewHandle;
if(drawable instanceof GLFBODrawableImpl) {
@@ -549,13 +530,12 @@ public abstract class MacOSXCGLContext extends GLContextImpl
isPBuffer = _isPBuffer[0];
isFBO = _isFBO[0];
}
- backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
+ final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
boolean incompleteView = null != backingLayerHost;
if( !incompleteView && surface instanceof ProxySurface ) {
incompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE );
}
- long pixelFormat;
{
final GLCapabilitiesImmutable targetCaps;
if( isFBO ) {
@@ -606,48 +586,54 @@ public abstract class MacOSXCGLContext extends GLContextImpl
}
config.setChosenCapabilities(fixedCaps);
- try {
- final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1);
- // Try to allocate a context with this
- ctx = CGL.createContext(share,
- nsViewHandle, incompleteView,
- pixelFormat,
- chosenCaps.isBackgroundOpaque(),
- viewNotReady);
- if (0 == ctx) {
- if(DEBUG) {
- System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0)));
- }
- return 0;
+ final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1);
+ // Try to allocate a context with this
+ ctx = CGL.createContext(share, nsViewHandle, incompleteView,
+ pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady);
+ if (0 == ctx) {
+ if(DEBUG) {
+ System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0)));
}
+ return 0;
+ }
- if(null != backingLayerHost) {
- nsOpenGLLayerPFmt = pixelFormat;
- pixelFormat = 0;
- }
-
- if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) {
- // Set the context opacity
- CGL.setContextOpacity(ctx, 0);
- }
- } finally {
- if(0!=pixelFormat) {
- CGL.deletePixelFormat(pixelFormat);
- pixelFormat = 0;
- }
+ if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) {
+ // Set the context opacity
+ CGL.setContextOpacity(ctx, 0);
}
return ctx;
}
@Override
public boolean destroy(long ctx) {
+ if(0!=pixelFormat) {
+ CGL.deletePixelFormat(pixelFormat);
+ pixelFormat = 0;
+ }
return CGL.deleteContext(ctx, true);
+
}
@Override
- public boolean contextRealized(boolean realized) {
- if( realized ) {
+ public void associateDrawable(boolean bound) {
+ final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true);
+
+ if(DEBUG) {
+ System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+", hasBackingLayerHost "+(null!=backingLayerHost));
+ }
+
+ if( bound ) {
+
if( null != backingLayerHost ) {
+
+ if( 0 != nsOpenGLLayer ) { // FIXME: redundant
+ throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set local: "+nsOpenGLLayer+", "+this);
+ }
+ nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer();
+ if( 0 != nsOpenGLLayer ) { // FIXME: redundant
+ throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set on backingLayerHost: "+nsOpenGLLayer+", "+this);
+ }
+
//
// handled layered surface
//
@@ -700,8 +686,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl
}
final boolean ctxUnlocked = CGL.kCGLNoError == CGL.CGLUnlockContext(cglCtx);
try {
- nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, nsOpenGLLayerPFmt, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight);
- nsOpenGLLayerPFmt = 0; // NSOpenGLLayer will release pfmt
+ nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight);
if (DEBUG) {
System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable);
}
@@ -718,17 +703,22 @@ public abstract class MacOSXCGLContext extends GLContextImpl
} else {
lastWidth = drawable.getWidth();
lastHeight = drawable.getHeight();
+ boolean[] isPBuffer = { false };
+ boolean[] isFBO = { false };
+ CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO));
}
} else {
if( 0 != nsOpenGLLayer ) {
- final NativeSurface surface = drawable.getNativeSurface();
+ if( null == backingLayerHost ) { // FIXME: redundant
+ throw new InternalError("Lifecycle: bound=false, hasNSOpneGLLayer=true, but 'backingLayerHost' is null local: "+nsOpenGLLayer+", "+this);
+ }
+
if (DEBUG) {
System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable);
}
- final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true);
- if(null != ols && ols.isSurfaceLayerAttached()) {
+ if( backingLayerHost.isSurfaceLayerAttached() ) {
// still having a valid OLS attached to surface (parent OLS could have been removed)
- ols.detachSurfaceLayer();
+ backingLayerHost.detachSurfaceLayer();
}
CGL.releaseNSOpenGLLayer(nsOpenGLLayer);
if( null != gl3ShaderProgram ) {
@@ -738,8 +728,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl
nsOpenGLLayer = 0;
}
}
- backingLayerHost = null;
- return true;
}
private final void validatePBufferConfig(long ctx) {
@@ -888,11 +876,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl
@Override
public boolean isNSContext() { return false; }
- @Override
- public void drawableChangedNotify() {
- // FIXME
- }
-
@Override
public long create(long share, int ctp, int major, int minor) {
long ctx = 0;
@@ -947,8 +930,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl
}
@Override
- public boolean contextRealized(boolean realized) {
- return true;
+ public void associateDrawable(boolean bound) {
}
@Override
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
index ff1772860..0f282d33f 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java
@@ -119,7 +119,6 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl {
if(bound) {
final MacOSXCGLContext osxCtx = (MacOSXCGLContext)ctx;
createdContexts.add(new WeakReference
+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *
+ */ +public abstract class GLContextDrawableSwitchBase extends UITestCase { + static protected enum GLADType { GLCanvasOnscreen, GLCanvasOffscreen, GLWindow, GLOffscreen }; + + // default period for 1 GLAD cycle + static long duration = 1000; // ms + + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + static void setGLCanvasSize(final GLCanvas glc, final Dimension new_sz) { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + glc.setMinimumSize(new_sz); + glc.setPreferredSize(new_sz); + glc.setSize(new_sz); + } } ); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + static void setFrameVisible(final Frame frame) throws InterruptedException { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.pack(); + frame.setVisible(true); + }}); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + static void destroyFrame(final Frame frame) throws InterruptedException { + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.dispose(); + }}); + } catch( Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + } + + private GLOffscreenAutoDrawable createGLOffscreenAutoDrawable(GLCapabilities caps, int width, int height) throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + return factory.createOffscreenAutoDrawable(null, caps, null, width, height, null); + } + + protected static boolean validateOnOffscreenLayer(GLADType gladType1, GLADType gladType2) { + final boolean useOffscreenLayer = GLADType.GLCanvasOffscreen == gladType1 || GLADType.GLCanvasOffscreen == gladType2 ; + final boolean useOnscreenLayer = GLADType.GLCanvasOnscreen == gladType1 || GLADType.GLCanvasOnscreen == gladType2 ; + if( useOffscreenLayer ) { + if( !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("Platform doesn't support offscreen rendering."); + return false; + } + } else if( useOnscreenLayer ) { + if( JAWTUtil.isOffscreenLayerRequired() ) { + System.err.println("Platform requires offscreen rendering."); + return false; + } + } + return true; + } + + protected void testGLADOneLifecycle(GLCapabilities caps, GLADType gladType, int width, int height, + GLEventListenerCounter glelTracker, SnapshotGLEventListener snapshotGLEventListener, + GLEventListenerState glelsIn, GLEventListenerState glelsOut[], GLAnimatorControl animator) + throws InterruptedException { + + final Frame frame; + final GLAutoDrawable glad; + if( GLADType.GLCanvasOnscreen == gladType ) { + if( jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerRequired() ) { + throw new InternalError("Platform requires offscreen rendering, but onscreen requested: "+gladType); + } + frame = new Frame("AWT GLCanvas"); + + glad = new GLCanvas(caps); + setGLCanvasSize((GLCanvas)glad, new Dimension(width, height)); + frame.add((GLCanvas)glad); + } else if( GLADType.GLCanvasOffscreen == gladType ) { + if( !jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerSupported() ) { + throw new InternalError("Platform doesn't support offscreen rendering: "+gladType); + } + frame = new Frame("AWT GLCanvas"); + + glad = new GLCanvas(caps); + ((GLCanvas)glad).setShallUseOffscreenLayer(true); + setGLCanvasSize((GLCanvas)glad, new Dimension(width, height)); + frame.add((GLCanvas)glad); + } else if( GLADType.GLWindow == gladType ) { + frame = null; + + glad = GLWindow.create(caps); + ((GLWindow)glad).setTitle("Newt GLWindow"); + ((GLWindow)glad).setSize(width, height); + } else if( GLADType.GLOffscreen == gladType ) { + frame = null; + + glad = this.createGLOffscreenAutoDrawable(caps, width, height); + } else { + throw new InternalError("Unsupported: "+gladType); + } + + if( null == glelsIn ) { + if( null != animator ) { + animator.add(glad); + } + glad.addGLEventListener(glelTracker); + glad.addGLEventListener(new GearsES2(1)); + glad.addGLEventListener(snapshotGLEventListener); + } + snapshotGLEventListener.setMakeSnapshot(); + + if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) { + setFrameVisible(frame); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + } else if( GLADType.GLWindow == gladType ) { + ((GLWindow)glad).setVisible(true); + } + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, true)); + Assert.assertNotNull(glad.getContext()); + Assert.assertTrue(glad.isRealized()); + + if( null != glelsIn ) { + Assert.assertEquals(0, glad.getGLEventListenerCount()); + glelsIn.moveTo(glad); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + Assert.assertEquals(3, glad.getGLEventListenerCount()); + + Assert.assertEquals(glelsIn.context, glad.getContext()); + Assert.assertEquals(glelsIn.listenerCount(), glad.getGLEventListenerCount()); + Assert.assertEquals(glelsIn.context.getGLReadDrawable(), glad.getDelegatedDrawable()); + Assert.assertEquals(glelsIn.context.getGLDrawable(), glad.getDelegatedDrawable()); + Assert.assertEquals(false, glelsIn.isOwner()); + } + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + Assert.assertEquals(0, glelTracker.disposeCount); + + if( null != glelsOut ) { + final GLContext context1 = glad.getContext(); + final GLEventListenerState _gllsOut = GLEventListenerState.moveFrom(glad); + + Assert.assertEquals(context1, _gllsOut.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, _gllsOut.listenerCount()); + Assert.assertEquals(true, _gllsOut.isOwner()); + Assert.assertEquals(null, glad.getContext()); + Assert.assertEquals(0, glad.getGLEventListenerCount()); + + glelsOut[0] = _gllsOut; + } + if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) { + destroyFrame(frame); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, false)); + } else if( GLADType.GLWindow == gladType ) { + glad.destroy(); + } else if( GLADType.GLOffscreen == gladType ) { + glad.destroy(); + } + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glad, false)); + + Assert.assertEquals(1, glelTracker.initCount); + Assert.assertTrue(1 <= glelTracker.reshapeCount); + Assert.assertTrue(1 <= glelTracker.displayCount); + if( null != glelsOut ) { + Assert.assertEquals(0, glelTracker.disposeCount); + } else { + Assert.assertEquals(1, glelTracker.disposeCount); + } + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java new file mode 100644 index 000000000..5f2b9fb53 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/glels/TestGLContextDrawableSwitch01NEWT.java @@ -0,0 +1,374 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore.glels; + +import java.io.IOException; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.WindowUpdateEvent; +import com.jogamp.newt.opengl.GLWindow; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLProfile; + +import com.jogamp.opengl.GLAutoDrawableDelegate; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLDrawableUtil; + +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.test.junit.util.UITestCase; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test re-association (switching) of GLContext/GLDrawables, + * i.e. ctx1/draw1, ctx2/draw2 -> ctx1/draw2, ctx2/draw1. + */ +public class TestGLContextDrawableSwitch01NEWT extends UITestCase { + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLContext context = drawable.createContext(null); + Assert.assertNotNull(context); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + window.setWindowDestroyNotifyAction( new Runnable() { + public void run() { + glad.windowDestroyNotifyOp(); + } } ); + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void testSwitch2WindowSingleContextGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2WindowSingleContextImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2WindowSingleContextGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2WindowSingleContextImpl(reqGLCaps); + } + + private void testSwitch2WindowSingleContextImpl(GLCapabilities caps) throws InterruptedException { + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLAutoDrawable glad1 = createGLAutoDrawable(caps, 64, 64, width, height, quitAdapter); + GLAutoDrawable glad2 = createGLAutoDrawable(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + + // create single context using glad1 and assign it to glad1, + // destroy the prev. context afterwards. + { + final GLContext newCtx = glad1.createContext(null); + Assert.assertNotNull(newCtx); + final GLContext oldCtx = glad1.setContext(newCtx, true); + Assert.assertNotNull(oldCtx); + Assert.assertFalse(oldCtx.isCreated()); + final int res = newCtx.makeCurrent(); + Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); + newCtx.release(); + } + + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + GearsES2 gears = new GearsES2(1); + glad1.addGLEventListener(gears); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + Animator animator = new Animator(); + animator.add(glad1); + animator.add(glad2); + animator.start(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glad1, glad2); + + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glad1.destroy(); + glad2.destroy(); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowOneDemoGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowOneDemoImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowOneDemoGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowOneDemoImpl(reqGLCaps); + } + + private void testSwitch2GLWindowOneDemoImpl(GLCapabilities caps) throws InterruptedException { + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GearsES2 gears = new GearsES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + + // switch context _and_ the demo synchronously + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + + snapshotGLEventListener.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + glWindow1.destroy(); + glWindow2.destroy(); + + } + + @Test(timeout=30000) + public void testSwitch2GLWindowEachWithOwnDemoGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void testSwitch2GLWindowEachWithOwnDemoGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testSwitch2GLWindowEachWithOwnDemoImpl(reqGLCaps); + } + + public void testSwitch2GLWindowEachWithOwnDemoImpl(GLCapabilities caps) throws InterruptedException { + final GearsES2 gears = new GearsES2(1); + final RedSquareES2 rsquare = new RedSquareES2(1); + final QuitAdapter quitAdapter = new QuitAdapter(); + final SnapshotGLEventListener snapshotGLEventListener1 = new SnapshotGLEventListener(); + final SnapshotGLEventListener snapshotGLEventListener2 = new SnapshotGLEventListener(); + + GLWindow glWindow1 = GLWindow.create(caps); + glWindow1.setTitle("win1"); + glWindow1.setSize(width, height); + glWindow1.setPosition(64, 64); + glWindow1.addGLEventListener(0, gears); + glWindow1.addGLEventListener(snapshotGLEventListener1); + glWindow1.addWindowListener(quitAdapter); + + GLWindow glWindow2 = GLWindow.create(caps); + glWindow2.setTitle("win2"); + glWindow2.setSize(width+100, height+100); + glWindow2.setPosition(2*64+width, 64); + glWindow2.addGLEventListener(0, rsquare); + glWindow2.addGLEventListener(snapshotGLEventListener2); + glWindow2.addWindowListener(quitAdapter); + + Animator animator = new Animator(); + animator.add(glWindow1); + animator.add(glWindow2); + animator.start(); + + glWindow1.setVisible(true); + glWindow2.setVisible(true); + + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + + int s = 0; + long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + if( ( t1 - t0 ) / period > s) { + s++; + System.err.println(s+" - switch - START "+ ( t1 - t0 )); + System.err.println(s+" - A w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - A w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + GLDrawableUtil.swapGLContextAndAllGLEventListener(glWindow1, glWindow2); + System.err.println(s+" - B w1-h 0x"+Long.toHexString(glWindow1.getHandle())+",-ctx 0x"+Long.toHexString(glWindow1.getContext().getHandle())); + System.err.println(s+" - B w2-h 0x"+Long.toHexString(glWindow2.getHandle())+",-ctx 0x"+Long.toHexString(glWindow2.getContext().getHandle())); + System.err.println(s+" - switch - END "+ ( t1 - t0 )); + snapshotGLEventListener1.setMakeSnapshot(); + snapshotGLEventListener2.setMakeSnapshot(); + } + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + animator.stop(); + // System.err.println("pre -del-w1: w1: "+glWindow1); + // System.err.println("pre -del-w1: w2: "+glWindow2); + glWindow1.destroy(); + // System.err.println("post-del-w1: w1: "+glWindow1); + // System.err.println("post-del-w1: w2: "+glWindow2); + glWindow2.destroy(); + + } + + // default timing for 2 switches + static long duration = 2200; // ms + static long period = 1000; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i+ * This test is using NEWT's plain Window w/ GLAutoDrawableDelegate. + *
+ *+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *
+ */ +public class TestGLContextDrawableSwitch10NEWT extends UITestCase { + // default period for 1 GLAD cycle + static long duration = 1000; // ms + + static int width, height; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + @BeforeClass + public static void initClass() { + width = 256; + height = 256; + } + + private GLAutoDrawable createGLAutoDrawableWithoutContext(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + final GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, null, window, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); + window.destroy(); // destroys the actual window + } + }; + + window.setWindowDestroyNotifyAction( new Runnable() { + public void run() { + glad.windowDestroyNotifyOp(); + } } ); + + // add basic window interaction + window.addWindowListener(new WindowAdapter() { + @Override + public void windowRepaint(WindowUpdateEvent e) { + glad.windowRepaintOp(); + } + @Override + public void windowResized(WindowEvent e) { + glad.windowResizedOp(window.getWidth(), window.getHeight()); + } + }); + window.addWindowListener(wl); + + return glad; + } + + @Test(timeout=30000) + public void test01GLADDelegateGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLADDelegateImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void test02GLADDelegateGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLADDelegateImpl(reqGLCaps); + } + + private void testGLADDelegateImpl(GLCapabilities caps) throws InterruptedException { + final GLEventListenerCounter glelCounter = new GLEventListenerCounter(); + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glls1; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + final QuitAdapter quitAdapter = new QuitAdapter(); + final GLAutoDrawable glad1 = createGLAutoDrawableWithoutContext(caps, 64, 64, width, height, quitAdapter); + final GLContext context1 = glad1.createContext(null); + glad1.setContext(context1, true); + animator.add(glad1); + + glad1.addGLEventListener(glelCounter); + glad1.addGLEventListener(new GearsES2(1)); + glad1.addGLEventListener(snapshotGLEventListener); + snapshotGLEventListener.setMakeSnapshot(); + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glad1.getContext()); + Assert.assertEquals(3, glad1.getGLEventListenerCount()); + Assert.assertEquals(context1.getGLReadDrawable(), glad1.getDelegatedDrawable()); + Assert.assertEquals(context1.getGLDrawable(), glad1.getDelegatedDrawable()); + + // - dis-associate context from glad1 + // - destroy glad1 + glls1 = GLEventListenerState.moveFrom(glad1); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(context1, glls1.context); + Assert.assertNull(context1.getGLReadDrawable()); + Assert.assertNull(context1.getGLDrawable()); + Assert.assertEquals(3, glls1.listenerCount()); + Assert.assertEquals(true, glls1.isOwner()); + Assert.assertEquals(null, glad1.getContext()); + Assert.assertEquals(0, glad1.getGLEventListenerCount()); + + glad1.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + } + + // - create glad2 w/ survived context + { + final QuitAdapter quitAdapter = new QuitAdapter(); + final GLAutoDrawable glad2 = createGLAutoDrawableWithoutContext(caps, 2*64+width, 64, width+100, height+100, quitAdapter); + snapshotGLEventListener.setMakeSnapshot(); + + Assert.assertEquals(null, glad2.getContext()); + Assert.assertEquals(0, glad2.getGLEventListenerCount()); + + glls1.moveTo(glad2); + + Assert.assertTrue(glad2.isRealized()); + + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(0, glelCounter.disposeCount); + Assert.assertEquals(glls1.context, glad2.getContext()); + Assert.assertEquals(3, glad2.getGLEventListenerCount()); + Assert.assertEquals(glls1.context.getGLReadDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(glls1.context.getGLDrawable(), glad2.getDelegatedDrawable()); + Assert.assertEquals(false, glls1.isOwner()); + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + + while( !quitAdapter.shouldQuit() && ( t1 - t0 ) < duration ) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + glad2.destroy(); + Assert.assertEquals(1, glelCounter.initCount); + Assert.assertTrue(1 <= glelCounter.reshapeCount); + Assert.assertTrue(1 <= glelCounter.displayCount); + Assert.assertEquals(1, glelCounter.disposeCount); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i+ * This test is using JOGL's NEWT GLWindow. + *
+ *+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *
+ */ +public class TestGLContextDrawableSwitch11NewtAWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test21GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLWindowImpl(reqGLCaps); + } + + @Test(timeout=30000) + public void test22GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLWindowImpl(reqGLCaps); + } + + private void testGLWindowImpl(GLCapabilities caps) throws InterruptedException { + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, GLADType.GLWindow, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, GLADType.GLWindow, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i+ * This test is using JOGL's AWT GLCanvas + *
+ *+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *
+ */ +public class TestGLContextDrawableSwitch12AWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test01GLCanvasOnscreenGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, false); + } + + @Test(timeout=30000) + public void test02GLCanvasOnscreenGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, false); + } + + @Test(timeout=30000) + public void test11GLCanvasOffscreenGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, true); + } + + @Test(timeout=30000) + public void test12GLCanvasOffscreenGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvasImpl(reqGLCaps, true); + } + + private void testGLCanvasImpl(GLCapabilities caps, boolean offscreenLayer) throws InterruptedException { + if( offscreenLayer ) { + if( !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("Platform doesn't support offscreen rendering."); + return; + } + } else { + if( JAWTUtil.isOffscreenLayerRequired() ) { + System.err.println("Platform requires offscreen rendering."); + return; + } + } + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, offscreenLayer ? GLADType.GLCanvasOffscreen : GLADType.GLCanvasOnscreen, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, offscreenLayer ? GLADType.GLCanvasOffscreen : GLADType.GLCanvasOnscreen, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i+ * This test moves the {@link GLEventListenerState} from a + * NEWT GLWindow before it's destruction to an AWT GLCanvas after it's creation + * and vice versa + *
+ *+ * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665. + *
+ */ +public class TestGLContextDrawableSwitch21Newt2AWT extends GLContextDrawableSwitchBase { + + @Test(timeout=30000) + public void test01GLCanvasOnScrn2GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOnscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test02GLCanvasOnScrn2GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOnscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test11GLWindow2GLCanvasOnScrnGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOnscreen); + } + + @Test(timeout=30000) + public void test12GLWindow2GLCanvasOnScrnGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOnscreen); + } + + @Test(timeout=30000) + public void test21GLCanvasOffScrn2GLWindowGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOffscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test22GLCanvasOffScrn2GLWindowGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLCanvasOffscreen, GLADType.GLWindow); + } + + @Test(timeout=30000) + public void test31GLWindow2GLCanvasOffScrnGL2ES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOffscreen); + } + + @Test(timeout=30000) + public void test32GLWindow2GLCanvasOffScrnGLES2() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); + if(null == reqGLCaps) return; + testGLCanvas2GLWindowImpl(reqGLCaps, GLADType.GLWindow, GLADType.GLCanvasOffscreen); + } + + private void testGLCanvas2GLWindowImpl(GLCapabilities caps, GLADType gladType1, GLADType gladType2) throws InterruptedException { + if( !validateOnOffscreenLayer(gladType1, gladType2) ) { + return; + } + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + final GLEventListenerCounter glelTracker = new GLEventListenerCounter(); + final Animator animator = new Animator(); + animator.start(); + + final GLEventListenerState glels[] = new GLEventListenerState[1]; + + // - create glad1 w/o context + // - create context using glad1 and assign it to glad1 + { + testGLADOneLifecycle(caps, gladType1, width, height, + glelTracker, snapshotGLEventListener, + null, + glels, animator); + } + + // - create glad2 w/ survived context + { + testGLADOneLifecycle(caps, gladType2, width+100, height+100, + glelTracker, snapshotGLEventListener, + glels[0], + null, null); + } + animator.stop(); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i