diff options
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(); } |