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 | |
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.
38 files changed, 701 insertions, 623 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 8a0a638ba..3dc983072 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -81,6 +81,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.TraceGL -Djogl.debug.DebugGL -Djogl.debug.GLSLCode -Djogl.debug.GLSLState" #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.DebugGL -Djogl.debug.TraceGL" #D_ARGS="-Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.UseCurrentThreadLibLoader" + #D_ARGS="-Djogamp.debug.NativeLibrary" #D_ARGS="-Djogl.1thread=false -Djogl.debug.Threading" #D_ARGS="-Djogl.1thread=true -Djogl.debug.Threading" #D_ARGS="-Djogl.debug.DebugGL -Djogl.debug.TraceGL -Djogl.debug.GLContext.TraceSwitch -Djogl.debug=all" @@ -100,7 +101,6 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile -Djogl.debug.GLDrawable" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile" #D_ARGS="-Djogl.debug.GLProfile" - #D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" #D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window -Djogl.debug.GLContext" @@ -109,6 +109,7 @@ function jrun() { #D_ARGS="-Dnativewindow.debug.X11Util -Dnativewindow.debug.X11Util.XSync" #D_ARGS="-Dnativewindow.debug.X11Util.XSync -Dnewt.debug.Window" #D_ARGS="-Djogl.debug.GLDrawable -Djogl.debug.GLContext" + #D_ARGS="-Dnativewindow.debug.NativeWindow -Dnativewindow.debug.X11Util" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=3000 -Djogamp.debug.Lock -Djogl.debug.GLContext.TraceSwitch" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=600000 -Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock" #D_ARGS="-Djogamp.common.utils.locks.Lock.timeout=600000 -Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock -Dnativewindow.debug.ToolkitLock.TraceLock" @@ -135,7 +136,9 @@ function jrun() { #D_ARGS="-Djogl.debug.Animator" #D_ARGS="-Dnativewindow.debug=all" #D_ARGS="-Djogl.debug.GLCanvas" - #D_ARGS="-Dnativewindow.debug.ToolkitLock.TraceLock" + #D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.X11Util.XSync" + #D_ARGS="-Dnativewindow.debug.X11Util.XSync" + #D_ARGS="-Dnativewindow.debug.ToolkitLock" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLCode -Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.graph.curve -Djogl.debug.GLSLState" #D_ARGS="-Djogamp.debug.JNILibLoader -Djogamp.debug.TempJarCache -Djogamp.debug.JarUtil" @@ -187,6 +190,8 @@ function jrun() { #export LD_LIBRARY_PATH=/opt-linux-x86_64/mesa-7.8.1/lib64:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=/usr/lib/mesa:/usr/lib32/mesa:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/mesa:/usr/lib/i386-linux-gnu/mesa:$LD_LIBRARY_PATH + #export LD_LIBRARY_PATH=`pwd`/lib/external/mesa/x86_64-linux-gnu:$LD_LIBRARY_PATH + #export LD_LIBRARY_PATH=`pwd`/lib/external/mesa/x86_64-linux-gnu/gallium:$LD_LIBRARY_PATH echo echo "Test Start: $*" echo @@ -194,10 +199,10 @@ function jrun() { echo echo $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* #LIBGL_DRIVERS_PATH=/usr/lib/mesa:/usr/lib32/mesa \ - #gdb --args $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* #LIBGL_DEBUG=verbose INTEL_STRICT_CONFORMANCE=1 INTEL_DEBUG="buf bat" \ #LIBGL_DEBUG=verbose MESA_DEBUG=true INTEL_STRICT_CONFORMANCE=1 \ - #LIBGL_DEBUG=verbose MESA_DEBUG=true LIBGL_ALWAYS_SOFTWARE=true \ + #export LIBGL_DEBUG=verbose MESA_DEBUG=true LIBGL_ALWAYS_SOFTWARE=true + #gdb --args $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* $javaexe $javaxargs $X_ARGS $D_ARGS $C_ARG $* echo echo "Test End: $*" @@ -239,7 +244,8 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile01NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestShutdownCompleteNEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrentNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextSurfaceLockNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug01NEWT $* @@ -250,6 +256,38 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLContextDrawableSwitchNEWT $* +# x11 no XinitThreads() specific tests (regressions, concurrent behavior) ! +# Deadlock: +# com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 - test01 +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* +# com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT - testEachWithAnimatorSharedOffscreen +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT $* +# +# XCB: +# +# com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT - testShaderState01PerformanceDouble +#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLShaderState02NEWT $* +# com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT - testWindowParenting02ReparentTop2WinReparentRecreate +#testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $* +# com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT - winHopFrame2FrameDirectHop +#testawtswt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* + +#testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT +#testnoawt com.jogamp.opengl.test.junit.newt.TestWindows01NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent01NEWT $* +testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestInitConcurrent02NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOMix2DemosES2NEWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting04AWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.TestRemoteGLWindows01NEWT $* +#testswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTEclipseGLCanvas01GLn $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextListNEWT2 $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOffThreadSharedContextMix2DemosES2NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestFBOOnThreadSharedContext1DemoES2NEWT $* + + #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateOnOffscrnCapsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT $* @@ -322,7 +360,7 @@ function testawtswt() { #testawt com.jogamp.opengl.test.junit.jogl.awt.TestAWT02WindowClosing #testawt com.jogamp.opengl.test.junit.jogl.awt.text.TestAWTTextRendererUseVertexArrayBug464 #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT $* -testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* +#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWTAnalyzeBug455 $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWTBug450 $* diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index ce2e824f5..0a603ab8a 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -71,10 +71,9 @@ public class EGLDisplayUtil { Thread.dumpStack(); } if( eglDisplayCounter.size() > 0) { - EGLDisplayUtil.dumpOpenDisplayConnections(); + dumpOpenDisplayConnections(); } } - return eglDisplayCounter.size(); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index e1e25be67..bdccc1047 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -172,7 +172,6 @@ public abstract class X11GLXContext extends GLContextImpl { glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, ctx); } - private static final int ctx_arb_attribs_idx_major = 0; private static final int ctx_arb_attribs_idx_minor = 2; private static final int ctx_arb_attribs_idx_flags = 6; @@ -228,14 +227,14 @@ public abstract class X11GLXContext extends GLContextImpl { X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); - long display = device.getHandle(); + final long display = device.getHandle(); try { // critical path, a remote display might not support this command, // hence we need to catch the X11 Error within this block. - X11Lib.XSync(display, false); + X11Util.setX11ErrorHandler(true, DEBUG ? false : true); // make sure X11 error handler is set ctx = _glXExt.glXCreateContextAttribsARB(display, config.getFBConfig(), share, direct, attribs); - X11Lib.XSync(display, false); + if(DEBUG) { X11Lib.XSync(display, false); } } catch (RuntimeException re) { if(DEBUG) { Throwable t = new Throwable(getThreadName()+": Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); @@ -263,16 +262,6 @@ public abstract class X11GLXContext extends GLContextImpl { @Override protected boolean createImpl(GLContextImpl shareWith) { - // covers the whole context creation loop incl createContextARBImpl and destroyContextARBImpl - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - return createImplRaw(shareWith); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - } - - private boolean createImplRaw(GLContextImpl shareWith) { boolean direct = true; // try direct always isDirect = false; // fall back @@ -401,14 +390,9 @@ public abstract class X11GLXContext extends GLContextImpl { protected void makeCurrentImpl() throws GLException { long dpy = drawable.getNativeSurface().getDisplayHandle(); - if (GLX.glXGetCurrentContext() != contextHandle) { - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - if (!glXMakeContextCurrent(dpy, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { - throw new GLException(getThreadName()+": Error making context current: "+this); - } - } finally { - X11Util.setX11ErrorHandler(false, false); + if (GLX.glXGetCurrentContext() != contextHandle) { + if (!glXMakeContextCurrent(dpy, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { + throw new GLException(getThreadName()+": Error making context current: "+this); } } } @@ -416,13 +400,8 @@ public abstract class X11GLXContext extends GLContextImpl { @Override protected void releaseImpl() throws GLException { long display = drawable.getNativeSurface().getDisplayHandle(); - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - if (!glXMakeContextCurrent(display, 0, 0, 0)) { - throw new GLException(getThreadName()+": Error freeing OpenGL context"); - } - } finally { - X11Util.setX11ErrorHandler(false, false); + if (!glXMakeContextCurrent(display, 0, 0, 0)) { + throw new GLException(getThreadName()+": Error freeing OpenGL context"); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index ca5cd424b..03c661565 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -47,7 +47,6 @@ import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeSurface; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.nativewindow.VisualIDHolder; @@ -230,11 +229,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @Override public SharedResourceRunner.Resource createSharedResource(String connection) { - final X11GraphicsDevice sharedDevice = - new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, - true); // own non-shared display connection, w/ locking - // new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, - // NativeWindowFactory.getNullToolkitLock(), true); // own non-shared display connection, w/o locking + final X11GraphicsDevice sharedDevice = new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, true); sharedDevice.lock(); try { final X11GraphicsScreen sharedScreen = new X11GraphicsScreen(sharedDevice, sharedDevice.getDefaultScreen()); @@ -509,8 +504,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final X11GraphicsDevice device; if(createNewDevice) { - // Null X11 locking, due to private non-shared Display handle - device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), NativeWindowFactory.getNullToolkitLock(), true); + // Null X11 resource locking, due to private non-shared Display handle + device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), true); } else { device = (X11GraphicsDevice)deviceReq; } @@ -531,7 +526,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @Override protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { - final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), NativeWindowFactory.getNullToolkitLock(), true); + final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), true); final X11GraphicsScreen screen = new X11GraphicsScreen(device, screenIdx); final int xvisualID = X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); if(VisualIDHolder.VID_UNDEFINED == xvisualID) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 152384980..2e4099c1b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -73,7 +73,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl /** * @param display the Display connection - * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking w/ private connection * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) */ public X11GraphicsDevice(long display, int unitID, ToolkitLock locker, boolean owner) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java index 5f3c220ca..7ab5bd6aa 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java @@ -63,7 +63,7 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl private static int fetchScreen(X11GraphicsDevice device, int screen) { // It still could be an AWT hold handle .. - if(X11Util.XineramaIsEnabled(device.getHandle())) { + if(X11Util.XineramaIsEnabled(device)) { screen = 0; // Xinerama -> 1 screen } return screen; diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 756e4451b..5eaaa6613 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -131,7 +131,7 @@ public interface AbstractGraphicsDevice extends Cloneable { /** * Optionally closing the device if handle is not <code>null</code>. * <p> - * The default implementation is a <code>NOP</code>, just setting the handle to <code>null</code>. + * The default implementation {@link ToolkitLock#dispose() dispose} it's {@link ToolkitLock} and sets the handle to <code>null</code>. * </p> * <p> * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index 583fde07f..b16b0c75c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -153,6 +153,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice @Override public boolean close() { + toolkitLock.dispose(); if(0 != handle) { handle = 0; return true; @@ -162,7 +163,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", "+toolkitLock+"]"; } /** diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index 40aaa8a25..4f4bb629b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -33,7 +33,6 @@ package javax.media.nativewindow; -import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -43,6 +42,7 @@ import java.util.Map; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; +import jogamp.nativewindow.ResourceToolkitLock; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; @@ -93,13 +93,6 @@ public abstract class NativeWindowFactory { private static ToolkitLock jawtUtilJAWTToolkitLock; - public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; - public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; - - private static Class<?> x11JAWTToolkitLockClass; - private static Constructor<?> x11JAWTToolkitLockConstructor; - private static Class<?> x11ToolkitLockClass; - private static Constructor<?> x11ToolkitLockConstructor; private static boolean requiresToolkitLock; private static volatile boolean isJVMShuttingDown = false; @@ -266,16 +259,6 @@ public abstract class NativeWindowFactory { // register either our default factory or (if exist) the X11/AWT one -> AWT Component registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory); } - - if( TYPE_X11 == nativeWindowingTypePure ) { - // passing through RuntimeException if not exists intended - x11ToolkitLockClass = ReflectionUtil.getClass(X11ToolkitLockClassName, false, cl); - x11ToolkitLockConstructor = ReflectionUtil.getConstructor(x11ToolkitLockClass, new Class[] { long.class } ); - if( isAWTAvailable() ) { - x11JAWTToolkitLockClass = ReflectionUtil.getClass(X11JAWTToolkitLockClassName, false, cl); - x11JAWTToolkitLockConstructor = ReflectionUtil.getConstructor(x11JAWTToolkitLockClass, new Class[] { long.class } ); - } - } if(DEBUG) { System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock); @@ -300,6 +283,7 @@ public abstract class NativeWindowFactory { GraphicsConfigurationFactory.shutdown(); } shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown + // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); } @@ -358,16 +342,9 @@ public abstract class NativeWindowFactory { /** * Provides the default {@link ToolkitLock} for <code>type</code>, a singleton instance. - * <br> * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>AWT-type</b> and <b>native-X11-type</b> and <b>AWT-available</b></li> - * <ul> - * <li> return {@link #getAWTToolkitLock()} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link #getNullToolkitLock()} </li> + * <li> JAWT {@link ToolkitLock} if required and AWT available, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock getDefaultToolkitLock(String type) { @@ -390,84 +367,36 @@ public abstract class NativeWindowFactory { /** * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. - * <br> * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>X11 type</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - return createX11ToolkitLock(deviceHandle); - } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } /** * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. - * <br> * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>X11 type</b> </li> - * <ul> - * <li> If <b>shared-AWT-type</b> and <b>AWT available</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock} </li> - * </ul> - * <li> else return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> + * <li> JAWT {@link ToolkitLock} if required and AWT available,</li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - if( TYPE_AWT == sharedType && isAWTAvailable() ) { - return createX11AWTToolkitLock(deviceHandle); - } - return createX11ToolkitLock(deviceHandle); + if( TYPE_AWT == sharedType && isAWTAvailable() ) { + return getAWTToolkitLock(); } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } - - protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { - try { - if(DEBUG) { - System.err.println("NativeWindowFactory.createX11AWTToolkitLock(0x"+Long.toHexString(deviceHandle)+")"); - // Thread.dumpStack(); - } - return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - protected static ToolkitLock createX11ToolkitLock(long deviceHandle) { - try { - return (ToolkitLock) x11ToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - + /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java index 30f9660f0..18b7cf5d9 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -33,12 +33,26 @@ import jogamp.nativewindow.Debug; /** * Marker for a singleton global recursive blocking lock implementation, * optionally locking a native windowing toolkit as well. - * <br> - * One use case is the AWT locking on X11, see {@link jogamp.nativewindow.jawt.JAWTToolkitLock}. + * <p> + * Toolkit locks are created solely via {@link NativeWindowFactory}. + * </p> + * <p> + * One use case is the AWT locking on X11, see {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * </p> */ public interface ToolkitLock { public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); public void lock(); public void unlock(); + + /** + * Dispose this instance. + * <p> + * Shall be called when instance is no more required. + * </p> + * This allows implementations sharing a lock via resources + * to decrease the reference counter. + */ + public void dispose(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index 1af6bf279..e59910138 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -50,4 +50,13 @@ public class NullToolkitLock implements ToolkitLock { public final void unlock() { if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } } + + public final void dispose() { + // nop + } + + public String toString() { + return "NullToolkitLock[]"; + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java index 5166ef577..a3b0804fa 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 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: @@ -25,7 +25,8 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package jogamp.nativewindow.x11; + +package jogamp.nativewindow; import javax.media.nativewindow.ToolkitLock; @@ -33,38 +34,41 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should not be used in case XInitThreads() is being used, - * or a higher level toolkit lock is required, ie AWT lock. + * Implementing a resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within a unique object + * and can be synchronized across threads via an instance of ResourceToolkitLock. + * </p> */ -public class X11ToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; - - public X11ToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } +public class ResourceToolkitLock implements ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); + + public static final ResourceToolkitLock create() { + return new ResourceToolkitLock(); } + private final RecursiveLock lock; + + private ResourceToolkitLock() { + this.lock = LockFactory.createRecursiveLock(); + } + + public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); - } + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); } + lock.lock(); } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } + if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); } + lock.unlock(); + } + + public final void dispose() { + // nop + } + + public String toString() { + return "ResourceToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java new file mode 100644 index 000000000..5d7ae8abb --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -0,0 +1,141 @@ +/** + * Copyright 2012 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 jogamp.nativewindow; + +import java.util.Iterator; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a shared resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within many objects + * and can be synchronized across threads via an unique instance of SharedResourceToolkitLock. + * </p> + * <p> + * Implementation holds a synchronized map from handle to reference counted {@link SharedResourceToolkitLock}. + * New elements are added via {@link #get(long)} if new + * and removed via {@link #dispose()} if no more referenced. + * </p> + */ +public class SharedResourceToolkitLock implements ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); + private static final LongObjectHashMap handle2Lock; + static { + handle2Lock = new LongObjectHashMap(); + handle2Lock.setKeyNotFoundValue(null); + } + + /** + * @return number of unclosed EGL Displays.<br> + */ + public static int shutdown(boolean verbose) { + if(DEBUG || verbose || handle2Lock.size() > 0 ) { + System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")"); + if(DEBUG) { + Thread.dumpStack(); + } + if( handle2Lock.size() > 0) { + dumpOpenDisplayConnections(); + } + } + return handle2Lock.size(); + } + + public static void dumpOpenDisplayConnections() { + System.err.println("SharedResourceToolkitLock: Open ResourceToolkitLock's: "+handle2Lock.size()); + int i=0; + for(Iterator<LongObjectHashMap.Entry> iter = handle2Lock.iterator(); iter.hasNext(); i++) { + final LongObjectHashMap.Entry e = iter.next(); + System.err.println("SharedResourceToolkitLock: Open["+i+"]: "+e.value); + } + } + + public static final SharedResourceToolkitLock get(long handle) { + SharedResourceToolkitLock res; + synchronized(handle2Lock) { + res = (SharedResourceToolkitLock) handle2Lock.get(handle); + if( null == res ) { + res = new SharedResourceToolkitLock(handle); + res.refCount++; + handle2Lock.put(handle, res); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * NEW *: "+res); } + } else { + res.refCount++; + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * EXIST *: "+res); } + } + } + return res; + } + + private final RecursiveLock lock; + private final long handle; + private volatile int refCount; + + private SharedResourceToolkitLock(long handle) { + this.lock = LockFactory.createRecursiveLock(); + this.handle = handle; + this.refCount = 0; + } + + + public final void lock() { + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); } + lock.lock(); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); } + lock.unlock(); + } + + public final void dispose() { + if(0 < refCount) { // volatile OK + synchronized(handle2Lock) { + refCount--; + if(0 == refCount) { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * REMOV *: "+this); } + handle2Lock.remove(handle); + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * DOWN *: "+this); } + } + } + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * NULL *: "+this); } + } + } + + public String toString() { + return "SharedResourceToolkitLock[refCount "+refCount+", handle 0x"+Long.toHexString(handle)+", obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]"; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index f1e8a786a..7c934b154 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -237,6 +237,9 @@ public class JAWTUtil { public final void unlock() { JAWTUtil.unlockToolkit(); } + public final void dispose() { + // nop + } }; // trigger native AWT toolkit / properties initialization diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 736718de8..467809284 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -127,7 +127,8 @@ public class X11JAWTWindow extends JAWTWindow { } protected Point getLocationOnScreenNativeImpl(int x, int y) { - return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + // surface is locked and hence the device + return X11Lib.GetRelativeLocation(getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 2ea75c7fb..60f54eb3c 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -42,8 +42,8 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; - import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; /** * Contains a thread safe X11 utility to retrieve display connections. @@ -80,25 +80,15 @@ public class X11Util { */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true); - /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */ - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; - - /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ - public static final boolean HAS_XLOCKDISPLAY_BUG = true; - public static final boolean DEBUG = Debug.debug("X11Util"); public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); private static String nullDisplayName = null; - private static boolean isX11LockAvailable = false; - private static boolean requiresX11Lock = true; private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues - private static int setX11ErrorHandlerRecCount = 0; private static Object setX11ErrorHandlerLock = new Object(); - /** * Called by {@link NativeWindowFactory#initSingleton()} @@ -115,9 +105,7 @@ public class X11Util { throw new NativeWindowException("NativeWindow X11 native library load error."); } - final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED ; - final boolean isXInitThreadsOK = initialize0( callXInitThreads, XERROR_STACKDUMP); - isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; + final boolean isInitOK = initialize0( XERROR_STACKDUMP ); final long dpy = X11Lib.XOpenDisplay(null); if(0 != dpy) { @@ -134,9 +122,7 @@ public class X11Util { } if(DEBUG) { - System.err.println("X11Util requiresX11Lock "+requiresX11Lock+ - ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ - ", isX11LockAvailable "+isX11LockAvailable+ + System.err.println("X11Util init OK "+isInitOK+"]"+ ", X11 Display(NULL) <"+nullDisplayName+">"+ ", XSynchronize Enabled: "+XSYNC_ENABLED); // Thread.dumpStack(); @@ -199,31 +185,14 @@ public class X11Util { } } } - - public static synchronized boolean isNativeLockAvailable() { - return isX11LockAvailable; - } - - public static synchronized boolean requiresToolkitLock() { - return requiresX11Lock; + + public static boolean requiresToolkitLock() { + return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock. } - + public static void setX11ErrorHandler(boolean onoff, boolean quiet) { synchronized(setX11ErrorHandlerLock) { - if(onoff) { - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(true, quiet); - } - setX11ErrorHandlerRecCount++; - } else { - if(0 >= setX11ErrorHandlerRecCount) { - throw new InternalError(); - } - setX11ErrorHandlerRecCount--; - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(false, false); - } - } + setX11ErrorHandler0(onoff, quiet); } } @@ -492,52 +461,50 @@ public class X11Util { *******************************/ public static long XOpenDisplay(String arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - long handle = X11Lib.XOpenDisplay(arg0); - if(XSYNC_ENABLED && 0 != handle) { - X11Lib.XSynchronize(handle, true); - } - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - // Thread.dumpStack(); - } - return handle; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + long handle = X11Lib.XOpenDisplay(arg0); + if(XSYNC_ENABLED && 0 != handle) { + X11Lib.XSynchronize(handle, true); + } + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); } + return handle; } public static int XCloseDisplay(long display) { - NativeWindowFactory.getDefaultToolkitLock().lock(); + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); + } + int res = -1; try { - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - // Thread.dumpStack(); - } - int res = -1; - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - res = X11Lib.XCloseDisplay(display); - } catch (Exception ex) { - System.err.println("X11Util: Catched Exception:"); - ex.printStackTrace(); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - return res; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + res = X11Lib.XCloseDisplay(display); + } catch (Exception ex) { + System.err.println("X11Util: Catched Exception:"); + ex.printStackTrace(); } + return res; } static volatile boolean XineramaFetched = false; static long XineramaLibHandle = 0; static long XineramaQueryFunc = 0; - public static boolean XineramaIsEnabled(long display) { - if(0==display) { - throw new IllegalArgumentException("Display NULL"); + public static boolean XineramaIsEnabled(X11GraphicsDevice device) { + if(null == device) { + throw new IllegalArgumentException("X11 Display device is NULL"); + } + device.lock(); + try { + return XineramaIsEnabled(device.getHandle()); + } finally { + device.unlock(); + } + } + public static boolean XineramaIsEnabled(long displayHandle) { + if( 0 == displayHandle ) { + throw new IllegalArgumentException("X11 Display handle is NULL"); } if(!XineramaFetched) { // volatile: ok synchronized(X11Util.class) { @@ -551,9 +518,9 @@ public class X11Util { } } if(0!=XineramaQueryFunc) { - final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, display); + final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, displayHandle); if(DEBUG) { - System.err.println("XineramaIsEnabled: "+res); + System.err.println("XineramaIsEnabled: 0x"+Long.toHexString(displayHandle)+": "+res); } return res; } else if(DEBUG) { @@ -566,7 +533,7 @@ public class X11Util { private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - private static native boolean initialize0(boolean firstUIActionOnProcess, boolean debug); + private static native boolean initialize0(boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index 1de03e8be..b152f0f97 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -91,7 +91,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); final long displayHandle; - boolean owner = false; + final boolean owner; if(0==displayHandleAWT) { displayHandle = X11Util.openDisplay(null); owner = true; @@ -112,9 +112,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println(getThreadName()+" - X11AWTGraphicsConfigurationFactory: AWT dpy "+displayName+" / "+toHexString(displayHandleAWT)+", create X11 display "+toHexString(displayHandle)); } } - final ToolkitLock lock = owner ? - NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock - NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); + // Global JAWT lock required - No X11 resource locking due to private display connection + final ToolkitLock lock = NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT); final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index fcba8580c..afdd413eb 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -178,11 +178,14 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) char threadName[80]; char errCodeStr[80]; char reqCodeStr[80]; - int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; + if( errorHandlerDebug || errorHandlerThrowException ) { + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + } (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); @@ -191,7 +194,7 @@ static int x11ErrorHandler(Display *dpy, XErrorEvent *e) threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); - if( errorHandlerDebug ) { + if( errorHandlerDebug && NULL != jniEnv ) { (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); } @@ -246,16 +249,17 @@ static int x11IOErrorHandler(Display *dpy) { const char * dpyName = XDisplayName(NULL); const char * errnoStr = strerror(errno); - char threadName[80]; int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + JNIEnv *jniEnv = NULL; - fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); + fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if (NULL != jniEnv) { + char threadName[80]; + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); if (shallBeDetached) { @@ -305,6 +309,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0 /* no dpy, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); @@ -315,6 +320,7 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboo JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } @@ -347,7 +353,7 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja } NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -382,7 +388,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); return r; } @@ -396,7 +402,7 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, } NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); return r; } @@ -439,7 +445,7 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused } NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); return _res; } @@ -497,7 +503,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -541,7 +547,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow XSelectInput(dpy, window, 0); // no events - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -569,7 +575,7 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); } /* @@ -597,7 +603,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 1e9a0e9eb..391bccf3d 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -113,17 +113,23 @@ public abstract class Display { */ public abstract int removeReference(); + /** + * Return the {@link AbstractGraphicsDevice} used for depending resources lifecycle, + * i.e. {@link Screen} and {@link Window}, as well as the event dispatching (EDT). */ public abstract AbstractGraphicsDevice getGraphicsDevice(); /** - * @return the fully qualified Display name, - * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()} + * Return the handle of the {@link AbstractGraphicsDevice} as returned by {@link #getGraphicsDevice()}. */ - public abstract String getFQName(); - public abstract long getHandle(); /** + * @return The fully qualified Display name, + * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()}. + */ + public abstract String getFQName(); + + /** * @return this display internal serial id */ public abstract int getId(); @@ -141,6 +147,9 @@ public abstract class Display { */ public abstract String getType(); + /** Return true if this instance is exclusive, i.e. will not be shared. */ + public abstract boolean isExclusive(); + /** * Sets a new {@link EDTUtil} and returns the previous one. * <p> @@ -183,11 +192,12 @@ public abstract class Display { * * @param type * @param name - * @param fromIndex start index, then increasing until found or end of list * + * @param fromIndex start index, then increasing until found or end of list + * @paran shared if true, only shared instances are found, otherwise also exclusive * @return */ - public static Display getFirstDisplayOf(String type, String name, int fromIndex) { - return getDisplayOfImpl(type, name, fromIndex, 1); + public static Display getFirstDisplayOf(String type, String name, int fromIndex, boolean shared) { + return getDisplayOfImpl(type, name, fromIndex, 1, shared); } /** @@ -195,19 +205,22 @@ public abstract class Display { * @param type * @param name * @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1. + * @paran shared if true, only shared instances are found, otherwise also exclusive * @return */ - public static Display getLastDisplayOf(String type, String name, int fromIndex) { - return getDisplayOfImpl(type, name, fromIndex, -1); + public static Display getLastDisplayOf(String type, String name, int fromIndex, boolean shared) { + return getDisplayOfImpl(type, name, fromIndex, -1, shared); } - private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr) { + private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr, boolean shared) { synchronized(displayList) { int i = fromIndex >= 0 ? fromIndex : displayList.size() - 1 ; while( ( incr > 0 ) ? i < displayList.size() : i >= 0 ) { Display display = (Display) displayList.get(i); if( display.getType().equals(type) && - display.getName().equals(name) ) { + display.getName().equals(name) && + ( !shared || shared && !display.isExclusive() ) + ) { return display; } i+=incr; diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index abae94ab6..1bf47f4aa 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -305,7 +305,7 @@ public class NewtFactory { * Instantiate a Display entity using the native handle. */ public static Display createDisplay(String type, long handle, boolean reuse) { - return DisplayImpl.create(type, null, handle, false); + return DisplayImpl.create(type, null, handle, reuse); } public static boolean isScreenCompatible(NativeWindow parent, Screen childScreen) { diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index 26f19ad6b..cfbcc988a 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -145,7 +145,7 @@ public abstract class Screen { public abstract Display getDisplay(); /** - * @return the screen fully qualified Screen name, + * @return The screen fully qualified Screen name, * which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}. */ public abstract String getFQName(); diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index bca7f6e5b..daeb3e886 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -42,6 +42,7 @@ import com.jogamp.newt.event.NEWTEventConsumer; import jogamp.newt.event.NEWTEventTask; import com.jogamp.newt.util.EDTUtil; import java.util.ArrayList; + import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; @@ -66,7 +67,7 @@ public abstract class DisplayImpl extends Display { name = display.validateDisplayName(name, handle); synchronized(displayList) { if(reuse) { - Display display0 = Display.getLastDisplayOf(type, name, -1); + Display display0 = Display.getLastDisplayOf(type, name, -1, true /* shared only */); if(null != display0) { if(DEBUG) { System.err.println("Display.create() REUSE: "+display0+" "+getThreadName()); @@ -74,9 +75,9 @@ public abstract class DisplayImpl extends Display { return display0; } } + display.exclusive = !reuse; display.name = name; display.type=type; - display.destroyWhenUnused=false; display.refCount=0; display.id = serialno++; display.fqname = getFQName(display.type, display.name, display.id); @@ -94,7 +95,7 @@ public abstract class DisplayImpl extends Display { throw new RuntimeException(e); } } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -116,10 +117,12 @@ public abstract class DisplayImpl extends Display { return true; } + @Override public int hashCode() { return hashCode; } + @Override public synchronized final void createNative() throws NativeWindowException { @@ -148,10 +151,6 @@ public abstract class DisplayImpl extends Display { } } - protected boolean shallRunOnEDT() { - return true; - } - protected EDTUtil createEDTUtil() { final EDTUtil def; if(NewtFactory.useEDT()) { @@ -179,12 +178,7 @@ public abstract class DisplayImpl extends Display { if(DEBUG) { System.err.println("Display.setEDTUtil: "+oldEDTUtil+" -> "+newEDTUtil); } - if(null != oldEDTUtil) { - stopEDT( new Runnable() { public void run() {} } ); - // ready for restart .. - oldEDTUtil.waitUntilStopped(); - oldEDTUtil.reset(); - } + removeEDT( new Runnable() { public void run() {} } ); edtUtil = newEDTUtil; return oldEDTUtil; } @@ -194,16 +188,19 @@ public abstract class DisplayImpl extends Display { return edtUtil; } - private void stopEDT(final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil ) { + private void removeEDT(final Runnable task) { + if(null!=edtUtil) { edtUtil.invokeStop(task); + // ready for restart .. + edtUtil.waitUntilStopped(); + edtUtil.reset(); } else { task.run(); } } public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil && !edtUtil.isCurrentThreadEDT()) { + if( null!=edtUtil && !edtUtil.isCurrentThreadEDT()) { edtUtil.invoke(wait, task); } else { task.run(); @@ -212,18 +209,17 @@ public abstract class DisplayImpl extends Display { public boolean validateEDT() { if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) { - stopEDT( new Runnable() { + removeEDT( new Runnable() { public void run() { // nop } } ); - edtUtil.waitUntilStopped(); - edtUtil.reset(); return true; } return false; } + @Override public synchronized final void destroy() { if(DEBUG) { dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); @@ -239,17 +235,13 @@ public abstract class DisplayImpl extends Display { } final AbstractGraphicsDevice f_aDevice = aDevice; final DisplayImpl f_dpy = this; - stopEDT( new Runnable() { + removeEDT( new Runnable() { public void run() { if ( null != f_aDevice ) { f_dpy.closeNativeImpl(); } } } ); - if(null!=edtUtil) { - edtUtil.waitUntilStopped(); - edtUtil.reset(); - } aDevice = null; refCount=0; if(DEBUG) { @@ -290,21 +282,30 @@ public abstract class DisplayImpl extends Display { protected abstract void createNativeImpl(); protected abstract void closeNativeImpl(); + @Override public final int getId() { return id; } + @Override public final String getType() { return type; } + @Override public final String getName() { return name; } + @Override public final String getFQName() { return fqname; } + + @Override + public final boolean isExclusive() { + return exclusive; + } public static final String nilString = "nil" ; @@ -324,9 +325,10 @@ public abstract class DisplayImpl extends Display { sb.append(name); sb.append("-"); sb.append(id); - return sb.toString().intern(); + return sb.toString(); } + @Override public final long getHandle() { if(null!=aDevice) { return aDevice.getHandle(); @@ -334,14 +336,17 @@ public abstract class DisplayImpl extends Display { return 0; } + @Override public final AbstractGraphicsDevice getGraphicsDevice() { return aDevice; } + @Override public synchronized final boolean isNativeValid() { return null != aDevice; } + @Override public boolean isEDTRunning() { if(null!=edtUtil) { return edtUtil.isRunning(); @@ -351,7 +356,7 @@ public abstract class DisplayImpl extends Display { @Override public String toString() { - return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; + return "NEWT-Display["+getFQName()+", excl "+exclusive+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; } protected abstract void dispatchMessagesNative(); @@ -403,6 +408,7 @@ public abstract class DisplayImpl extends Display { eventTask.notifyCaller(); } + @Override public void dispatchMessages() { // System.err.println("Display.dispatchMessages() 0 "+this+" "+getThreadName()); if(0==refCount || // no screens @@ -475,20 +481,23 @@ public abstract class DisplayImpl extends Display { public interface DisplayRunnable<T> { T run(long dpy); } - public final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) { - final AbstractGraphicsDevice aDevice = getGraphicsDevice(); - if(null == aDevice) { - throw new RuntimeException("null device - not initialized: "+this); - } + public static final <T> T runWithLockedDevice(AbstractGraphicsDevice device, DisplayRunnable<T> action) { T res; - aDevice.lock(); + device.lock(); try { - res = action.run(aDevice.getHandle()); + res = action.run(device.getHandle()); } finally { - aDevice.unlock(); + device.unlock(); } return res; } + public final <T> T runWithLockedDisplayDevice(DisplayRunnable<T> action) { + final AbstractGraphicsDevice device = getGraphicsDevice(); + if(null == device) { + throw new RuntimeException("null device - not initialized: "+this); + } + return runWithLockedDevice(device, action); + } protected EDTUtil edtUtil = null; protected int id; @@ -497,7 +506,7 @@ public abstract class DisplayImpl extends Display { protected String fqname; protected int hashCode; protected int refCount; // number of Display references by Screen - protected boolean destroyWhenUnused; + protected boolean exclusive; // do not share this display, uses NullLock! protected AbstractGraphicsDevice aDevice; } diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index e2c0f746f..1cc53e80e 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -42,7 +42,6 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.util.Dimension; import javax.media.nativewindow.util.DimensionImmutable; import javax.media.nativewindow.util.Point; @@ -130,7 +129,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { } } screen.screen_idx = idx; - screen.fqname = (display.getFQName()+idx).intern(); + screen.fqname = display.getFQName()+"-s"+idx; screen.hashCode = screen.fqname.hashCode(); screenList.add(screen); if(DEBUG) { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index c1ac87d38..79770189b 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -85,7 +85,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private volatile long windowHandle = 0; // lifecycle critical private volatile boolean visible = false; // lifecycle critical private RecursiveLock windowLock = LockFactory.createRecursiveLock(); // Window instance wide lock - private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); // Surface only lock + private int surfaceLockCount = 0; // surface lock recursion count private ScreenImpl screen; // never null after create - may change reference though (reparent) private boolean screenReferenceAdded = false; @@ -553,10 +553,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final int lockSurface() throws NativeWindowException, RuntimeException { final RecursiveLock _wlock = windowLock; - final RecursiveLock _slock = surfaceLock; _wlock.lock(); - _slock.lock(); - int res = _slock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? + surfaceLockCount++; + int res = ( 1 == surfaceLockCount ) ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { try { @@ -573,7 +572,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } finally { if (LOCK_SURFACE_NOT_READY >= res) { - _slock.unlock(); _wlock.unlock(); } } @@ -583,12 +581,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void unlockSurface() { - final RecursiveLock _slock = surfaceLock; final RecursiveLock _wlock = windowLock; - _slock.validateLocked(); _wlock.validateLocked(); - if (_slock.getHoldCount() == 1) { + if ( 1 == surfaceLockCount ) { final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); @@ -596,42 +592,48 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer adevice.unlock(); } } - _slock.unlock(); + surfaceLockCount--; _wlock.unlock(); } @Override public final boolean isSurfaceLockedByOtherThread() { - return surfaceLock.isLockedByOtherThread(); + return windowLock.isLockedByOtherThread(); } @Override public final Thread getSurfaceLockOwner() { - return surfaceLock.getOwner(); + return windowLock.getOwner(); } public final RecursiveLock getLock() { return windowLock; } + @Override public long getSurfaceHandle() { return windowHandle; // default: return window handle } + @Override public boolean surfaceSwap() { return false; } + @Override public final AbstractGraphicsConfiguration getGraphicsConfiguration() { return config.getNativeGraphicsConfiguration(); } - public final long getDisplayHandle() { - return getScreen().getDisplay().getHandle(); + @Override + public long getDisplayHandle() { + // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle(); + return screen.getDisplay().getHandle(); // shortcut } + @Override public final int getScreenIndex() { - return getScreen().getIndex(); + return screen.getIndex(); } //---------------------------------------------------------------------- @@ -1554,8 +1556,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer for (int i = 0; i < keyListeners.size(); i++ ) { sb.append(keyListeners.get(i)+", "); } - sb.append("], surfaceLock "+surfaceLock); - sb.append(", windowLock "+windowLock+"]"); + sb.append("], windowLock "+windowLock+"]"); return sb.toString(); } diff --git a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java index 70e9ba570..ead567d82 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/DisplayDriver.java @@ -66,7 +66,9 @@ public class DisplayDriver extends DisplayImpl { return def; } - protected void closeNativeImpl() { } + protected void closeNativeImpl() { + aDevice.close(); + } protected void dispatchMessagesNative() { /* nop */ } } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java index 65ca63eec..cc55c336e 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java @@ -39,6 +39,7 @@ import javax.media.nativewindow.NativeWindowException; import jogamp.newt.NEWTJNILibLoader; import jogamp.opengl.egl.EGL; +import jogamp.opengl.egl.EGLDisplayUtil; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; @@ -72,6 +73,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) { DestroyDisplay(aDevice.getHandle()); } + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java index 97c384d33..e370038d9 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/DisplayDriver.java @@ -84,6 +84,7 @@ public class DisplayDriver extends jogamp.newt.DisplayImpl { } } } + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index 1a3f14859..b49c6b6e0 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -72,7 +72,9 @@ public class DisplayDriver extends DisplayImpl { aDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } - protected void closeNativeImpl() { } + protected void closeNativeImpl() { + aDevice.close(); + } public static void runNSApplication() { runNSApplication0(); diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index 579ec5be8..615f9e63b 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -73,6 +73,7 @@ public class DisplayDriver extends DisplayImpl { protected void closeNativeImpl() { sharedClassFactory.releaseSharedClass(); + aDevice.close(); } protected void dispatchMessagesNative() { diff --git a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java index 714324d63..bff050030 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/DisplayDriver.java @@ -36,7 +36,6 @@ package jogamp.newt.driver.x11; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -74,71 +73,48 @@ public class DisplayDriver extends DisplayImpl { * {@inheritDoc} * * We use a private non-shared X11 Display instance for EDT window operations and one for exposed animation, eg. OpenGL. - * <p> - * In case {@link X11Util#HAS_XLOCKDISPLAY_BUG} and {@link X11Util#XINITTHREADS_ALWAYS_ENABLED}, - * we use null locking. Even though this seems not to be rational, it gives most stable results on all platforms. - * </p> - * <p> - * Otherwise we use basic locking via the constructor {@link X11GraphicsDevice#X11GraphicsDevice(long, int, boolean)}, - * since it is possible to share this device via {@link com.jogamp.newt.NewtFactory#createDisplay(String, boolean)}. - * </p> */ - @SuppressWarnings("unused") protected void createNativeImpl() { + X11Util.setX11ErrorHandler(true, DEBUG ? false : true); // make sure X11 error handler is set long handle = X11Util.openDisplay(name); if( 0 == handle ) { throw new RuntimeException("Error creating display(Win): "+name); } - if(USE_SEPARATE_DISPLAY_FOR_EDT) { - edtDisplayHandle = X11Util.openDisplay(name); - if( 0 == edtDisplayHandle ) { - X11Util.closeDisplay(handle); - throw new RuntimeException("Error creating display(EDT): "+name); - } - } else { - edtDisplayHandle = handle; - } + aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, true); try { - CompleteDisplay0(edtDisplayHandle); + CompleteDisplay0(aDevice.getHandle()); } catch(RuntimeException e) { closeNativeImpl(); throw e; - } - - // see API doc above! - if(X11Util.XINITTHREADS_ALWAYS_ENABLED && X11Util.HAS_XLOCKDISPLAY_BUG) { - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock(), false); - } else { - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, false); - } + } } protected void closeNativeImpl() { - DisplayRelease0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom); + DisplayRelease0(aDevice.getHandle(), javaObjectAtom, windowDeleteAtom); javaObjectAtom = 0; windowDeleteAtom = 0; - // closing using ATI driver bug 'same order' - final long handle = getHandle(); - X11Util.closeDisplay(handle); - if(handle != edtDisplayHandle) { - X11Util.closeDisplay(edtDisplayHandle); - } - edtDisplayHandle = 0; + aDevice.close(); // closes X11 display } protected void dispatchMessagesNative() { - if(0 != edtDisplayHandle) { - DispatchMessages0(edtDisplayHandle, javaObjectAtom, windowDeleteAtom); + aDevice.lock(); + try { + final long handle = aDevice.getHandle(); + if(0 != handle) { + DispatchMessages0(handle, javaObjectAtom, windowDeleteAtom); + } + } finally { + aDevice.unlock(); } } - protected long getEDTHandle() { return edtDisplayHandle; } protected long getJavaObjectAtom() { return javaObjectAtom; } protected long getWindowDeleteAtom() { return windowDeleteAtom; } //---------------------------------------------------------------------- // Internals only // + private static native boolean initIDs0(boolean debug); private native void CompleteDisplay0(long handle); @@ -151,17 +127,6 @@ public class DisplayDriver extends DisplayImpl { private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom); - /** - * 2011/06/14 libX11 1.4.2 and libxcb 1.7 bug 20708 - Multithreading Issues w/ OpenGL, .. - * https://bugs.freedesktop.org/show_bug.cgi?id=20708 - * https://jogamp.org/bugzilla/show_bug.cgi?id=502 - * Affects: Ubuntu 11.04, OpenSuSE 11, .. - * Workaround: Using a separate X11 Display connection for event dispatching (EDT) - */ - private final boolean USE_SEPARATE_DISPLAY_FOR_EDT = true; - - private long edtDisplayHandle; - /** X11 Window delete atom marker used on EDT */ private long windowDeleteAtom; diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 10f6b84da..b09d98e06 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -59,7 +59,7 @@ public class ScreenDriver extends ScreenImpl { protected void createNativeImpl() { // validate screen index - Long handle = display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Long>() { + Long handle = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Long>() { public Long run(long dpy) { return new Long(GetScreen0(dpy, screen_idx)); } } ); @@ -81,7 +81,7 @@ public class ScreenDriver extends ScreenImpl { private int nmode_number; protected int[] getScreenModeFirstImpl() { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<int[]>() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<int[]>() { public int[] run(long dpy) { // initialize iterators and static data nrotations = getAvailableScreenModeRotations0(dpy, screen_idx); @@ -110,7 +110,7 @@ public class ScreenDriver extends ScreenImpl { protected int[] getScreenModeNextImpl() { // assemble: w x h x bpp x f x r - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<int[]>() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<int[]>() { public int[] run(long dpy) { /** System.err.println("******** mode: "+nmode_number); @@ -176,7 +176,7 @@ public class ScreenDriver extends ScreenImpl { } protected ScreenMode getCurrentScreenModeImpl() { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<ScreenMode>() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<ScreenMode>() { public ScreenMode run(long dpy) { long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx); if(0 == screenConfigHandle) { @@ -237,7 +237,7 @@ public class ScreenDriver extends ScreenImpl { throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode); } final long t0 = System.currentTimeMillis(); - boolean done = runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() { + boolean done = runWithTempDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() { public Boolean run(long dpy) { boolean done = false; long screenConfigHandle = getScreenConfiguration0(dpy, screen_idx); @@ -276,23 +276,21 @@ public class ScreenDriver extends ScreenImpl { return done; } - private class XineramaEnabledQuery implements DisplayImpl.DisplayRunnable<Boolean> { + private DisplayImpl.DisplayRunnable<Boolean> xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable<Boolean>() { public Boolean run(long dpy) { return new Boolean(X11Util.XineramaIsEnabled(dpy)); - } - } - private XineramaEnabledQuery xineramaEnabledQuery = new XineramaEnabledQuery(); + } }; protected int validateScreenIndex(final int idx) { if(getDisplay().isNativeValid()) { - return runWithLockedDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + return X11Util.XineramaIsEnabled((X11GraphicsDevice)getDisplay().getGraphicsDevice()) ? 0 : idx; } else { - return runWithTempDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + return runWithTempDisplayHandle( xineramaEnabledQueryWithTemp ).booleanValue() ? 0 : idx; } } protected void getVirtualScreenOriginAndSize(final Point virtualOrigin, final Dimension virtualSize) { - display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { public Object run(long dpy) { virtualOrigin.setX(0); virtualOrigin.setY(0); @@ -305,10 +303,8 @@ public class ScreenDriver extends ScreenImpl { //---------------------------------------------------------------------- // Internals only // - private final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) { - return display.runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); - // return runWithoutLock(action); + private final <T> T runWithLockedDisplayDevice(DisplayRunnable<T> action) { + return display.runWithLockedDisplayDevice(action); } private final <T> T runWithTempDisplayHandle(DisplayRunnable<T> action) { @@ -324,9 +320,6 @@ public class ScreenDriver extends ScreenImpl { } return res; } - private final <T> T runWithoutLock(DisplayRunnable<T> action) { - return action.run(display.getHandle()); - } private static native long GetScreen0(long dpy, int scrn_idx); diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index 97d1ae3db..aea86a420 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -35,6 +35,7 @@ package jogamp.newt.driver.x11; import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; import jogamp.newt.DisplayImpl.DisplayRunnable; import jogamp.newt.WindowImpl; @@ -44,6 +45,8 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; import com.jogamp.newt.event.MouseEvent; public class WindowDriver extends WindowImpl { @@ -63,9 +66,19 @@ public class WindowDriver extends WindowImpl { protected void createNativeImpl() { final ScreenDriver screen = (ScreenDriver) getScreen(); final DisplayDriver display = (DisplayDriver) screen.getDisplay(); + final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice(); + + // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering + final long renderDeviceHandle = X11Util.openDisplay(edtDevice.getConnection()); + if( 0 == renderDeviceHandle ) { + throw new RuntimeException("Error creating display(EDT): "+edtDevice.getConnection()); + } + renderDevice = new X11GraphicsDevice(renderDeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true); + AbstractGraphicsScreen renderScreen = new X11GraphicsScreen((X11GraphicsDevice) renderDevice, screen.getIndex()); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested); final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); + capsRequested, capsRequested, capabilitiesChooser, renderScreen, VisualIDHolder.VID_UNDEFINED); if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+cfg); } @@ -78,11 +91,16 @@ public class WindowDriver extends WindowImpl { } setGraphicsConfiguration(cfg); final int flags = getReconfigureFlags(0, true) & - ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; - setWindowHandle(CreateWindow0(getParentWindowHandle(), - display.getEDTHandle(), screen.getIndex(), visualID, - display.getJavaObjectAtom(), display.getWindowDeleteAtom(), - getX(), getY(), getWidth(), getHeight(), autoPosition(), flags)); + ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; + edtDevice.lock(); + try { + setWindowHandle(CreateWindow0(getParentWindowHandle(), + edtDevice.getHandle(), screen.getIndex(), visualID, + display.getJavaObjectAtom(), display.getWindowDeleteAtom(), + getX(), getY(), getWidth(), getHeight(), autoPosition(), flags)); + } finally { + edtDevice.unlock(); + } windowHandleClose = getWindowHandle(); if (0 == windowHandleClose) { throw new NativeWindowException("Error creating window"); @@ -92,8 +110,10 @@ public class WindowDriver extends WindowImpl { protected void closeNativeImpl() { if(0!=windowHandleClose && null!=getScreen() ) { DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); + final AbstractGraphicsDevice edtDevice = display.getGraphicsDevice(); + edtDevice.lock(); try { - CloseWindow0(display.getEDTHandle(), windowHandleClose, + CloseWindow0(edtDevice.getHandle(), windowHandleClose, display.getJavaObjectAtom(), display.getWindowDeleteAtom()); } catch (Throwable t) { if(DEBUG_IMPLEMENTATION) { @@ -101,28 +121,47 @@ public class WindowDriver extends WindowImpl { e.printStackTrace(); } } finally { + edtDevice.unlock(); windowHandleClose = 0; } } + if(null != renderDevice) { + renderDevice.close(); // closes X11 display + renderDevice = null; + } } - protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { + @Override + public long getDisplayHandle() { + // Actually: return getGraphicsConfiguration().getScreen().getDevice().getHandle(); + return renderDevice.getHandle(); // shortcut + } + + protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ getReconfigureFlagsAsString(null, flags)); } + final int _x, _y; if(0 == ( FLAG_IS_UNDECORATED & flags)) { final InsetsImmutable i = getInsets(); // client position -> top-level window position - x -= i.getLeftWidth() ; - y -= i.getTopHeight() ; + _x = x - i.getLeftWidth() ; + _y = y - i.getTopHeight() ; + } else { + _x = x; + _y = y; } final DisplayDriver display = (DisplayDriver) getScreen().getDisplay(); - reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(), - getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(), - x, y, width, height, flags); - + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { + public Object run(long dpy) { + reconfigureWindow0( dpy, getScreenIndex(), + getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(), + _x, _y, width, height, flags); + return null; + } + }); return true; } @@ -133,13 +172,18 @@ public class WindowDriver extends WindowImpl { } } - protected void requestFocusImpl(boolean force) { - requestFocus0(getDisplayEDTHandle(), getWindowHandle(), force); + protected void requestFocusImpl(final boolean force) { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { + public Object run(long dpy) { + requestFocus0(dpy, getWindowHandle(), force); + return null; + } + }); } @Override protected void setTitleImpl(final String title) { - runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { public Object run(long dpy) { setTitle0(dpy, getWindowHandle(), title); return null; @@ -149,35 +193,38 @@ public class WindowDriver extends WindowImpl { @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() { public Boolean run(long dpy) { - return Boolean.valueOf(setPointerVisible0(getDisplayEDTHandle(), getWindowHandle(), pointerVisible)); + return Boolean.valueOf(setPointerVisible0(dpy, getWindowHandle(), pointerVisible)); } }).booleanValue(); } @Override protected boolean confinePointerImpl(final boolean confine) { - return runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Boolean>() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Boolean>() { public Boolean run(long dpy) { - return Boolean.valueOf(confinePointer0(getDisplayEDTHandle(), getWindowHandle(), confine)); + return Boolean.valueOf(confinePointer0(dpy, getWindowHandle(), confine)); } }).booleanValue(); } @Override protected void warpPointerImpl(final int x, final int y) { - runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Object>() { public Object run(long dpy) { - warpPointer0(getDisplayEDTHandle(), getWindowHandle(), x, y); + warpPointer0(dpy, getWindowHandle(), x, y); return null; } }); } protected Point getLocationOnScreenImpl(final int x, final int y) { - // X11Util.GetRelativeLocation: locks display already ! - return X11Lib.GetRelativeLocation( getScreen().getDisplay().getHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable<Point>() { + public Point run(long dpy) { + return X11Lib.GetRelativeLocation(dpy, getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + } + } ); } protected void updateInsetsImpl(Insets insets) { @@ -229,16 +276,11 @@ public class WindowDriver extends WindowImpl { //---------------------------------------------------------------------- // Internals only // - private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - private final long getDisplayEDTHandle() { - return ((DisplayDriver) getScreen().getDisplay()).getEDTHandle(); - } - private final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) { - return ((DisplayImpl) getScreen().getDisplay()).runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); + private final <T> T runWithLockedDisplayDevice(DisplayRunnable<T> action) { + return ((DisplayDriver) getScreen().getDisplay()).runWithLockedDisplayDevice(action); } protected static native boolean initIDs0(); @@ -258,4 +300,5 @@ public class WindowDriver extends WindowImpl { private static native void warpPointer0(long display, long windowHandle, int x, int y); private long windowHandleClose; + private AbstractGraphicsDevice renderDevice; } diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index 128b6b6f1..4d1a7b59e 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -70,7 +70,6 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 84b3a7630..56c11fab4 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -52,90 +52,6 @@ static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID requestFocusID = NULL; -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; - -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } - jvmVersion = (*env)->GetVersion(env); -} - -static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; -static int errorHandlerDebug = 0 ; -static int errorHandlerThrowException = 0; - -static int x11ErrorHandler(Display *dpy, XErrorEvent *e) -{ - if(!errorHandlerQuiet) { - const char * errnoStr = strerror(errno); - char threadName[80]; - char errCodeStr[80]; - char reqCodeStr[80]; - - int shallBeDetached = 0; - JNIEnv *jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - - (void) NewtCommon_GetStaticStringMethod(jniEnv, X11NewtWindowClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); - XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); - XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - - fprintf(stderr, "Info: Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - - if( errorHandlerDebug ) { - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11NewtWindowClazz, dumpStackID); - } - - if(errorHandlerThrowException) { - if(NULL != jniEnv) { - NewtCommon_throwNewRuntimeException(jniEnv, "Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { - fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif - } - } - fflush(stderr); - - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } - } - - return 0; -} - -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { - errorHandlerQuiet = quiet; - if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - } - } else { - if(NULL!=origErrorHandler) { - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - XSetErrorHandler(origErrorHandler); - origErrorHandler = NULL; - } - } -} - /** * Keycode */ @@ -273,9 +189,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 { jclass c; - if(debug) { - errorHandlerDebug = 1 ; - } NewtCommon_init(env); if(NULL==X11NewtWindowClazz) { @@ -439,8 +352,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, #ifdef VERBOSE_ON True @@ -449,8 +360,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage #endif ); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - if(NULL==jwindow) { fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window); diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 59862f463..2e16e7cae 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -683,16 +683,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 DBG_PRINT( "X11: CloseWindow START dpy %p, win %p\n", (void*)dpy, (void*)w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "could not fetch Java Window object, bail out!"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!"); return; } @@ -700,7 +696,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 XSync(dpy, False); XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); // Drain all events related to this window .. Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom); @@ -761,8 +756,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo fsEWMHFlags |= _NET_WM_ABOVE; // toggle above } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", (void*)dpy, screen_index, (void*) jparent, (void*)parent, (void*)w, x, y, width, height, @@ -779,7 +772,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) ) { Bool enable = TST_FLAG_CHANGE_FULLSCREEN(flags) ? TST_FLAG_IS_FULLSCREEN(flags) : TST_FLAG_IS_ALWAYSONTOP(flags) ; if( NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); #ifdef FS_GRAB_KEYBOARD if(TST_FLAG_CHANGE_FULLSCREEN(flags)) { if(TST_FLAG_IS_FULLSCREEN(flags)) { @@ -863,8 +855,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo #endif } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - DBG_PRINT( "X11: reconfigureWindow0 X\n"); } 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/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java index 743d371b7..e5ed8a79f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrent01NEWT.java @@ -3,14 +3,14 @@ * * 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 @@ -20,57 +20,59 @@ * 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 jogamp.nativewindow.jawt.x11; + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; -import jogamp.nativewindow.jawt.*; -import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; -import javax.media.nativewindow.ToolkitLock; +import org.junit.Test; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.common.os.Platform; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should only be used if AWT is using the underlying native windowing toolkit - * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call - * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. + * 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 X11JAWTToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; +public class TestInitConcurrent01NEWT extends InitConcurrentBaseNEWT { - public X11JAWTToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2, true); } - - public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } - JAWTUtil.lockToolkit(); - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); + + @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 { - lock.lock(); + runJOGLTasks( 8, true); } } - - public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); + + 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(); } + } } - JAWTUtil.unlockToolkit(); + 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); + } + +} |