diff options
author | Sven Gothel <[email protected]> | 2012-09-27 17:33:39 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-09-27 17:33:39 +0200 |
commit | fbe331f013608eb31ff0d8675f4e4c9881c9c48b (patch) | |
tree | 535aae61f299884ce6b61d026a60ed0546e9703b /src/test | |
parent | ba846a478d616327817dd530dbdcd9a786be5b7a (diff) |
Fix Bug 616: X11: Remove XInitThreads() dependency while cleaning up device locking, resulting in a native-lock-free impl.
The X11 implementation details of NativeWindow and NEWT used the X11 implicit locking facility
XLockDisplay/XUnlockDisplay, enabled via XInitThreads().
The latter useage is complicated within an unsure environment where the initialization point of JOGL
is unknown, but XInitThreads() requires to be called once and before any other X11 calls.
The solution is simple and thorough, replace native X11 locking w/ 'application level' locking.
Following this pattern actually cleans up a pretty messy part of X11 NativeWindow and NEWT,
since the generalization of platform independent locking simplifies code.
Simply using our RecursiveLock also speeds up locking, since it doesn't require JNI calls down to X11 anymore.
It allows us to get rid of X11ToolkitLock and X11JAWTToolkitLock.
Using the RecursiveLock also allows us to remove the shortcut of explicitly createing
a NullToolkitLocked device for 'private' display connections.
All devices use proper locking as claimed in their toolkit util 'requiresToolkitLock()' in X11Util, OSXUtil, ..
Further more a bug has been fixed of X11ErrorHandler usage, i.e. we need to keep our handler alive at all times
due to async X11 messaging behavior. This allows to remove the redundant code in X11/NEWT.
The AbstractGraphicsDevice lifecycle has been fixed as well, i.e. called when closing NEWT's Display
for all driver implementations.
On the NEWT side the Display's AbstractGraphicsDevice semantics has been clarified,
i.e. it's usage for EDT and lifecycle operations.
Hence the X11 Display 2nd device for rendering operations has been moved to X11 Window
where it belongs - and the X11 Display's default device used for EDT/lifecycle-ops as it should be.
This allows running X11/NEWT properly with the default usage, where the Display instance
and hence the EDT thread is shared with many Screen and Window.
Rendering using NEWT Window is decoupled from it's shared Display lock
via it's own native X11 display.
Lock free AbstractGraphicsDevice impl. (Windows, OSX, ..) don't require any attention in this regard
since they use NullToolkitLock.
Tests:
======
This implementation has been tested manually with Mesa3d (soft, Intel), ATI and Nvidia
on X11, Windows and OSX w/o any regressions found in any unit test.
Issues on ATI:
==============
Only on ATI w/o a composite renderer the unit tests expose a driver or WM bug where XCB
claims a lack of locking. Setting env. var 'LIBXCB_ALLOW_SLOPPY_LOCK=true' is one workaround
if users refuse to enable compositing. We may investigate this issue in more detail later on.
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java (renamed from src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java) | 84 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java | 78 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent02NEWT.java | 78 |
3 files changed, 190 insertions, 50 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java index 7127b0a5f..11d1331ed 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java @@ -28,8 +28,6 @@ package com.jogamp.opengl.test.junit.jogl.acore; -import java.io.IOException; - import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.opengl.GLCapabilities; @@ -37,17 +35,24 @@ import javax.media.opengl.GLProfile; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Test; -import com.jogamp.common.os.Platform; +import com.jogamp.newt.Display; import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; import com.jogamp.newt.Window; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; -public class TestInitConcurrentNEWT extends UITestCase { +/** + * Concurrent and lock-free initialization and rendering using exclusive NEWT Display EDT instances, or + * concurrent locked initialization and lock-free rendering using a shared NEWT Display EDT instances. + * <p> + * Rendering is always lock-free and independent of the EDT. + * </p> + */ +public class InitConcurrentBaseNEWT extends UITestCase { static final int demoSize = 128; @@ -73,20 +78,24 @@ public class TestInitConcurrentNEWT extends UITestCase { } public class JOGLTask implements Runnable { - private int id; - private Object postSync; + private final int id; + private final Object postSync; + private final boolean reuse; private boolean done = false; - public JOGLTask(Object postSync, int id) { + public JOGLTask(Object postSync, int id, boolean reuse) { this.postSync = postSync; this.id = id; + this.reuse = reuse; } public void run() { int x = ( id % num_x ) * ( demoSize + insets.getTotalHeight() ); int y = ( (id / num_x) % num_y ) * ( demoSize + insets.getTotalHeight() ); - System.err.println("JOGLTask "+id+": START: "+x+"/"+y+" - "+Thread.currentThread().getName()); - GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); + System.err.println("JOGLTask "+id+": START: "+x+"/"+y+", reuse "+reuse+" - "+Thread.currentThread().getName()); + final Display display = NewtFactory.createDisplay(null, reuse); + final Screen screen = NewtFactory.createScreen(display, 0); + final GLWindow glWindow = GLWindow.create(screen, new GLCapabilities(GLProfile.getDefault())); Assert.assertNotNull(glWindow); glWindow.setTitle("Task "+id); glWindow.setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight() ); @@ -98,6 +107,9 @@ public class TestInitConcurrentNEWT extends UITestCase { glWindow.setSize(demoSize, demoSize); glWindow.setVisible(true); animator.setUpdateFPSFrames(60, null); + + System.err.println("JOGLTask "+id+": INITIALIZED: "+", "+display+" - "+Thread.currentThread().getName()); + animator.start(); Assert.assertEquals(true, animator.isAnimating()); Assert.assertEquals(true, glWindow.isVisible()); @@ -169,67 +181,39 @@ public class TestInitConcurrentNEWT extends UITestCase { return sb.toString(); } - protected void runJOGLTasks(int num) throws InterruptedException { + protected void runJOGLTasks(int num, boolean reuse) throws InterruptedException { final String currentThreadName = Thread.currentThread().getName(); - final Object sync = new Object(); + final Object syncDone = new Object(); final JOGLTask[] tasks = new JOGLTask[num]; final Thread[] threads = new Thread[num]; int i; for(i=0; i<num; i++) { - tasks[i] = new JOGLTask(sync, i); + tasks[i] = new JOGLTask(syncDone, i, reuse); threads[i] = new Thread(tasks[i], currentThreadName+"-jt"+i); } + final long t0 = System.currentTimeMillis(); + for(i=0; i<num; i++) { threads[i].start(); } - synchronized (sync) { + synchronized (syncDone) { while(!done(tasks)) { try { - sync.wait(); + syncDone.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } + final long t1 = System.currentTimeMillis(); + System.err.println("total: "+(t1-t0)/1000.0+"s"); + Assert.assertTrue("Tasks are incomplete. Complete: "+doneDump(tasks), done(tasks)); i=0; while(i<30 && !isDead(threads)) { Thread.sleep(100); i++; } - Assert.assertTrue("Threads are still alive after 3s. Alive: "+isAliveDump(threads), isDead(threads)); - } - - @Test - public void test01OneThread() throws InterruptedException { - runJOGLTasks(1); - } - - @Test - public void test02TwoThreads() throws InterruptedException { - runJOGLTasks(2); - } - - @Test - public void test16SixteenThreads() throws InterruptedException { - if( Platform.getCPUFamily() == Platform.CPUFamily.ARM ) { - runJOGLTasks(8); - } else { - runJOGLTasks(16); - } - } - - public static void main(String args[]) throws IOException { - for(int i=0; i<args.length; i++) { - if(args[i].equals("-time")) { - i++; - try { - duration = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } - } - } - String tstname = TestInitConcurrentNEWT.class.getName(); - org.junit.runner.JUnitCore.main(tstname); - } - + Assert.assertTrue("Threads are still alive after 3s. Alive: "+isAliveDump(threads), isDead(threads)); + } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java new file mode 100644 index 000000000..e5ed8a79f --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java @@ -0,0 +1,78 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import org.junit.Test; + +import com.jogamp.common.os.Platform; + +/** + * Concurrent initialization and lock-free rendering using shared NEWT Display EDT instances. + * <p> + * Rendering is always lock-free and independent of the EDT, however shared NEWT Display instances + * perform lifecycle actions (window creation etc) with locking. + * </p> + */ +public class TestInitConcurrent01NEWT extends InitConcurrentBaseNEWT { + + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2, true); + } + + @Test + public void test02FourThreads() throws InterruptedException { + runJOGLTasks(4, true); + } + + @Test + public void test16SixteenThreads() throws InterruptedException { + if( Platform.getCPUFamily() != Platform.CPUFamily.ARM ) { + runJOGLTasks(16, true); + } else { + runJOGLTasks( 8, true); + } + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + String tstname = TestInitConcurrent01NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent02NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent02NEWT.java new file mode 100644 index 000000000..51e9af00e --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent02NEWT.java @@ -0,0 +1,78 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import org.junit.Test; + +import com.jogamp.common.os.Platform; + +/** + * Concurrent and lock-free initialization and rendering using exclusive NEWT Display EDT instances. + * <p> + * Rendering is always lock-free and independent of the EDT, however exclusive NEWT Display instances + * perform lifecycle actions (window creation etc) w/o locking. + * </p> + */ +public class TestInitConcurrent02NEWT extends InitConcurrentBaseNEWT { + + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2, false); + } + + @Test + public void test02FourThreads() throws InterruptedException { + runJOGLTasks(4, false); + } + + @Test + public void test16SixteenThreads() throws InterruptedException { + if( Platform.getCPUFamily() != Platform.CPUFamily.ARM ) { + runJOGLTasks(16, false); + } else { + runJOGLTasks( 8, false); + } + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + String tstname = TestInitConcurrent02NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} |