diff options
author | Sven Gothel <[email protected]> | 2013-03-19 00:22:28 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-03-19 00:22:28 +0100 |
commit | f354fb204d8973453c538dda78a2c82c87be61dc (patch) | |
tree | f70748d4aaaacd442f9baa146be554120d8f8080 /src | |
parent | 12e868f79938f44eba6f50313f977be76d8ea2bb (diff) |
OSX/CALayer: OSX/CALayer Threading Part3 - Run CALayer ops in a streaming design on main-thread w/o [infinitive] blocking
History:
Part1 commit 896e8b021b39e9415040a57a1d540d7d24b02db1 (Run CALayer Ops on current thread to avoid blocking)
Part2 commit 28c6472335b924080d638b33a28f8f4eedb459b1 (Run CALayer Ops on main-thread w/o blocking)
Dependency:
GlueGen commit 4becdfa125b07ff969d6540e1112735b53cd15eb (Fix RecursiveLockImpl* Timeout corner case)
Part2 misses essential locking of the OpenGL context (and it's surface upfront) while creating the
NSOpenGLLayer instance. The latter instantiates a OpenGL context shared w/ JOGL's, hence it cannot be locked.
Encapsulating NSOpenGLLayer creation/attachment and it's detachment/release in sub-classes
AttachNSOpenGLLayer and DetachNSOpenGLLayer, where instances will be streamed on main-thread.
Both tasks are triggered at associateDrawable(boolean bound).
The mentioned GL context locking requires disturbs the 'streaming' design considerably in AttachNSOpenGLLayer.
It is solved by attempt to acquire the recursive lock of the surface and the context via 'tryLock(maxwait)'
w/ screen-vSync-period/2. If the locks could not be acquired completly, the AttachNSOpenGLLayer instance
will be re-queued to the main-thread for later execution.
Before DetachNSOpenGLLayer is being streamed, it is validated whether AttachNSOpenGLLayer did run.
A recursive situation does happen w/ resizing an offscreen pbuffer drawable! Hence extra care is being taken.
Diffstat (limited to 'src')
14 files changed, 439 insertions, 259 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 4121e8f77..64ade3eff 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -367,7 +367,7 @@ public abstract class GLContextImpl extends GLContext { try { // release current context if(lock.getHoldCount() == 1) { - // needs current context to disable debug handler + // needs current context to call associateDrawable(..) and to disable debug handler makeCurrent(); } try { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 1caa942ba..9c1cd478b 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -190,7 +190,7 @@ public class GLDrawableHelper { * <li>make context current, if it was current</li> * </ul> * <p> - * No locking is being performed, caller is required to take care of it. + * Locking is performed via {@link GLContext#makeCurrent()} on the passed <code>context</code>. * </p> * * @param drawable diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index f01e03a2f..33893e456 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -71,6 +71,7 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.os.Platform; import com.jogamp.common.util.VersionNumber; +import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.opengl.GLExtensions; @@ -461,10 +462,13 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { - private long pixelFormat = 0; // lifecycle: [create - destroy] - private volatile long nsOpenGLLayer = 0; // lifecycle: [associateDrawable_true - associateDrawable_false] - private float screenVSyncTimeout = 16666; // microSec - defaults to 1/60s - private volatile int vsyncTimeout = 16666 + 1000; // microSec - for nsOpenGLLayer mode - defaults to 1/60s + 1ms + private OffscreenLayerSurface backingLayerHost = null; + /** lifecycle: [create - destroy] */ + private long pixelFormat = 0; + /** microSec - defaults to 1/60s */ + private int screenVSyncTimeout = 16666; + /** microSec - for nsOpenGLLayer mode - defaults to 1/60s + 1ms */ + private volatile int vsyncTimeout = 16666 + 1000; private int lastWidth=0, lastHeight=0; // allowing to detect size change private boolean needsSetContextPBuffer = false; private ShaderProgram gl3ShaderProgram = null; @@ -562,7 +566,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } final int sRefreshRate = OSXUtil.GetScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex()); if( 0 < sRefreshRate ) { - screenVSyncTimeout = 1000000f / sRefreshRate; + screenVSyncTimeout = 1000000 / sRefreshRate; } if(DEBUG) { System.err.println("NS create OSX>=lion "+isLionOrLater); @@ -608,32 +612,147 @@ public abstract class MacOSXCGLContext extends GLContextImpl return CGL.deleteContext(ctx, true); } + /** + * NSOpenGLLayer creation and it's attachment is performed on the main-thread w/o [infinite] blocking. + * <p> + * Since NSOpenGLLayer creation requires this context for it's shared context creation, + * this method attempts to acquire the surface and context lock with {@link #screenVSyncTimeout}/2 maximum wait time. + * If the surface and context lock could not be acquired, this runnable is being re-queued for later execution. + * </p> + * <p> + * Hence this method blocks the main-thread only for a short period of time. + * </p> + */ + class AttachNSOpenGLLayer implements Runnable { + final OffscreenLayerSurface ols; + final long ctx; + final int shaderProgram; + final long pfmt; + final long pbuffer; + final int texID; + final boolean isOpaque; + final int width; + final int height; + /** Synchronized by instance's monitor */ + long nsOpenGLLayer; + /** Synchronized by instance's monitor */ + boolean valid; + + AttachNSOpenGLLayer(OffscreenLayerSurface ols, long ctx, int shaderProgram, long pfmt, long pbuffer, int texID, boolean isOpaque, int width, int height) { + this.ols = ols; + this.ctx = ctx; + this.shaderProgram = shaderProgram; + this.pfmt = pfmt; + this.pbuffer = pbuffer; + this.texID = texID; + this.isOpaque = isOpaque; + this.width = width; + this.height = height; + this.valid = false; + this.nsOpenGLLayer = 0; + } + + @Override + public void run() { + synchronized(this) { + if( !valid ) { + try { + final int maxwait = screenVSyncTimeout/2000; // TO 1/2 of current screen-vsync in [ms] + final RecursiveLock surfaceLock = ols.getLock(); + if( surfaceLock.tryLock( maxwait ) ) { + try { + if( MacOSXCGLContext.this.lock.tryLock( maxwait ) ) { + try { + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, shaderProgram, pfmt, pbuffer, texID, isOpaque, width, height); + ols.attachSurfaceLayer(nsOpenGLLayer); + final int currentInterval = MacOSXCGLContext.this.getSwapInterval(); + final int interval = 0 <= currentInterval ? currentInterval : 1; + setSwapIntervalImpl(nsOpenGLLayer, interval); // enabled per default in layered surface + valid = true; + if (DEBUG) { + System.err.println("NSOpenGLLayer.Attach: OK, layer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbuffer)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", drawableHandle "+toHexString(drawable.getHandle())+" - "+Thread.currentThread().getName()); + } + } finally { + MacOSXCGLContext.this.lock.unlock(); + } + } + } finally { + surfaceLock.unlock(); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + if( !valid ) { + // could not acquire lock, re-queue + if (DEBUG) { + System.err.println("NSOpenGLLayer.Attach: Re-Queue, drawableHandle "+toHexString(drawable.getHandle())+" - "+Thread.currentThread().getName()); + } + OSXUtil.RunLater(this, 1); + } + } + } + } + } + AttachNSOpenGLLayer attachCALayerCmd = null; + + class DetachNSOpenGLLayer implements Runnable { + final AttachNSOpenGLLayer cmd; + + DetachNSOpenGLLayer(AttachNSOpenGLLayer cmd) { + this.cmd = cmd; + } + @Override + public void run() { + synchronized( cmd ) { + if( cmd.valid ) { + // still having a valid OLS attached to surface (parent OLS could have been removed) + try { + final OffscreenLayerSurface ols = cmd.ols; + final long l = ols.getAttachedSurfaceLayer(); + if( 0 != l ) { + ols.detachSurfaceLayer(); + } + } catch(Throwable t) { + System.err.println("Catched exception @ "+Thread.currentThread().getName()+": "); + t.printStackTrace(); + } + CGL.releaseNSOpenGLLayer(cmd.nsOpenGLLayer); + if(DEBUG) { + System.err.println("NSOpenGLLayer.Detach: OK, layer "+toHexString(cmd.nsOpenGLLayer)+", drawableHandle "+toHexString(drawable.getHandle())+" - "+Thread.currentThread().getName()); + } + cmd.nsOpenGLLayer = 0; + cmd.valid = false; + } else if(DEBUG) { + System.err.println("NSOpenGLLayer.Detach: Skipped "+toHexString(cmd.nsOpenGLLayer)+", drawableHandle "+toHexString(drawable.getHandle())+" - "+Thread.currentThread().getName()); + } + } + } + } + @Override public void associateDrawable(boolean bound) { - final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); + backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); if(DEBUG) { System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+", hasBackingLayerHost "+(null!=backingLayerHost)); + // Thread.dumpStack(); } 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); - } + if( null != backingLayerHost ) { + final GLCapabilitiesImmutable chosenCaps; + final long ctx; + final int texID; + final long pbufferHandle; + final int gl3ShaderProgramName; // // handled layered surface // - final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities(); - final long ctx = MacOSXCGLContext.this.getHandle(); - final int texID; + chosenCaps = drawable.getChosenGLCapabilities(); + ctx = MacOSXCGLContext.this.getHandle(); final long drawableHandle = drawable.getHandle(); - final long pbufferHandle; if(drawable instanceof GLFBODrawableImpl) { final GLFBODrawableImpl fbod = (GLFBODrawableImpl)drawable; texID = fbod.getTextureBuffer(GL.GL_FRONT).getName(); @@ -657,7 +776,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(0>=lastWidth || 0>=lastHeight || !drawable.isRealized()) { throw new GLException("Drawable not realized yet or invalid texture size, texSize "+lastWidth+"x"+lastHeight+", "+drawable); } - final int gl3ShaderProgramName; if( MacOSXCGLContext.this.isGL3core() ) { if( null == gl3ShaderProgram) { gl3ShaderProgram = createCALayerShader(MacOSXCGLContext.this.gl.getGL3()); @@ -665,88 +783,42 @@ public abstract class MacOSXCGLContext extends GLContextImpl gl3ShaderProgramName = gl3ShaderProgram.program(); } else { gl3ShaderProgramName = 0; - } + } - /** - * NSOpenGLLayer creation and it's attachment is performed on the main w/o blocking, - * due to OSX main-thread requirements. - * Note: It somewhat works from another thread, however, - * GC-dealloc of the 'released' resources would happen very late! - * - * NSOpenGLLayer initialization creates it's own GL ctx sharing - * this ctx, hence we have to lock this ctx in the main-thread. - * - * Locking of this ctx while creation and attachment - * also gives us good means of synchronization, i.e. it will be - * performed after this thread ends it's associateDrawable() [makeCurrent(), setDrawable(..)] - * and before the next display cycle involving makeCurrent(). - */ - OSXUtil.RunOnMainThread(false, new Runnable() { - public void run() { - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer.0 "+Thread.currentThread().getName()); - } - final long cglCtx = CGL.getCGLContext(ctx); - if(0 == cglCtx) { - throw new GLException("Null CGLContext for: "+MacOSXCGLContext.this); - } - if( CGL.kCGLNoError != CGL.CGLLockContext(cglCtx) ) { - throw new GLException("Could not lock CGLContext for: "+MacOSXCGLContext.this); - } - try { - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer.2 "+Thread.currentThread().getName()+": "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(pbufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); - } - backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); - setSwapInterval(1); // enabled per default in layered surface - } catch (Throwable t) { - throw new GLException("createNSOpenGLLayer failed for: "+MacOSXCGLContext.this, t); - } finally { - if(CGL.kCGLNoError != CGL.CGLUnlockContext(cglCtx)) { - throw new GLException("Could not unlock CGLContext for: "+MacOSXCGLContext.this); - } - } - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer.X "+Thread.currentThread().getName()); - } - } - }); - CGL.setContextView(contextHandle, 0); // [ctx clearDrawable] + // All CALayer lifecycle ops are deferred on main-thread + attachCALayerCmd = new AttachNSOpenGLLayer( + backingLayerHost, ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, + chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight ); + OSXUtil.RunOnMainThread(false, attachCALayerCmd); } else { // -> null == backingLayerHost lastWidth = drawable.getWidth(); lastHeight = drawable.getHeight(); boolean[] isPBuffer = { false }; boolean[] isFBO = { false }; - CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); // will call [ctx clearDrawable] if view == 0, otherwise [ctx setView: view] if valid + CGL.setContextView(contextHandle, getNSViewHandle(isPBuffer, isFBO)); } } else { // -> !bound - if( 0 != nsOpenGLLayer ) { - if( null == backingLayerHost ) { // FIXME: redundant - throw new InternalError("Lifecycle: bound=false, hasNSOpneGLLayer=true, but 'backingLayerHost' is null local: "+nsOpenGLLayer+", "+this); + if( null != backingLayerHost ) { + final AttachNSOpenGLLayer cmd = attachCALayerCmd; + attachCALayerCmd = null; + if( 0 != cmd.pbuffer ) { + CGL.setContextPBuffer(contextHandle, 0); } - - if (DEBUG) { - System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable); - } - if( backingLayerHost.isSurfaceLayerAttached() ) { - // still having a valid OLS attached to surface (parent OLS could have been removed) - backingLayerHost.detachSurfaceLayer(); - } - // All CALayer lifecycle calls are deferred on main-thread, so is this. - final long _nsOpenGLLayer = nsOpenGLLayer; - nsOpenGLLayer = 0; - OSXUtil.RunOnMainThread(false, new Runnable() { - public void run() { - CGL.releaseNSOpenGLLayer(_nsOpenGLLayer); - } - }); - if( null != gl3ShaderProgram ) { - gl3ShaderProgram.destroy(MacOSXCGLContext.this.gl.getGL3()); - gl3ShaderProgram = null; + synchronized(cmd) { + if( !cmd.valid ) { + cmd.valid = true; // skip pending creation + } else { + // All CALayer lifecycle ops are deferred on main-thread + OSXUtil.RunOnMainThread(false, new DetachNSOpenGLLayer(cmd)); + if( null != gl3ShaderProgram ) { + gl3ShaderProgram.destroy(MacOSXCGLContext.this.gl.getGL3()); + gl3ShaderProgram = null; + } + } } } - CGL.setContextView(contextHandle, 0); // [ctx clearDrawable] + CGL.clearDrawable(contextHandle); + backingLayerHost = null; } } @@ -832,65 +904,83 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean setSwapInterval(int interval) { - if(0 != nsOpenGLLayer) { - CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + final AttachNSOpenGLLayer cmd = attachCALayerCmd; + if(null != cmd) { + synchronized(cmd) { + if( cmd.valid && 0 != cmd.nsOpenGLLayer) { + setSwapIntervalImpl(cmd.nsOpenGLLayer, interval); + return true; + } + } + } + setSwapIntervalImpl(0, interval); + return true; + } + + private void setSwapIntervalImpl(final long l, int interval) { + if( 0 != l ) { + CGL.setNSOpenGLLayerSwapInterval(l, interval); if( 0 < interval ) { - vsyncTimeout = interval * (int)screenVSyncTimeout + 1000; // +1ms + vsyncTimeout = interval * screenVSyncTimeout + 1000; // +1ms } if(DEBUG) { System.err.println("NS setSwapInterval: "+interval+" -> "+vsyncTimeout+" micros"); } } + if(DEBUG) { System.err.println("CGL setSwapInterval: "+interval); } CGL.setSwapInterval(contextHandle, interval); - return true; } - + private int skipSync=0; @Override public boolean swapBuffers() { - final boolean res; - if( 0 != nsOpenGLLayer ) { - if( validateDrawableSizeConfig(contextHandle) ) { - // skip wait-for-vsync for a few frames if size has changed, - // allowing to update the texture IDs ASAP. - skipSync = 10; - } - - final int texID; - final boolean valid; - final boolean isFBO = drawable instanceof GLFBODrawableImpl; - if( isFBO ){ - texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName(); - valid = 0 != texID; - } else { - texID = 0; - valid = 0 != drawable.getHandle(); - } - if(valid) { - if(0 == skipSync) { - // If v-sync is disabled, frames will be drawn as quickly as possible w/o delay, - // while still synchronizing w/ CALayer. - // If v-sync is enabled wait until next swap interval (v-sync). - CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout); - } else { - skipSync--; - } - res = CGL.flushBuffer(contextHandle); - if(res) { - if(isFBO) { - // trigger CALayer to update incl. possible surface change (texture) - CGL.setNSOpenGLLayerNeedsDisplayFBO(nsOpenGLLayer, texID); + final AttachNSOpenGLLayer cmd = attachCALayerCmd; + if(null != cmd) { + synchronized(cmd) { + if( cmd.valid && 0 != cmd.nsOpenGLLayer) { + if( validateDrawableSizeConfig(contextHandle) ) { + // skip wait-for-vsync for a few frames if size has changed, + // allowing to update the texture IDs ASAP. + skipSync = 10; + } + + final boolean res; + final int texID; + final boolean valid; + final boolean isFBO = drawable instanceof GLFBODrawableImpl; + if( isFBO ){ + texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName(); + valid = 0 != texID; + } else { + texID = 0; + valid = 0 != drawable.getHandle(); + } + if(valid) { + res = CGL.flushBuffer(contextHandle); + if(res) { + if(0 == skipSync) { + // If v-sync is disabled, frames will be drawn as quickly as possible w/o delay, + // while still synchronizing w/ CALayer. + // If v-sync is enabled wait until next swap interval (v-sync). + CGL.waitUntilNSOpenGLLayerIsReady(cmd.nsOpenGLLayer, vsyncTimeout); + } else { + skipSync--; + } + if(isFBO) { + // trigger CALayer to update incl. possible surface change (texture) + CGL.setNSOpenGLLayerNeedsDisplayFBO(cmd.nsOpenGLLayer, texID); + } else { + // trigger CALayer to update incl. possible surface change (new pbuffer handle) + CGL.setNSOpenGLLayerNeedsDisplayPBuffer(cmd.nsOpenGLLayer, drawable.getHandle()); + } + } } else { - // trigger CALayer to update incl. possible surface change (new pbuffer handle) - CGL.setNSOpenGLLayerNeedsDisplayPBuffer(nsOpenGLLayer, drawable.getHandle()); + res = true; } + return res; } - } else { - res = true; } - } else { - res = CGL.flushBuffer(contextHandle); } - return res; + return CGL.flushBuffer(contextHandle); } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 15a0f550f..16d4a07ef 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -85,7 +85,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected long drawable; protected Rectangle bounds; protected Insets insets; - private long offscreenSurfaceLayer; + private volatile long offscreenSurfaceLayer; private long drawable_old; @@ -135,12 +135,12 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected synchronized void invalidate() { if(DEBUG) { - System.err.println("JAWTWindow.invalidate()"); + System.err.println("JAWTWindow.invalidate() - "+Thread.currentThread().getName()); + if( isSurfaceLayerAttached() ) { + System.err.println("OffscreenSurfaceLayer still attached: 0x"+Long.toHexString(offscreenSurfaceLayer)); + } // Thread.dumpStack(); } - if( isSurfaceLayerAttached() ) { - detachSurfaceLayer(); - } invalidateNative(); jawt = null; isOffscreenLayerSurface = false; @@ -227,21 +227,16 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, if( !isOffscreenLayerSurfaceEnabled() ) { throw new NativeWindowException("Not an offscreen layer surface"); } - int lockRes = lockSurface(); - if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - throw new NativeWindowException("Could not lock (offscreen layer): "+this); - } - try { - if(DEBUG) { - System.err.println("JAWTWindow.attachSurfaceHandle: "+toHexString(layerHandle) + ", bounds "+bounds); - } - attachSurfaceLayerImpl(layerHandle); - offscreenSurfaceLayer = layerHandle; - } finally { - unlockSurface(); + if(DEBUG) { + System.err.println("JAWTWindow.attachSurfaceHandle: "+toHexString(layerHandle) + ", bounds "+bounds); } + attachSurfaceLayerImpl(layerHandle); + offscreenSurfaceLayer = layerHandle; + layoutSurfaceLayerImpl(layerHandle, getWidth(), getHeight()); + } + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); } - protected abstract void attachSurfaceLayerImpl(final long layerHandle); /** * Layout the offscreen layer according to the implementing class's constraints. @@ -256,38 +251,39 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, * @see #isOffscreenLayerSurfaceEnabled() * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false */ - protected void layoutSurfaceLayerImpl() {} + protected void layoutSurfaceLayerImpl(long layerHandle, int width, int height) {} private final void layoutSurfaceLayerIfEnabled() throws NativeWindowException { if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) { - layoutSurfaceLayerImpl(); + layoutSurfaceLayerImpl(offscreenSurfaceLayer, getWidth(), getHeight()); } } @Override public final void detachSurfaceLayer() throws NativeWindowException { - if( !isOffscreenLayerSurfaceEnabled() ) { - throw new java.lang.UnsupportedOperationException("Not an offscreen layer surface"); - } if( 0 == offscreenSurfaceLayer) { throw new NativeWindowException("No offscreen layer attached: "+this); } - int lockRes = lockSurface(); - if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - throw new NativeWindowException("Could not lock (offscreen layer): "+this); - } - try { - if(DEBUG) { - System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer)); - } - detachSurfaceLayerImpl(offscreenSurfaceLayer); - offscreenSurfaceLayer = 0; - } finally { - unlockSurface(); + if(DEBUG) { + System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer)); } + detachSurfaceLayerImpl(offscreenSurfaceLayer, detachSurfaceLayerNotify); } - protected abstract void detachSurfaceLayerImpl(final long layerHandle); + private final Runnable detachSurfaceLayerNotify = new Runnable() { + @Override + public void run() { + offscreenSurfaceLayer = 0; + } + }; + + /** + * @param detachNotify Runnable to be called before native detachment + */ + protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + @Override public final long getAttachedSurfaceLayer() { @@ -305,6 +301,11 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, getPrivateGraphicsConfiguration().setChosenCapabilities(caps); } + @Override + public final RecursiveLock getLock() { + return surfaceLock; + } + // // SurfaceUpdateListener // diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java index 8c02a68bb..1826008ad 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -27,6 +27,8 @@ */ package javax.media.nativewindow; +import com.jogamp.common.util.locks.RecursiveLock; + /** * Interface specifying the offscreen layer surface protocol. */ @@ -60,4 +62,7 @@ public interface OffscreenLayerSurface { /** Sets the capabilities of this instance, allowing upstream API's to refine it, i.e. OpenGL related settings. */ public void setChosenCapabilities(CapabilitiesImmutable caps); + /** Returns the recursive lock object of this surface, which synchronizes multithreaded access. */ + public RecursiveLock getLock(); + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index d11d24664..9f76392a9 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -69,16 +69,18 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } } + @Override protected void invalidateNative() { if(DEBUG) { System.err.println("MacOSXJAWTWindow.invalidateNative(): osh-enabled "+isOffscreenLayerSurfaceEnabled()+ - ", osh-set "+offscreenSurfaceHandleSet+ - ", osh "+toHexString(offscreenSurfaceHandle)+ - ", rsh "+toHexString(rootSurfaceLayer)+ + ", osd-set "+offscreenSurfaceDrawableSet+ + ", osd "+toHexString(offscreenSurfaceDrawable)+ + ", osl "+toHexString(getAttachedSurfaceLayer())+ + ", rsl "+toHexString(rootSurfaceLayer)+ ", wh "+toHexString(windowHandle)+" - "+Thread.currentThread().getName()); } - offscreenSurfaceHandle=0; - offscreenSurfaceHandleSet=false; + offscreenSurfaceDrawable=0; + offscreenSurfaceDrawableSet=false; if( isOffscreenLayerSurfaceEnabled() ) { if(0 != windowHandle) { OSXUtil.DestroyNSWindow(windowHandle); @@ -108,29 +110,41 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { jawt.FreeDrawingSurface(ds); } } - OSXUtil.DestroyCALayer(rootSurfaceLayer); - rootSurfaceLayer = 0; + + OSXUtil.RunOnMainThread(false, new Runnable() { + public void run() { + OSXUtil.DestroyCALayer(rootSurfaceLayer, false); + rootSurfaceLayer = 0; + } + }); } } windowHandle=0; } + @Override protected void attachSurfaceLayerImpl(final long layerHandle) { OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, getWidth(), getHeight()); } - protected void layoutSurfaceLayerImpl() { - final long osl = getAttachedSurfaceLayer(); - final int w = getWidth(); - final int h = getHeight(); + @Override + protected void layoutSurfaceLayerImpl(long layerHandle, int width, int height) { if(DEBUG) { - System.err.println("JAWTWindow.fixSurfaceLayerLayout: "+toHexString(osl) + ", bounds "+bounds+", "+w+"x"+h); + System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", "+width+"x"+height+"; "+this); } - OSXUtil.FixCALayerLayout(rootSurfaceLayer, osl, w, h); + OSXUtil.FixCALayerLayout(rootSurfaceLayer, layerHandle, width, height); } - protected void detachSurfaceLayerImpl(final long layerHandle) { - OSXUtil.RemoveCASublayer(rootSurfaceLayer, layerHandle); + @Override + protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) { + OSXUtil.RunOnMainThread(false, new Runnable() { + public void run() { + final long l = MacOSXJAWTWindow.this.getAttachedSurfaceLayer(); + if( 0 != l ) { + detachNotify.run(); + OSXUtil.RemoveCASublayer(rootSurfaceLayer, layerHandle, false); + } + } } ); } @Override @@ -140,7 +154,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { @Override public final long getSurfaceHandle() { - return offscreenSurfaceHandleSet ? offscreenSurfaceHandle : drawable /* super.getSurfaceHandle() */ ; + return offscreenSurfaceDrawableSet ? offscreenSurfaceDrawable : drawable /* super.getSurfaceHandle() */ ; } public void setSurfaceHandle(long surfaceHandle) { @@ -150,8 +164,8 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { if(DEBUG) { System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): "+toHexString(surfaceHandle)); } - this.offscreenSurfaceHandle = surfaceHandle; - this.offscreenSurfaceHandleSet = true; + this.offscreenSurfaceDrawable = surfaceHandle; + this.offscreenSurfaceDrawableSet = true; } protected JAWT fetchJAWTImpl() throws NativeWindowException { @@ -257,7 +271,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } if(null != errMsg) { if(0 != rootSurfaceLayer) { - OSXUtil.DestroyCALayer(rootSurfaceLayer); + OSXUtil.DestroyCALayer(rootSurfaceLayer, true); rootSurfaceLayer = 0; } if(0 != windowHandle) { @@ -329,11 +343,11 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - private long rootSurfaceLayer = 0; // attached to the JAWT_SurfaceLayer + private volatile long rootSurfaceLayer = 0; // attached to the JAWT_SurfaceLayer private long windowHandle = 0; - private long offscreenSurfaceHandle = 0; - private boolean offscreenSurfaceHandleSet = false; + private long offscreenSurfaceDrawable = 0; + private boolean offscreenSurfaceDrawableSet = false; // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 5d1d43792..905a313d5 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -64,13 +64,6 @@ public class WindowsJAWTWindow extends JAWTWindow { windowHandle = 0; } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 467809284..2e5dc7fb5 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -59,13 +59,6 @@ public class X11JAWTWindow extends JAWTWindow { protected void invalidateNative() { } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 703c3d972..4b102be00 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -138,11 +138,15 @@ public class OSXUtil implements ToolkitProperties { /** * Create a CALayer suitable to act as a root CALayer. - * @see #DestroyCALayer(long) + * @see #DestroyCALayer(long, boolean) * @see #AddCASublayer(long, long) */ public static long CreateCALayer(final int x, final int y, final int width, final int height) { - return CreateCALayer0(x, y, width, height); + final long l = CreateCALayer0(x, y, width, height); + if(DEBUG) { + System.err.println("OSXUtil.CreateCALayer: 0x"+Long.toHexString(l)+" - "+Thread.currentThread().getName()); + } + return l; } /** @@ -156,7 +160,7 @@ public class OSXUtil implements ToolkitProperties { * they will be used for creation. * </p> * @see #CreateCALayer(int, int, int, int) - * @see #RemoveCASublayer(long, long) + * @see #RemoveCASublayer(long, long, boolean) */ public static void AddCASublayer(final long rootCALayer, final long subCALayer, final int width, final int height) { if(0==rootCALayer || 0==subCALayer) { @@ -164,6 +168,9 @@ public class OSXUtil implements ToolkitProperties { } RunOnMainThread(false, new Runnable() { public void run() { + if(DEBUG) { + System.err.println("OSXUtil.AttachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } AddCASublayer0(rootCALayer, subCALayer, width, height); } }); @@ -193,32 +200,48 @@ public class OSXUtil implements ToolkitProperties { } /** - * Detach a sub CALayer from the root CALayer on the main-thread w/o blocking. + * Detach a sub CALayer from the root CALayer. + * @param onMainThread if <code>true</code> method will be performed on the main-thread w/o blocking. */ - public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) { + public static void RemoveCASublayer(final long rootCALayer, final long subCALayer, boolean onMainThread) { if(0==rootCALayer || 0==subCALayer) { throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); } - RunOnMainThread(false, new Runnable() { + final Runnable action = new Runnable() { public void run() { + if(DEBUG) { + System.err.println("OSXUtil.DetachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } RemoveCASublayer0(rootCALayer, subCALayer); - } - }); + } }; + if( onMainThread ) { + RunOnMainThread(false, action); + } else { + action.run(); + } } /** - * Destroy a CALayer on main-thread w/o blocking. + * Destroy a CALayer. + * @param onMainThread if <code>true</code> method will be performed on the main-thread w/o blocking. * @see #CreateCALayer(int, int, int, int) */ - public static void DestroyCALayer(final long caLayer) { + public static void DestroyCALayer(final long caLayer, boolean onMainThread) { if(0==caLayer) { throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); } - RunOnMainThread(false, new Runnable() { + final Runnable action = new Runnable() { public void run() { + if(DEBUG) { + System.err.println("OSXUtil.DestroyCALayer: 0x"+Long.toHexString(caLayer)+" - "+Thread.currentThread().getName()); + } DestroyCALayer0(caLayer); - } - }); + } }; + if( onMainThread ) { + RunOnMainThread(false, action); + } else { + action.run(); + } } /** @@ -238,7 +261,7 @@ public class OSXUtil implements ToolkitProperties { // otherwise we may freeze the OSX main thread. Throwable throwable = null; final Object sync = new Object(); - final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true ); + final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); synchronized(sync) { RunOnMainThread0(rt); if( waitUntilDone ) { @@ -258,6 +281,16 @@ public class OSXUtil implements ToolkitProperties { } } + /** + * Run later on current OSX thread. + * + * @param runnable + * @param delay delay to run the runnable in milliseconds + */ + public static void RunLater(Runnable runnable, int delay) { + RunLater0(new RunnableTask( runnable, null, true, System.err ), delay); + } + private static Runnable _nop = new Runnable() { public void run() {}; }; /** Issues a {@link #RunOnMainThread(boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done. */ @@ -282,7 +315,7 @@ public class OSXUtil implements ToolkitProperties { // otherwise we may freeze the OSX main thread. Throwable throwable = null; final Object sync = new Object(); - final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true ); + final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); synchronized(sync) { rt.setArgs(args); RunOnMainThread0(rt); @@ -349,6 +382,7 @@ public class OSXUtil implements ToolkitProperties { private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(Runnable runnable); + private static native void RunLater0(Runnable runnable, int delay); private static native boolean IsMainThread0(); private static native int GetScreenRefreshRate0(int scrn_idx); } diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index d902b0f09..a3c2a5dc8 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -43,9 +43,7 @@ import java.security.PrivilegedAction; import java.util.Set; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerOption; -import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.WindowClosingProtocol; import javax.swing.MenuSelectionManager; @@ -615,12 +613,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto configureNewtChild(false); newtChild.setVisible(false); - // Detach OLS early.. - final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(newtChild, true); - if(null != ols && ols.isSurfaceLayerAttached()) { - ols.detachSurfaceLayer(); - } - newtChild.reparentWindow(null); // will destroy context (offscreen -> onscreen) and implicit detachSurfaceLayer (if still attached) + newtChild.reparentWindow(null); // will destroy context (offscreen -> onscreen) and implicit detachSurfaceLayer if(DEBUG) { System.err.println("NewtCanvasAWT.detachNewtChild.X: win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()+", comp "+this); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java index 48c3c89b3..c2eebbfd8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove01GLCanvasSwingAWT.java @@ -55,13 +55,14 @@ import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { - static long durationPerTest = 50; + static long durationPerTest = 100; static int addRemoveCount = 15; static int pauseEach = 0; static int pauseDuration = 500; static boolean noOnscreenTest = false; static boolean noOffscreenTest = false; - static boolean shallUseOffscreenPBufferLayer = false; + static boolean offscreenPBufferOnly = false; + static boolean offscreenFBOOnly = false; static GLProfile glp; static int width, height; static boolean waitForKey = false; @@ -143,6 +144,9 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { throws AWTException, InterruptedException, InvocationTargetException { + if(waitForKey) { + UITestCase.waitForKey("Start"); + } for(int i=0; i<addRemoveOpCount; i++) { System.err.println("Loop # "+i+" / "+addRemoveCount); final GLCanvas glc = new GLCanvas(caps); @@ -195,29 +199,47 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { return; } GLCapabilities caps = new GLCapabilities(glp); - if(shallUseOffscreenPBufferLayer) { - caps.setPBuffer(true); - caps.setOnscreen(true); // simulate normal behavior .. - } runTestGL(true, caps, addRemoveCount); } @Test - public void test02Offscreen() + public void test02OffscreenFBO() throws AWTException, InterruptedException, InvocationTargetException { if( noOffscreenTest || !JAWTUtil.isOffscreenLayerSupported() ) { System.err.println("No offscreen test requested or platform doesn't support offscreen rendering."); return; } + if( offscreenPBufferOnly ) { + System.err.println("Only PBuffer test is requested."); + return; + } GLCapabilities caps = new GLCapabilities(glp); - if(shallUseOffscreenPBufferLayer) { + if(offscreenPBufferOnly) { caps.setPBuffer(true); caps.setOnscreen(true); // simulate normal behavior .. } runTestGL(false, caps, addRemoveCount); } + @Test + public void test03OffscreenPBuffer() + throws AWTException, InterruptedException, InvocationTargetException + { + if( noOffscreenTest || !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("No offscreen test requested or platform doesn't support offscreen rendering."); + return; + } + if( offscreenFBOOnly ) { + System.err.println("Only FBO test is requested."); + return; + } + GLCapabilities caps = new GLCapabilities(glp); + caps.setPBuffer(true); + caps.setOnscreen(true); // simulate normal behavior .. + runTestGL(false, caps, addRemoveCount); + } + public static void main(String args[]) throws IOException { for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { @@ -238,8 +260,10 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { noOnscreenTest = true; } else if(args[i].equals("-noOffscreen")) { noOffscreenTest = true; + } else if(args[i].equals("-layeredFBO")) { + offscreenFBOOnly = true; } else if(args[i].equals("-layeredPBuffer")) { - shallUseOffscreenPBufferLayer = true; + offscreenPBufferOnly = true; } else if(args[i].equals("-wait")) { waitForKey = true; } else if(args[i].equals("-waitPost")) { @@ -247,6 +271,7 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { } } System.err.println("waitForKey "+waitForKey); + System.err.println("waitForKeyPost "+waitForKeyPost); System.err.println("addRemoveCount "+addRemoveCount); System.err.println("pauseEach "+pauseEach); @@ -254,10 +279,9 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { System.err.println("noOnscreenTest "+noOnscreenTest); System.err.println("noOffscreenTest "+noOffscreenTest); - System.err.println("shallUseOffscreenPBufferLayer "+shallUseOffscreenPBufferLayer); - if(waitForKey) { - UITestCase.waitForKey("Start"); - } - org.junit.runner.JUnitCore.main(TestAddRemove01GLCanvasSwingAWT.class.getName()); + System.err.println("offscreenPBufferOnly "+offscreenPBufferOnly); + System.err.println("offscreenFBOOnly "+offscreenFBOOnly); + + org.junit.runner.JUnitCore.main(TestAddRemove01GLCanvasSwingAWT.class.getName()); } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove02GLWindowNewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove02GLWindowNewtCanvasAWT.java index ce88abfba..8b447485c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove02GLWindowNewtCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove02GLWindowNewtCanvasAWT.java @@ -63,10 +63,12 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { static int pauseDuration = 500; static boolean noOnscreenTest = false; static boolean noOffscreenTest = false; - static boolean shallUseOffscreenPBufferLayer = false; + static boolean offscreenPBufferOnly = false; + static boolean offscreenFBOOnly = false; static GLProfile glp; static int width, height; static boolean waitForKey = false; + static boolean waitForKeyPost = false; @BeforeClass public static void initClass() { @@ -183,6 +185,9 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { Thread.sleep(pauseDuration); } } + if(waitForKeyPost) { + UITestCase.waitForKey("End"); + } } @Test @@ -194,26 +199,40 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { return; } GLCapabilities caps = new GLCapabilities(glp); - if(shallUseOffscreenPBufferLayer) { - caps.setPBuffer(true); - caps.setOnscreen(true); // simulate normal behavior .. - } runTestGL(true, caps, addRemoveCount); } @Test - public void test02Offscreen() + public void test02OffscreenFBO() throws AWTException, InterruptedException, InvocationTargetException { if( noOffscreenTest || !JAWTUtil.isOffscreenLayerSupported() ) { System.err.println("No offscreen test requested or platform doesn't support offscreen rendering."); return; } + if( offscreenPBufferOnly ) { + System.err.println("Only PBuffer test is requested."); + return; + } GLCapabilities caps = new GLCapabilities(glp); - if(shallUseOffscreenPBufferLayer) { - caps.setPBuffer(true); - caps.setOnscreen(true); // simulate normal behavior .. + runTestGL(false, caps, addRemoveCount); + } + + @Test + public void test03OffscreenPBuffer() + throws AWTException, InterruptedException, InvocationTargetException + { + if( noOffscreenTest || !JAWTUtil.isOffscreenLayerSupported() ) { + System.err.println("No offscreen test requested or platform doesn't support offscreen rendering."); + return; } + if( offscreenFBOOnly ) { + System.err.println("Only FBO test is requested."); + return; + } + GLCapabilities caps = new GLCapabilities(glp); + caps.setPBuffer(true); + caps.setOnscreen(true); // simulate normal behavior .. runTestGL(false, caps, addRemoveCount); } @@ -237,13 +256,18 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { noOnscreenTest = true; } else if(args[i].equals("-noOffscreen")) { noOffscreenTest = true; + } else if(args[i].equals("-layeredFBO")) { + offscreenFBOOnly = true; } else if(args[i].equals("-layeredPBuffer")) { - shallUseOffscreenPBufferLayer = true; + offscreenPBufferOnly = true; } else if(args[i].equals("-wait")) { waitForKey = true; + } else if(args[i].equals("-waitPost")) { + waitForKeyPost = true; } } System.err.println("waitForKey "+waitForKey); + System.err.println("waitForKeyPost "+waitForKeyPost); System.err.println("addRemoveCount "+addRemoveCount); System.err.println("pauseEach "+pauseEach); @@ -251,7 +275,8 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { System.err.println("noOnscreenTest "+noOnscreenTest); System.err.println("noOffscreenTest "+noOffscreenTest); - System.err.println("shallUseOffscreenPBufferLayer "+shallUseOffscreenPBufferLayer); + System.err.println("offscreenPBufferOnly "+offscreenPBufferOnly); + System.err.println("offscreenFBOOnly "+offscreenFBOOnly); if(waitForKey) { UITestCase.waitForKey("Start"); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java b/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java index a6b3eb85d..d8a2e7810 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java @@ -155,7 +155,7 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { colorPanel.setBackground(Color.white); colorPanel.repaint(); }}); - + robot = new Robot(); robot.setAutoWaitForIdle(true); @@ -210,6 +210,8 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { AWTRobotUtil.toFrontAndRequestFocus(robot, frame); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(drawable, true)); + drawable.addGLEventListener(new GearsES2()); for(int i=0; i<100; i++) { @@ -262,6 +264,8 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { GLWindow win0 = GLWindow.create(caps); win0.setSize(100,100); win0.setVisible(true); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(win0, true)); + Screen screen = win0.getScreen(); win0.setPosition(screen.getWidth()-150, 0); win0.addGLEventListener(new GearsES2()); @@ -274,6 +278,7 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { runTestGL(newtCanvasAWT, win1); win0.destroy(); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(win0, false)); Assert.assertEquals(false, win0.isNativeValid()); Assert.assertEquals(true, anim.isAnimating()); // due to newtCanvasAWT/win1 @@ -313,8 +318,7 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { GLCanvas glCanvas = new GLCanvas(caps); anim.add(glCanvas); runTestGL(glCanvas, glCanvas); - - Assert.assertEquals(true, anim.isAnimating()); + anim.remove(glCanvas); Assert.assertEquals(false, anim.isAnimating()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting04AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting04AWT.java index b0e58b5ec..0af42ec03 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting04AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting04AWT.java @@ -159,6 +159,8 @@ public class TestParenting04AWT extends UITestCase { } canvas1.setNEWTChild(glWindow2); // put g2 -> w1. free g1 of w1 canvas2.setNEWTChild(glWindow1); // put g1 -> w2 + frame1.invalidate(); + frame2.invalidate(); frame1.validate(); frame2.validate(); } @@ -176,6 +178,8 @@ public class TestParenting04AWT extends UITestCase { } canvas1.setNEWTChild(glWindow1); canvas2.setNEWTChild(glWindow2); + frame1.invalidate(); + frame2.invalidate(); frame1.validate(); frame2.validate(); } |