From 28c6472335b924080d638b33a28f8f4eedb459b1 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 15 Mar 2013 19:08:22 +0100 Subject: Remodel OSX/CALayer Threading (commit 896e8b021b39e9415040a57a1d540d7d24b02db1): Run on main-thread w/o blocking ; Misc Changes Commit 896e8b021b39e9415040a57a1d540d7d24b02db1 moved all native CALayer calls to the current thread to avoid deadlocks. Even though this seemed to be fine at least resource GC (release/dealloc calls) were issued very late in time, probably due to multithreading synchronization of JAWT and/or OSX API. Example: Our 'TestAddRemove01GLCanvasSwingAWT' test didn't freed CALayer resources incl. GL ctx when destroying the objects (AWT Frame, GLCanvas, ..), leading to resource starvation .. eventually. Remedy is a compromise of behavior before commit 896e8b021b39e9415040a57a1d540d7d24b02db1 and that commit, i.e. to run CALayer lifecycle methods on main-thread, but do not block! The careful part within MacOSXCGLContext.associateDrawable(..) performs the following block on main-thread: - lock the context - create NSOpenGLLayer (incl. it's own shared GL context and the DisplayLink) - attach NSOpenGLLayer to root CALayer - unlock the context Due to the GL ctx locking, this async offthread operation is safe within our course of operations. Details: - NSOpenGLContext - Context and CVDisplayLink creation at init - Call [ctx update] if texture/frame size changed - 'waitUntilRenderSignal' uses default TO value if given TO is 0 to avoid deadlocks +++ Misc Changes: - Fix object type detection: isMemberOfClass -> isKindOfClass - OSXUtil_isNSView0 OSXUtil_isNSWindow0, CGL_isNSOpenGLPixelBuffer - MacOSXCGLDrawable/MacOSXPbufferCGLDrawable: remove getNSViewHandle() method. MacOSXCGLContext uses common code to detect nature of the drawable handle. - MacOSXCGLContext/CALayer: Use safe screenVSyncTimeout values, never 0 to avoid deadlock! - JAWTWindow.invalidate: Call detachSurfaceLayer() if not done yet --- .../acore/TestAddRemove01GLCanvasSwingAWT.java | 32 ++++++++++++++++++---- .../TestAddRemove02GLWindowNewtCanvasAWT.java | 20 ++++++++++++-- .../jogl/acore/TestAddRemove03GLWindowNEWT.java | 20 ++++++++++++-- ...TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java | 9 ++++++ .../jogl/demos/es2/newt/TestGearsES2NEWT.java | 14 ++-------- 5 files changed, 72 insertions(+), 23 deletions(-) (limited to 'src/test/com/jogamp/opengl') 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 ce8f9adc8..48c3c89b3 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 @@ -51,17 +51,21 @@ import org.junit.BeforeClass; import org.junit.Test; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +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 int addRemoveCount = 15; + static int pauseEach = 0; + static int pauseDuration = 500; static boolean noOnscreenTest = false; static boolean noOffscreenTest = false; static boolean shallUseOffscreenPBufferLayer = false; static GLProfile glp; static int width, height; static boolean waitForKey = false; + static boolean waitForKeyPost = false; @BeforeClass public static void initClass() { @@ -167,9 +171,19 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { } while ( ( System.currentTimeMillis() - t0 ) < durationPerTest ) ; System.err.println("GLCanvas isOffscreenLayerSurfaceEnabled: "+glc.isOffscreenLayerSurfaceEnabled()+": "+glc.getChosenGLCapabilities()); + + dispose(top[0]); - dispose(top[0]); + if( 0 < pauseEach && 0 == i % pauseEach ) { + System.err.println("******* P A U S E - Start ********"); + // OSXUtil.WaitUntilFinish(); + Thread.sleep(pauseDuration); + System.err.println("******* P A U S E - End ********"); + } } + if(waitForKeyPost) { + UITestCase.waitForKey("End"); + } } @Test @@ -213,9 +227,13 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { } catch (Exception ex) { ex.printStackTrace(); } } else if(args[i].equals("-loops")) { i++; - try { - addRemoveCount = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } + addRemoveCount = MiscUtils.atoi(args[i], addRemoveCount); + } else if(args[i].equals("-pauseEach")) { + i++; + pauseEach = MiscUtils.atoi(args[i], pauseEach); + } else if(args[i].equals("-pauseDuration")) { + i++; + pauseDuration = MiscUtils.atoi(args[i], pauseDuration); } else if(args[i].equals("-noOnscreen")) { noOnscreenTest = true; } else if(args[i].equals("-noOffscreen")) { @@ -224,11 +242,15 @@ public class TestAddRemove01GLCanvasSwingAWT extends UITestCase { shallUseOffscreenPBufferLayer = 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("addRemoveCount "+addRemoveCount); + System.err.println("pauseEach "+pauseEach); + System.err.println("pauseDuration "+pauseDuration); System.err.println("noOnscreenTest "+noOnscreenTest); System.err.println("noOffscreenTest "+noOffscreenTest); 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 3d78943f9..ce88abfba 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 @@ -53,11 +53,14 @@ import org.junit.Test; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { static long durationPerTest = 50; static int addRemoveCount = 15; + static int pauseEach = 0; + static int pauseDuration = 500; static boolean noOnscreenTest = false; static boolean noOffscreenTest = false; static boolean shallUseOffscreenPBufferLayer = false; @@ -174,6 +177,11 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { dispose(top[0]); glw.destroy(); + + if( 0 < pauseEach && 0 == i % pauseEach ) { + System.err.println("******* P A U S E ********"); + Thread.sleep(pauseDuration); + } } } @@ -218,9 +226,13 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { } catch (Exception ex) { ex.printStackTrace(); } } else if(args[i].equals("-loops")) { i++; - try { - addRemoveCount = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } + addRemoveCount = MiscUtils.atoi(args[i], addRemoveCount); + } else if(args[i].equals("-pauseEach")) { + i++; + pauseEach = MiscUtils.atoi(args[i], pauseEach); + } else if(args[i].equals("-pauseDuration")) { + i++; + pauseDuration = MiscUtils.atoi(args[i], pauseDuration); } else if(args[i].equals("-noOnscreen")) { noOnscreenTest = true; } else if(args[i].equals("-noOffscreen")) { @@ -234,6 +246,8 @@ public class TestAddRemove02GLWindowNewtCanvasAWT extends UITestCase { System.err.println("waitForKey "+waitForKey); System.err.println("addRemoveCount "+addRemoveCount); + System.err.println("pauseEach "+pauseEach); + System.err.println("pauseDuration "+pauseDuration); System.err.println("noOnscreenTest "+noOnscreenTest); System.err.println("noOffscreenTest "+noOffscreenTest); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove03GLWindowNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove03GLWindowNEWT.java index 9d7a4026b..981b14af3 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove03GLWindowNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestAddRemove03GLWindowNEWT.java @@ -41,11 +41,14 @@ import org.junit.Test; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; public class TestAddRemove03GLWindowNEWT extends UITestCase { static long durationPerTest = 50; static int addRemoveCount = 15; + static int pauseEach = 0; + static int pauseDuration = 500; static GLProfile glp; static int width, height; static boolean waitForKey = false; @@ -91,6 +94,11 @@ public class TestAddRemove03GLWindowNEWT extends UITestCase { System.err.println("GLWindow: "+glw.getChosenGLCapabilities()); glw.destroy(); + + if( 0 < pauseEach && 0 == i % pauseEach ) { + System.err.println("******* P A U S E ********"); + Thread.sleep(pauseDuration); + } } } @@ -111,9 +119,13 @@ public class TestAddRemove03GLWindowNEWT extends UITestCase { } catch (Exception ex) { ex.printStackTrace(); } } else if(args[i].equals("-loops")) { i++; - try { - addRemoveCount = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } + addRemoveCount = MiscUtils.atoi(args[i], addRemoveCount); + } else if(args[i].equals("-pauseEach")) { + i++; + pauseEach = MiscUtils.atoi(args[i], pauseEach); + } else if(args[i].equals("-pauseDuration")) { + i++; + pauseDuration = MiscUtils.atoi(args[i], pauseDuration); } else if(args[i].equals("-wait")) { waitForKey = true; } @@ -121,6 +133,8 @@ public class TestAddRemove03GLWindowNEWT extends UITestCase { System.err.println("waitForKey "+waitForKey); System.err.println("addRemoveCount "+addRemoveCount); + System.err.println("pauseEach "+pauseEach); + System.err.println("pauseDuration "+pauseDuration); if(waitForKey) { UITestCase.waitForKey("Start"); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java index 0673e2f45..0b70cf151 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java @@ -64,6 +64,7 @@ import com.jogamp.opengl.test.junit.util.UITestCase; public class TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT extends UITestCase { static final int widthStep = 800/4; static final int heightStep = 600/4; + static boolean waitForKey = false; volatile int szStep = 2; static GLCapabilities getCaps(String profile) { @@ -331,6 +332,14 @@ public class TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT extends UITestCase { } public static void main(String args[]) throws IOException { + for(int i=0; i