From c225285e09f0a29fca418601bf1aa07cafb54339 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 13 Mar 2013 06:35:30 +0100 Subject: Bug 665: Allow re-association of GLContext/GLEventListener to a GLDrawable (Part 4) Note: - GLEventListenerState preservs the GLAutoDrawable state, i.e. GLContext, all GLEventListener and the GLAnimatorControl association. - GLEventListenerState may be utilized to move the state from a dying GLAutoDrawable, to be moved to a new created GLAutoDrawable at a later time. - GLEventListenerState will be made public soon. +++ Exessive unit tests cover the new feature, tested manually on GNU/Linux/X11 and OSX(Java6/Java7). +++ - GLAutoDrawable - Change 'setContext(..)' to allow the destruction of the unbound old context: 'setContext(GLContext newCtx)' -> 'setContext(GLContext newCtx, boolean destroyPrevCtx)' - Implementations: Properly implement 'setRealized(..)' incl. obeying threading constraints if exists. Method is being utilized at least for GLEventListenerState.moveTo(..) to unrealize and realize the drawable resources. +++ Fix propagation of GLContext/GLDrawable association change (Bottom -> Top): GLDrawableImpl.associateContext GLContextImpl.associateDrawable GLContextImpl.makeCurrent GLContextImpl.destroy GLContext.setGLDrawable ... GLDrawableHelper.switchContext GLAutoDrawble.setContext associateDrawable(..)/associateContext(..) unifies and hence: - GLContextImpl.contextRealized() (removed) - GLDrawableImpl.contextRealized() (removed) - GLDrawableImpl.associateContext(..) (merged) - MacOSXCGLContext.drawableChangedNotify(..) (removed) +++ - EGLUpstreamSurfaceHook.evalUpstreamSurface() validates the surface's device for reusage, which is valid in case of GLEventListenerState.moveTo(..) - MacOSXCGLContext.NSOpenGLImpl: pixelFormat replaces NSOpenGLLayerPfmt and has simplified lifecycle [create..destroy], while native NSOpenGLLayer code only holds the reference until released. --- .../classes/jogamp/opengl/GLAutoDrawableBase.java | 25 +++- src/jogl/classes/jogamp/opengl/GLContextImpl.java | 59 +++++---- .../classes/jogamp/opengl/GLDrawableHelper.java | 45 +++---- src/jogl/classes/jogamp/opengl/GLDrawableImpl.java | 40 +++---- .../jogamp/opengl/GLEventListenerState.java | 55 +++++---- .../classes/jogamp/opengl/GLFBODrawableImpl.java | 14 ++- src/jogl/classes/jogamp/opengl/GLPbufferImpl.java | 10 +- .../jogamp/opengl/egl/EGLUpstreamSurfaceHook.java | 53 +++++++-- .../jogamp/opengl/macosx/cgl/MacOSXCGLContext.java | 132 +++++++++------------ .../opengl/macosx/cgl/MacOSXCGLDrawable.java | 1 - 10 files changed, 242 insertions(+), 192 deletions(-) (limited to 'src/jogl/classes/jogamp') diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index c20197e72..ad67f8281 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -326,16 +326,13 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } @Override - public final GLContext setContext(GLContext newCtx) { + public final GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) { final RecursiveLock lock = getLock(); lock.lock(); try { final GLContext oldCtx = context; - final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; - if(newCtxCurrent) { // implies null != newCtx - context.makeCurrent(); - } return oldCtx; } finally { lock.unlock(); @@ -530,6 +527,24 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } } + @Override + public final void setRealized(boolean realized) { + final RecursiveLock _lock = getLock(); + _lock.lock(); + try { + final GLDrawable _drawable = drawable; + if( null == _drawable || realized && ( 0 >= _drawable.getWidth() || 0 >= _drawable.getHeight() ) ) { + return; + } + _drawable.setRealized(realized); + if( realized && _drawable.isRealized() ) { + sendReshape=true; // ensure a reshape is being send .. + } + } finally { + _lock.unlock(); + } + } + @Override public final boolean isRealized() { final GLDrawable _drawable = drawable; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 42364dbfd..4121e8f77 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -133,9 +133,6 @@ public abstract class GLContextImpl extends GLContext { GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this); this.drawable = drawable; - if(null != drawable) { - drawable.associateContext(this, true); - } this.drawableRead = drawable; this.glDebugHandler = new GLDebugMessageHandler(this); @@ -207,25 +204,36 @@ public abstract class GLContextImpl extends GLContext { return drawable; // no change. } final Thread currentThread = Thread.currentThread(); + if( lock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } final boolean lockHeld = lock.isOwner(currentThread); + if( lockHeld && lock.getHoldCount() > 1 ) { + // would need to makeCurrent * holdCount + throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); + } + final GLDrawableImpl old = drawable; + if( isCreated() && null != old && old.isRealized() ) { + if(!lockHeld) { + makeCurrent(); + } + associateDrawable(false); + if(!lockHeld) { + release(); + } + } if(lockHeld) { release(); - } else if(lock.isLockedByOtherThread()) { // still could glitch .. - throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); - } + } if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable drawableRead = (GLDrawableImpl) readWrite; } - final GLDrawableImpl old = drawable; - if( null != old ) { - old.associateContext(this, false); - } drawableRetargeted |= null != drawable && readWrite != drawable; drawable = (GLDrawableImpl) readWrite ; - if( null != drawable ) { - drawable.associateContext(this, true); - if( lockHeld ) { - makeCurrent(); + if( isCreated() && null != drawable && drawable.isRealized() ) { + makeCurrent(true); // implicit: associateDrawable(true) + if( !lockHeld ) { + release(); } } return old; @@ -363,8 +371,7 @@ public abstract class GLContextImpl extends GLContext { makeCurrent(); } try { - contextRealized(false); - drawable.associateContext(this, false); + associateDrawable(false); } catch (Throwable t) { drawableContextRealizedException = t; } @@ -467,7 +474,11 @@ public abstract class GLContextImpl extends GLContext { * @see #destroyContextARBImpl */ @Override - public int makeCurrent() throws GLException { + public final int makeCurrent() throws GLException { + return makeCurrent(false); + } + + protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException { if( TRACE_SWITCH ) { System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock); } @@ -561,7 +572,11 @@ public abstract class GLContextImpl extends GLContext { gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } - contextRealized(true); + forceDrawableAssociation = true; + } + + if( forceDrawableAssociation ) { + associateDrawable(true); } contextMadeCurrent(true); @@ -662,14 +677,14 @@ public abstract class GLContextImpl extends GLContext { protected abstract void makeCurrentImpl() throws GLException; /** - * @see GLDrawableImpl#contextRealized(GLContext, boolean) + * Calls {@link GLDrawableImpl#associateContext(GLContext, boolean)} */ - protected void contextRealized(boolean realized) { - drawable.contextRealized(this, realized); + protected void associateDrawable(boolean bound) { + drawable.associateContext(this, bound); } /** - * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean) + * Calls {@link GLDrawableImpl#contextMadeCurrent(GLContext, boolean)} */ protected void contextMadeCurrent(boolean current) { drawable.contextMadeCurrent(this, current); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 3eedf918e..1caa942ba 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -59,7 +59,7 @@ import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLRunnable; /** Encapsulates the implementation of most of the GLAutoDrawable's - methods to be able to share it between GLCanvas and GLJPanel. */ + methods to be able to share it between GLAutoDrawable implementations like GLAutoDrawableBase, GLCanvas and GLJPanel. */ public class GLDrawableHelper { /** true if property jogl.debug.GLDrawable.PerfStats is defined. */ private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); @@ -113,6 +113,9 @@ public class GLDrawableHelper { return sb.toString(); } + /** Limit release calls of {@link #forceNativeRelease(GLContext)} to {@value}. */ + private static final int MAX_RELEASE_ITER = 512; + /** * Since GLContext's {@link GLContext#makeCurrent()} and {@link GLContext#release()} * is recursive, a call to {@link GLContext#release()} may not natively release the context. @@ -122,18 +125,25 @@ public class GLDrawableHelper { * @param ctx */ public static final void forceNativeRelease(GLContext ctx) { + int releaseCount = 0; do { ctx.release(); + releaseCount++; if (DEBUG) { - System.err.println("GLDrawableHelper.forceNativeRelease() -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent()); + System.err.println("GLDrawableHelper.forceNativeRelease() #"+releaseCount+" -- currentThread "+Thread.currentThread()+" -> "+GLContext.getCurrent()); } - } while( ctx == GLContext.getCurrent() ); + } while( MAX_RELEASE_ITER > releaseCount && ctx.isCurrent() ); + + if( ctx.isCurrent() ) { + throw new GLException("Context still current after "+MAX_RELEASE_ITER+" releases: "+ctx); + } } /** * Switch {@link GLContext} / {@link GLDrawable} association. *

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

*

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

*

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

*

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

*

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

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

*

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

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

*/ public class GLEventListenerState { - private static final boolean DEBUG = true; + private static final boolean DEBUG = GLDrawableImpl.DEBUG; - private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, + private GLEventListenerState(AbstractGraphicsScreen upstreamScreen, boolean proxyOwnsUpstreamDevice, AbstractGraphicsScreen screen, GLCapabilitiesImmutable caps, GLContext context, int count, GLAnimatorControl anim) { this.upstreamScreen = upstreamScreen; + this.proxyOwnsUpstreamDevice = proxyOwnsUpstreamDevice; this.screen = screen; this.caps = caps; this.context = context; @@ -97,6 +97,7 @@ public class GLEventListenerState { public final int listenerCount() { return listeners.length; } public final AbstractGraphicsScreen upstreamScreen; + public final boolean proxyOwnsUpstreamDevice; public final AbstractGraphicsScreen screen; public final GLCapabilitiesImmutable caps; public final GLContext context; @@ -161,25 +162,30 @@ public class GLEventListenerState { } aScreen1.getDevice().clearHandleOwner(); // don't close device handle - final AbstractGraphicsScreen aUpScreen2; + final AbstractGraphicsScreen aUpScreen2; + final boolean proxyOwnsUpstreamDevice; { AbstractGraphicsScreen _aUpScreen2=null; if(aSurface instanceof ProxySurface) { final ProxySurface aProxy = (ProxySurface)aSurface; + proxyOwnsUpstreamDevice = aProxy.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); - if(null != aUpSurface) { + if(DEBUG && null != aUpSurface) { System.err.println("X00 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); } - aProxy.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); // don't close device handle if(null != aUpSurface) { final AbstractGraphicsScreen aUpScreen1 = aUpSurface.getGraphicsConfiguration().getScreen(); _aUpScreen2 = cloneScreen(aUpScreen1); if(null != aUpScreen1) { aUpScreen1.getDevice().clearHandleOwner(); // don't close device handle } - System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); - System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if(DEBUG) { + System.err.println("X0X NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + System.err.println("X0X UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + } } + } else { + proxyOwnsUpstreamDevice = false; } aUpScreen2=_aUpScreen2; } @@ -189,7 +195,7 @@ public class GLEventListenerState { aAnim.remove(a); // also handles ECT } - final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, aScreen2, caps, a.getContext(), aSz, aAnim); + final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, proxyOwnsUpstreamDevice, aScreen2, caps, a.getContext(), aSz, aAnim); // // remove and cache all GLEventListener and their init-state @@ -205,7 +211,7 @@ public class GLEventListenerState { // a.invoke(true, glFinish); - a.setContext( null ); + a.setContext( null, false ); return glls; } @@ -241,13 +247,7 @@ public class GLEventListenerState { throw new GLException("Incompatible Capabilities - Prev-Holder: "+caps+", New-Holder "+caps); } // Destroy and remove currently associated GLContext, if any (will be replaced) - { - final GLContext ctx = a.getContext(); - if( null != ctx) { - ctx.destroy(); - } - a.setContext( null ); - } + a.setContext( null, true ); final boolean aRealized = a.isRealized(); if( aRealized ) { a.setRealized(false); @@ -260,8 +260,11 @@ public class GLEventListenerState { final AbstractGraphicsScreen aScreen1 = aCfg.getScreen(); aCfg.setScreen( screen ); aScreen1.getDevice().close(); - System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + if( DEBUG ) { + System.err.println("XXX NativeSurface: "+aSurface.getClass().getName()+", "+aSurface); + } } + // If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it { boolean upstreamSet = false; @@ -270,13 +273,19 @@ public class GLEventListenerState { final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); if(null != aUpSurface) { final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration(); - final AbstractGraphicsScreen aUpScreen1 = aUpCfg.getScreen(); if( null != upstreamScreen ) { - System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if( DEBUG ) { + System.err.println("XX0 UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString()); + } + aUpCfg.getScreen().getDevice().close(); aUpCfg.setScreen( upstreamScreen ); - aUpScreen1.getDevice().close(); + if( proxyOwnsUpstreamDevice ) { + aProxy.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } upstreamSet = true; - System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface); + if( DEBUG ) { + System.err.println("XXX UpstreamSurface: "+aUpSurface.getClass().getName()+", "+aUpSurface+", "+aProxy.getUpstreamOptionBits(null).toString()); + } } else { throw new GLException("Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true"); } @@ -292,7 +301,7 @@ public class GLEventListenerState { } final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface(); try { - a.setContext( context ); + a.setContext( context, false ); } finally { if( surfaceLocked ) { aSurface.unlockSurface(); diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 86cfa4f4c..51ec7dda6 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -38,6 +38,7 @@ import com.jogamp.opengl.JoglVersion; */ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); + protected static final boolean DEBUG_SWAP = Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true); private final GLDrawableImpl parent; private GLCapabilitiesImmutable origParentChosenCaps; @@ -92,6 +93,9 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } private final void initialize(boolean realize, GL gl) { + if( initialized == realize ) { + throw new InternalError("Already set to initialize := "+realize+": "+this); + } if(realize) { final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true) @@ -323,8 +327,8 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } @Override - protected final void contextRealized(GLContext glc, boolean realized) { - initialize(realized, glc.getGL()); + protected void associateContext(GLContext glc, boolean bound) { + initialize(bound, glc.getGL()); } @Override @@ -338,7 +342,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { swapFBOImpl(glc); swapFBOImplPost(glc); fboBound=false; - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(@release): done"); } } @@ -354,7 +358,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { swapFBOImpl(ctx); doPostSwap = true; fboBound=false; - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(@swap): done"); } } @@ -406,7 +410,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer()); } */ - if(DEBUG) { + if(DEBUG_SWAP) { System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length); } } diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index b438131bc..ddc6d5917 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -86,9 +86,10 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { // @Override - public final void setRealized(boolean realized) { + public final void swapBuffers() throws GLException { + defaultSwapBuffers(); } - + // // GLAutoDrawable completion // @@ -125,11 +126,6 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { } } - @Override - public final void swapBuffers() throws GLException { - defaultSwapBuffers(); - } - //---------------------------------------------------------------------- // Internals only below this point // diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java index 342c4c417..77e9dc173 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java @@ -47,7 +47,7 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { public final void create(ProxySurface surface) { final String dbgPrefix; if(DEBUG) { - dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): "; + dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create( up "+upstreamSurface.getClass().getSimpleName()+" -> this "+surface.getClass().getSimpleName()+" ): "; System.err.println(dbgPrefix+this); } else { dbgPrefix = null; @@ -76,24 +76,51 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { boolean isEGLSurfaceValid = true; // assume yes - final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration(); - final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); - final EGLGraphicsDevice eglDevice; - if( aDevice instanceof EGLGraphicsDevice ) { - eglDevice = (EGLGraphicsDevice) aDevice; + final AbstractGraphicsConfiguration aConfig; + { + final AbstractGraphicsConfiguration surfaceConfig = surface.getGraphicsConfiguration(); + final AbstractGraphicsDevice surfaceDevice = null != surfaceConfig ? surfaceConfig.getScreen().getDevice() : null; + if(DEBUG) { + System.err.println(dbgPrefix+"SurfaceDevice: "+surfaceDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceDevice.hashCode())+", "+surfaceDevice); + System.err.println(dbgPrefix+"SurfaceConfig: "+surfaceConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(surfaceConfig.hashCode())+", "+surfaceConfig); + } + + final AbstractGraphicsConfiguration upstreamConfig = upstreamSurface.getGraphicsConfiguration(); + final AbstractGraphicsDevice upstreamDevice = upstreamConfig.getScreen().getDevice(); if(DEBUG) { - System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice); + System.err.println(dbgPrefix+"UpstreamDevice: "+upstreamDevice.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamDevice.hashCode())+", "+upstreamDevice); + System.err.println(dbgPrefix+"UpstreamConfig: "+upstreamConfig.getClass().getSimpleName()+", hash 0x"+Integer.toHexString(upstreamConfig.hashCode())+", "+upstreamConfig); } - if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { - eglDevice.open(); + + if( surfaceDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) surfaceDevice; + aConfig = surfaceConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing this eglDevice: "+eglDevice+", using this config "+aConfig.getClass().getSimpleName()+" "+aConfig); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else if( upstreamDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) upstreamDevice; + aConfig = upstreamConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing upstream eglDevice: "+eglDevice+", using upstream config "+aConfig.getClass().getSimpleName()+" "+aConfig); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else { + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + aConfig = upstreamConfig; isEGLSurfaceValid = false; surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } - } else { - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); - isEGLSurfaceValid = false; - surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 3825f855c..a03850043 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -85,10 +85,9 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGL-based or CGL-based) protected interface GLBackendImpl { boolean isNSContext(); - void drawableChangedNotify(); long create(long share, int ctp, int major, int minor); boolean destroy(long ctx); - boolean contextRealized(boolean realized); + void associateDrawable(boolean bound); boolean copyImpl(long src, int mask); boolean makeCurrent(long ctx); boolean release(long ctx); @@ -328,20 +327,15 @@ public abstract class MacOSXCGLContext extends GLContextImpl } @Override - protected void contextRealized(boolean realized) { + protected void associateDrawable(boolean bound) { // context stuff depends on drawable stuff - if(realized) { - super.contextRealized(true); // 1) init drawable stuff - impl.contextRealized(true); // 2) init context stuff + System.err.println("MaxOSXCGLContext.associateDrawable: "+bound); + if(bound) { + super.associateDrawable(true); // 1) init drawable stuff + impl.associateDrawable(true); // 2) init context stuff } else { - impl.contextRealized(false); // 1) free context stuff - super.contextRealized(false); // 2) free drawable stuff - } - } - - /* pp */ void drawableChangedNotify() { - if( 0 != contextHandle) { - impl.drawableChangedNotify(); + impl.associateDrawable(false); // 1) free context stuff + super.associateDrawable(false); // 2) free drawable stuff } } @@ -467,9 +461,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { - private OffscreenLayerSurface backingLayerHost = null; - private long nsOpenGLLayer = 0; - private long nsOpenGLLayerPFmt = 0; // lifecycle: [create - contextRealized] + private long pixelFormat = 0; // lifecycle: [create - destroy] + private long nsOpenGLLayer = 0; // lifecycle: [associateDrawable_true - associateDrawable_false] private float screenVSyncTimeout; // microSec private int vsyncTimeout; // microSec - for nsOpenGLLayer mode private int lastWidth=0, lastHeight=0; // allowing to detect size change @@ -479,18 +472,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean isNSContext() { return true; } - @Override - public void drawableChangedNotify() { - backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); - if( null == backingLayerHost ) { - boolean[] isPBuffer = { false }; - boolean[] isFBO = { false }; - CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); - } else { - nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer(); - } - } - private long getNSViewHandle(boolean[] isPBuffer, boolean[] isFBO) { final long nsViewHandle; if(drawable instanceof GLFBODrawableImpl) { @@ -549,13 +530,12 @@ public abstract class MacOSXCGLContext extends GLContextImpl isPBuffer = _isPBuffer[0]; isFBO = _isFBO[0]; } - backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); boolean incompleteView = null != backingLayerHost; if( !incompleteView && surface instanceof ProxySurface ) { incompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); } - long pixelFormat; { final GLCapabilitiesImmutable targetCaps; if( isFBO ) { @@ -606,48 +586,54 @@ public abstract class MacOSXCGLContext extends GLContextImpl } config.setChosenCapabilities(fixedCaps); - try { - final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1); - // Try to allocate a context with this - ctx = CGL.createContext(share, - nsViewHandle, incompleteView, - pixelFormat, - chosenCaps.isBackgroundOpaque(), - viewNotReady); - if (0 == ctx) { - if(DEBUG) { - System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0))); - } - return 0; + final IntBuffer viewNotReady = Buffers.newDirectIntBuffer(1); + // Try to allocate a context with this + ctx = CGL.createContext(share, nsViewHandle, incompleteView, + pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady); + if (0 == ctx) { + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady.get(0))); } + return 0; + } - if(null != backingLayerHost) { - nsOpenGLLayerPFmt = pixelFormat; - pixelFormat = 0; - } - - if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { - // Set the context opacity - CGL.setContextOpacity(ctx, 0); - } - } finally { - if(0!=pixelFormat) { - CGL.deletePixelFormat(pixelFormat); - pixelFormat = 0; - } + if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { + // Set the context opacity + CGL.setContextOpacity(ctx, 0); } return ctx; } @Override public boolean destroy(long ctx) { + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + pixelFormat = 0; + } return CGL.deleteContext(ctx, true); + } @Override - public boolean contextRealized(boolean realized) { - if( realized ) { + public void associateDrawable(boolean bound) { + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); + + if(DEBUG) { + System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+", hasBackingLayerHost "+(null!=backingLayerHost)); + } + + if( bound ) { + if( null != backingLayerHost ) { + + if( 0 != nsOpenGLLayer ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set local: "+nsOpenGLLayer+", "+this); + } + nsOpenGLLayer = backingLayerHost.getAttachedSurfaceLayer(); + if( 0 != nsOpenGLLayer ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=true, hasBackingLayerHost=true, but 'nsOpenGLLayer' is already/still set on backingLayerHost: "+nsOpenGLLayer+", "+this); + } + // // handled layered surface // @@ -700,8 +686,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } final boolean ctxUnlocked = CGL.kCGLNoError == CGL.CGLUnlockContext(cglCtx); try { - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, nsOpenGLLayerPFmt, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); - nsOpenGLLayerPFmt = 0; // NSOpenGLLayer will release pfmt + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); if (DEBUG) { System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); } @@ -718,17 +703,22 @@ public abstract class MacOSXCGLContext extends GLContextImpl } else { lastWidth = drawable.getWidth(); lastHeight = drawable.getHeight(); + boolean[] isPBuffer = { false }; + boolean[] isFBO = { false }; + CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); } } else { if( 0 != nsOpenGLLayer ) { - final NativeSurface surface = drawable.getNativeSurface(); + if( null == backingLayerHost ) { // FIXME: redundant + throw new InternalError("Lifecycle: bound=false, hasNSOpneGLLayer=true, but 'backingLayerHost' is null local: "+nsOpenGLLayer+", "+this); + } + if (DEBUG) { System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable); } - final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - if(null != ols && ols.isSurfaceLayerAttached()) { + if( backingLayerHost.isSurfaceLayerAttached() ) { // still having a valid OLS attached to surface (parent OLS could have been removed) - ols.detachSurfaceLayer(); + backingLayerHost.detachSurfaceLayer(); } CGL.releaseNSOpenGLLayer(nsOpenGLLayer); if( null != gl3ShaderProgram ) { @@ -738,8 +728,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl nsOpenGLLayer = 0; } } - backingLayerHost = null; - return true; } private final void validatePBufferConfig(long ctx) { @@ -888,11 +876,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean isNSContext() { return false; } - @Override - public void drawableChangedNotify() { - // FIXME - } - @Override public long create(long share, int ctp, int major, int minor) { long ctx = 0; @@ -947,8 +930,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } @Override - public boolean contextRealized(boolean realized) { - return true; + public void associateDrawable(boolean bound) { } @Override diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index ff1772860..0f282d33f 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -119,7 +119,6 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { if(bound) { final MacOSXCGLContext osxCtx = (MacOSXCGLContext)ctx; createdContexts.add(new WeakReference(osxCtx)); - osxCtx.drawableChangedNotify(); } else { for(int i=0; i ref = createdContexts.get(i); -- cgit v1.2.3