From fbe331f013608eb31ff0d8675f4e4c9881c9c48b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 27 Sep 2012 17:33:39 +0200 Subject: 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. --- src/newt/classes/com/jogamp/newt/Display.java | 35 ++++--- src/newt/classes/com/jogamp/newt/NewtFactory.java | 2 +- src/newt/classes/com/jogamp/newt/Screen.java | 2 +- src/newt/classes/jogamp/newt/DisplayImpl.java | 79 ++++++++------- src/newt/classes/jogamp/newt/ScreenImpl.java | 3 +- src/newt/classes/jogamp/newt/WindowImpl.java | 33 ++++--- .../jogamp/newt/driver/awt/DisplayDriver.java | 4 +- .../jogamp/newt/driver/bcm/egl/DisplayDriver.java | 2 + .../newt/driver/intel/gdl/DisplayDriver.java | 1 + .../jogamp/newt/driver/macosx/DisplayDriver.java | 4 +- .../jogamp/newt/driver/windows/DisplayDriver.java | 1 + .../jogamp/newt/driver/x11/DisplayDriver.java | 65 +++---------- .../jogamp/newt/driver/x11/ScreenDriver.java | 31 +++--- .../jogamp/newt/driver/x11/WindowDriver.java | 107 +++++++++++++++------ 14 files changed, 200 insertions(+), 169 deletions(-) (limited to 'src/newt/classes') 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,16 +113,22 @@ 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 */ @@ -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. *

@@ -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 run(long dpy); } - public final T runWithLockedDisplayHandle(DisplayRunnable action) { - final AbstractGraphicsDevice aDevice = getGraphicsDevice(); - if(null == aDevice) { - throw new RuntimeException("null device - not initialized: "+this); - } + public static final T runWithLockedDevice(AbstractGraphicsDevice device, DisplayRunnable 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 runWithLockedDisplayDevice(DisplayRunnable 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. - *

- * 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. - *

- *

- * 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)}. - *

*/ - @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 handle = runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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 done = runWithTempDisplayHandle( new DisplayImpl.DisplayRunnable() { 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 { + private DisplayImpl.DisplayRunnable xineramaEnabledQueryWithTemp = new DisplayImpl.DisplayRunnable() { 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() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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 runWithLockedDisplayHandle(DisplayRunnable action) { - return display.runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); - // return runWithoutLock(action); + private final T runWithLockedDisplayDevice(DisplayRunnable action) { + return display.runWithLockedDisplayDevice(action); } private final T runWithTempDisplayHandle(DisplayRunnable action) { @@ -324,9 +320,6 @@ public class ScreenDriver extends ScreenImpl { } return res; } - private final T runWithoutLock(DisplayRunnable 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() { + 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() { + public Object run(long dpy) { + requestFocus0(dpy, getWindowHandle(), force); + return null; + } + }); } @Override protected void setTitleImpl(final String title) { - runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + return runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + runWithLockedDisplayDevice( new DisplayImpl.DisplayRunnable() { 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() { + 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 runWithLockedDisplayHandle(DisplayRunnable action) { - return ((DisplayImpl) getScreen().getDisplay()).runWithLockedDisplayHandle(action); - // return runWithTempDisplayHandle(action); + private final T runWithLockedDisplayDevice(DisplayRunnable 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; } -- cgit v1.2.3