From dfee8c58d4915f78f57545c26a492668b2b68a87 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 6 Jul 2012 08:57:57 +0200 Subject: Fix SWT GLCanvas threading. Note: On OSX _only_ it's main thread is valid! --- .../classes/com/jogamp/opengl/swt/GLCanvas.java | 99 +++++----------------- .../com/jogamp/nativewindow/swt/SWTAccessor.java | 21 ++++- .../jogamp/nativewindow/macosx/OSXUtil.java | 22 +++++ .../test/junit/jogl/swt/TestSWTAccessor02GLn.java | 29 +++---- .../junit/jogl/swt/TestSWTAccessor03AWTGLn.java | 6 +- .../jogl/swt/TestSWTEclipseGLCanvas01GLn.java | 29 ++++--- .../junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java | 52 ++++++++---- 7 files changed, 132 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 571f5c5b2..5ee58b78d 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -47,7 +47,6 @@ import javax.media.opengl.Threading; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableHelper; -import jogamp.opengl.ThreadingImpl; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; @@ -62,6 +61,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.VersionUtil; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.opengl.JoglVersion; @@ -69,10 +69,6 @@ import com.jogamp.opengl.JoglVersion; /** * Native SWT Canvas implementing GLAutoDrawable *

- * FIXME: Still needs AWT for threading impl., - * ie. will issue a 'wrong thread' error if runs in headless mode! - *

- *

* FIXME: If this instance runs in multithreading mode, see {@link Threading#isSingleThreaded()} (impossible), * proper recursive locking is required for drawable/context @ destroy and display. * Recreation etc could pull those instances while animating! @@ -86,12 +82,6 @@ import com.jogamp.opengl.JoglVersion; However, since the user shall stick to the GLEventListener model while utilizing GLAutoDrawable implementations, she is safe due to the implicit locked state. *

- *

- * FIXME: [MT-2] Revise threading code - The logic whether to spawn off the GL task and - determination which thread to use is too complex and redundant. - (See isRenderThread(), runInGLThread() and runInDesignatedGLThread()) - *

*/ public class GLCanvas extends Canvas implements GLAutoDrawable { @@ -307,7 +297,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void display() { - runInGLThread(makeCurrentAndDisplayAction, displayAction); + runInGLThread(makeCurrentAndDisplayAction); } @Override @@ -458,7 +448,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void swapBuffers() throws GLException { - runInGLThread(makeCurrentAndSwapBuffersAction, swapBuffersAction); + runInGLThread(makeCurrentAndSwapBuffersAction); } // FIXME: API of update() method ? @@ -478,11 +468,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } if(context.isCreated()) { - if (Threading.isSingleThreaded() && !Threading.isOpenGLThread()) { - runInDesignatedGLThread(disposeOnEDTGLAction); - } else if (context.isCreated()) { - helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); - } + runInGLThread(disposeOnEDTGLAction); } if (animatorPaused) { @@ -500,70 +486,29 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } /** - * Determines whether the current thread is the appropriate thread to use the GLContext in. If we are using one of - * the single-threaded policies in {@link Threading}, than this is either the SWT event dispatch thread, or the - * OpenGL worker thread depending on the state of {@link #useSWTThread}. Otherwise this always returns true because - * the threading model is user defined. - *

- * FIXME: Redundant .. remove! Merge isRenderThread, runInGLThread and runInDesignatedGLThread - * - * @return true if the calling thread is the correct thread to execute OpenGL calls in, false otherwise. - */ - protected boolean isRenderThread() { - if (Threading.isSingleThreaded()) { - if (ThreadingImpl.getMode() != ThreadingImpl.Mode.ST_WORKER) { - final Display display = getDisplay(); - return display != null && display.getThread() == Thread.currentThread(); - } - return Threading.isOpenGLThread(); - } - /* - * For multi-threaded rendering, the render thread is not defined... - */ - return true; - } - - /** - * Runs the specified action in the designated OpenGL thread. If the current thread is designated, then the - * syncAction is run synchronously, otherwise the asyncAction is dispatched to the appropriate worker thread. - * - * @param asyncAction - * The non-null action to dispatch to an OpenGL worker thread. This action should not assume that a - * GLContext is current when invoked. - * @param syncAction - * The non-null action to run synchronously if the current thread is designated to handle OpenGL calls. - * This action may assume the GLContext is current. - * FIXME: Redundant .. remove! Merge isRenderThread, runInGLThread and runInDesignatedGLThread + * Runs the specified action in an SWT compatible thread, which is: + *

+ * @see Platform#AWT_AVAILABLE + * @see Platform#getOSType() */ - private void runInGLThread(final Runnable asyncAction, final Runnable syncAction) { - if (Threading.isSingleThreaded() && !isRenderThread()) { - /* Run in designated GL thread */ - runInDesignatedGLThread(asyncAction); + private void runInGLThread(final Runnable action) { + if(Platform.OSType.MACOS == Platform.OS_TYPE) { + SWTAccessor.invoke(true, action); } else { - /* Run in current thread... */ - helper.invokeGL(drawable, context, syncAction, initAction); + Threading.invokeOnOpenGLThread(true, action); } } - /** - * Dispatches the specified runnable to the appropriate OpenGL worker thread (either the SWT event dispatch thread, - * or the OpenGL worker thread depending on the state of {@link #useSWTThread}). - * - * @param makeCurrentAndRunAction - * The non-null action to dispatch. - * FIXME: Redundant .. remove! Merge isRenderThread, runInGLThread and runInDesignatedGLThread - */ - private void runInDesignatedGLThread(final Runnable makeCurrentAndRunAction) { - if (ThreadingImpl.getMode() != ThreadingImpl.Mode.ST_WORKER) { - final Display display = getDisplay(); - assert display.getThread() != Thread.currentThread() : "Incorrect use of thread dispatching."; - display.syncExec(makeCurrentAndRunAction); - } else { - Threading.invokeOnOpenGLThread(true, makeCurrentAndRunAction); - } - } - - public static void main(final String[] args) { System.err.println(VersionUtil.getPlatformInfo()); System.err.println(GlueGenVersion.getInstance()); diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java index f4309617b..735d85fb1 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -37,11 +37,13 @@ import org.eclipse.swt.widgets.Control; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowFactory; + import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import jogamp.common.awt.AWTEDTExecutor; import jogamp.nativewindow.macosx.OSXUtil; public class SWTAccessor { @@ -254,8 +256,25 @@ public class SWTAccessor { }); } + /** + * Runs the specified action in an SWT compatible thread, which is: + * + * @see Platform#AWT_AVAILABLE + * @see Platform#getOSType() + */ public static void invoke(boolean wait, Runnable runnable) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { + if( Platform.OS_TYPE == Platform.OSType.MACOS ) { + // Use SWT main thread! Only reliable config w/ -XStartOnMainThread !? OSXUtil.RunOnMainThread(wait, runnable); } else { runnable.run(); diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 94f949ea3..2cd87f276 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -30,6 +30,7 @@ package jogamp.nativewindow.macosx; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; +import jogamp.common.awt.AWTEDTExecutor; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; @@ -111,6 +112,27 @@ public class OSXUtil { return IsMainThread0(); } + /*** + private static boolean isAWTEDTMainThreadInit = false; + private static boolean isAWTEDTMainThread; + + public synchronized static boolean isAWTEDTMainThread() { + if(!isAWTEDTMainThreadInit) { + isAWTEDTMainThreadInit = true; + if(Platform.AWT_AVAILABLE) { + AWTEDTExecutor.singleton.invoke(true, new Runnable() { + public void run() { + isAWTEDTMainThread = IsMainThread(); + System.err.println("XXX: "+Thread.currentThread().getName()+" - isAWTEDTMainThread "+isAWTEDTMainThread); + } + }); + } else { + isAWTEDTMainThread = false; + } + } + return isAWTEDTMainThread; + } */ + private static native boolean initIDs0(); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); private static native long CreateNSView0(int x, int y, int width, int height); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor02GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor02GLn.java index 0c350255e..2121205e2 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor02GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor02GLn.java @@ -85,26 +85,17 @@ public class TestSWTAccessor02GLn extends UITestCase { @Before public void init() { - final Display[] r = new Display[1]; - final Shell[] s = new Shell[1]; SWTAccessor.invoke(true, new Runnable() { - public void run() { - r[0] = new Display(); - s[0] = new Shell(); - } - }); - display = r[0]; - shell = s[0]; - Assert.assertNotNull( display ); - Assert.assertNotNull( shell ); - - SWTAccessor.invoke(true, new Runnable() { - public void run() { - shell.setLayout( new FillLayout() ); - composite = new Composite( shell, SWT.NONE ); - Assert.assertNotNull( composite ); - composite.setLayout( new FillLayout() ); - }}); + public void run() { + display = new Display(); + Assert.assertNotNull( display ); + shell = new Shell( display ); + Assert.assertNotNull( shell ); + shell.setLayout( new FillLayout() ); + composite = new Composite( shell, SWT.NONE ); + composite.setLayout( new FillLayout() ); + Assert.assertNotNull( composite ); + }}); } @After diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor03AWTGLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor03AWTGLn.java index 966b39c57..ad8da8ad0 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor03AWTGLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAccessor03AWTGLn.java @@ -75,7 +75,11 @@ public class TestSWTAccessor03AWTGLn extends UITestCase { @BeforeClass public static void startup() { - System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() ); + System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() ); + Frame f0 = new Frame("Test - AWT 1st"); + f0.add(new java.awt.Label("AWT was here 1st")); + f0.pack(); + f0.setVisible(true); if(!GLProfile.isAvailable(GLProfile.GL2)) { setTestSupported(false); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTEclipseGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTEclipseGLCanvas01GLn.java index f38d5c7dc..0bd47c980 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTEclipseGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTEclipseGLCanvas01GLn.java @@ -53,6 +53,7 @@ import org.junit.BeforeClass; import org.junit.After; import org.junit.Test; +import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.opengl.test.junit.jogl.demos.es1.OneTriangle; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -81,14 +82,17 @@ public class TestSWTEclipseGLCanvas01GLn extends UITestCase { @Before public void init() { - display = new Display(); - Assert.assertNotNull( display ); - shell = new Shell( display ); - Assert.assertNotNull( shell ); - shell.setLayout( new FillLayout() ); - composite = new Composite( shell, SWT.NONE ); - composite.setLayout( new FillLayout() ); - Assert.assertNotNull( composite ); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display = new Display(); + Assert.assertNotNull( display ); + shell = new Shell( display ); + Assert.assertNotNull( shell ); + shell.setLayout( new FillLayout() ); + composite = new Composite( shell, SWT.NONE ); + composite.setLayout( new FillLayout() ); + Assert.assertNotNull( composite ); + }}); } @After @@ -97,9 +101,12 @@ public class TestSWTEclipseGLCanvas01GLn extends UITestCase { Assert.assertNotNull( shell ); Assert.assertNotNull( composite ); try { - composite.dispose(); - shell.dispose(); - display.dispose(); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + composite.dispose(); + shell.dispose(); + display.dispose(); + }}); } catch( Throwable throwable ) { throwable.printStackTrace(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java index addb14ce5..ba33aa31d 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java @@ -34,6 +34,8 @@ import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.macosx.OSXUtil; + import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; @@ -47,6 +49,8 @@ import org.junit.BeforeClass; import org.junit.After; import org.junit.Test; +import com.jogamp.common.os.Platform; +import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.opengl.swt.GLCanvas; import com.jogamp.opengl.test.junit.jogl.demos.es1.OneTriangle; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -57,10 +61,10 @@ import com.jogamp.opengl.test.junit.util.UITestCase; * Uses JOGL's new SWT GLCanvas. *

*

- * Holds AWT in it's test name, since our impl. still needs the AWT threading, - * see {@link GLCanvas}. + * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ + * SWT running on Mac OSX, i.e. to enforce UI action on the main thread. *

- * @author Wade Walker, et.al. + * @author Wade Walker, et al. */ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { @@ -76,18 +80,24 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { @BeforeClass public static void startup() { System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() ); + if( Platform.OS_TYPE == Platform.OSType.MACOS ) { + System.err.println("OSXUtil.isAWTEDTMainThread: "+ OSXUtil.isAWTEDTMainThread() ); + } } @Before public void init() { - display = new Display(); - Assert.assertNotNull( display ); - shell = new Shell( display ); - Assert.assertNotNull( shell ); - shell.setLayout( new FillLayout() ); - composite = new Composite( shell, SWT.NONE ); - composite.setLayout( new FillLayout() ); - Assert.assertNotNull( composite ); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + display = new Display(); + Assert.assertNotNull( display ); + shell = new Shell( display ); + Assert.assertNotNull( shell ); + shell.setLayout( new FillLayout() ); + composite = new Composite( shell, SWT.NONE ); + composite.setLayout( new FillLayout() ); + Assert.assertNotNull( composite ); + }}); } @After @@ -96,9 +106,12 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { Assert.assertNotNull( shell ); Assert.assertNotNull( composite ); try { - composite.dispose(); - shell.dispose(); - display.dispose(); + SWTAccessor.invoke(true, new Runnable() { + public void run() { + composite.dispose(); + shell.dispose(); + display.dispose(); + }}); } catch( Throwable throwable ) { throwable.printStackTrace(); @@ -118,14 +131,19 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { Assert.assertNotNull( canvas ); canvas.addGLEventListener(new GLEventListener() { - public void init(final GLAutoDrawable drawable) { } + public void init(final GLAutoDrawable drawable) { + System.err.println(Thread.currentThread().getName()+" - SWT Canvas - GLEventListener - init()"); + } public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { - OneTriangle.setup( drawable.getGL().getGL2(), width, height ); + System.err.println(Thread.currentThread().getName()+" - SWT Canvas - GLEventListener - reshape()"); + OneTriangle.setup( drawable.getGL().getGL2(), width, height ); } public void display(final GLAutoDrawable drawable) { OneTriangle.render( drawable.getGL().getGL2(), drawable.getWidth(), drawable.getHeight()); } - public void dispose(final GLAutoDrawable drawable) {} + public void dispose(final GLAutoDrawable drawable) { + System.err.println(Thread.currentThread().getName()+" - SWT Canvas - GLEventListener - dispose()"); + } }); shell.setText( getClass().getName() ); -- cgit v1.2.3