From f354fb204d8973453c538dda78a2c82c87be61dc Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Tue, 19 Mar 2013 00:22:28 +0100
Subject: 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.
---
src/jogl/classes/jogamp/opengl/GLContextImpl.java | 2 +-
.../classes/jogamp/opengl/GLDrawableHelper.java | 2 +-
.../jogamp/opengl/macosx/cgl/MacOSXCGLContext.java | 358 +++++++++++++--------
.../com/jogamp/nativewindow/awt/JAWTWindow.java | 73 ++---
.../media/nativewindow/OffscreenLayerSurface.java | 5 +
.../nativewindow/jawt/macosx/MacOSXJAWTWindow.java | 58 ++--
.../jawt/windows/WindowsJAWTWindow.java | 7 -
.../nativewindow/jawt/x11/X11JAWTWindow.java | 7 -
.../jogamp/nativewindow/macosx/OSXUtil.java | 64 +++-
.../classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 9 +-
.../acore/TestAddRemove01GLCanvasSwingAWT.java | 52 ++-
.../TestAddRemove02GLWindowNewtCanvasAWT.java | 47 ++-
...TestSwingAWTRobotUsageBeforeJOGLInitBug411.java | 10 +-
.../junit/newt/parenting/TestParenting04AWT.java | 4 +
14 files changed, 439 insertions(+), 259 deletions(-)
(limited to 'src')
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 {
* make context current, if it was current
*
*
- * No locking is being performed, caller is required to take care of it.
+ * Locking is performed via {@link GLContext#makeCurrent()} on the passed context
.
*
*
* @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.
+ *
+ * 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.
+ *
+ *
+ * Hence this method blocks the main-thread only for a short period of time.
+ *
+ */
+ 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.
*
* @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 true
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 true
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 NOP 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 rt = new FunctionTask( func, waitUntilDone ? sync : null, true );
+ final FunctionTask rt = new FunctionTask( 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 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();
}
--
cgit v1.2.3