aboutsummaryrefslogtreecommitdiffstats
path: root/src/nativewindow
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-09-30 19:47:46 +0200
committerSven Gothel <[email protected]>2012-09-30 19:47:46 +0200
commit92398025abdabb2fdef0d78edd41e730991a6f94 (patch)
tree8d209c588d1246aa126c29465206ba1f8167c0e2 /src/nativewindow
parent43891be36e8485353ac74f329fd2f7438303a846 (diff)
Workaround for Bug 623: Sporadic XCB assertion failures w/ ATI proprietary driver and w/o native X11 locking
The proprietary ATI X11 driver does not handle multi-threaded [GL] clients well, i.e. triggers an XCB assertion 'from time to time'. It almost seems like that the driver either: - aliases all display connections to it's connection name, i.e. server; or - utilizes a build-in display connection w/o locking, used for some reason +++ - X11Lib: Add QueryExtension(dpy, name) allowing early driver determination w/o GL - X11Util detects 'requiresGlobalToolkitLock' and 'markAllDisplaysUnclosable' via X11 extensions. In case certain ATI extensions are available, both are set to true. - X11GLXDrawableFactory: Dropped setting 'markAllDisplaysUnclosable', using X11Util's detection (see above). - New GlobalToolkitLock to satisfy certain driver restrictions (ATI's XCB multithreading bug) - NativeWindowFactory handles new property requiresGlobalToolkitLock, in which case the new GlobalToolkitLock is being used instead of ResourceToolkitLock. - JAWTUtil ToolkitLock locks GlobalToolkitLock 1st to match new 'requiresGlobalToolkitLock' property. - Document static method requirement of X11Util, GDIUtil and OSXUtil via marker interface ToolkitProperties - ToolkitLock: New method 'validateLocked()', allowing use to validate whether the device/toolkit is properly locked and hence to detect implementation bugs. See unit test class: ValidateLockListener
Diffstat (limited to 'src/nativewindow')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java2
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java11
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java21
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java101
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java22
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java75
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java7
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java19
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java15
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java11
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java51
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java36
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java22
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java15
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java51
-rw-r--r--src/nativewindow/native/x11/Xmisc.c35
16 files changed, 413 insertions, 81 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
index 142bb99e3..0f28ca67c 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java
@@ -61,7 +61,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl
}
/** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default
- * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}.
+ * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
* @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long)
*/
public X11GraphicsDevice(long display, int unitID, boolean owner) {
diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
index 5eaaa6613..8ecd5242d 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java
@@ -102,17 +102,24 @@ public interface AbstractGraphicsDevice extends Cloneable {
public long getHandle();
/**
- * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}.
+ * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#lock()}.
* The lock implementation must be recursive.
*/
public void lock();
/**
- * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}.
+ * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#unlock()}.
* The lock implementation must be recursive.
+ *
+ * @throws RuntimeException in case the lock is not acquired by this thread.
*/
public void unlock();
+ /**
+ * @throws RuntimeException if current thread does not hold the lock
+ */
+ public void validateLocked() throws RuntimeException;
+
/**
* Optionally [re]opening the device if handle is <code>null</code>.
* <p>
diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
index b16b0c75c..9288652d9 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java
@@ -60,7 +60,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
/**
* Create an instance with the system default {@link ToolkitLock}.
- * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}.
+ * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
* @param type
* @param handle
*/
@@ -70,7 +70,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
this.unitID = unitID;
this.uniqueID = getUniqueID(type, connection, unitID);
this.handle = handle;
- this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle);
+ this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type, handle);
}
/**
@@ -123,8 +123,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
}
/**
- * No lock is performed on the graphics device per default,
- * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked.
+ * {@inheritDoc}
+ * <p>
+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}.
+ * </p>
*
* @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long)
* @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock)
@@ -134,9 +136,16 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice
toolkitLock.lock();
}
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ toolkitLock.validateLocked();
+ }
+
/**
- * No lock is performed on the graphics device per default,
- * instead the aggregated recursive {@link ToolkitLock#unlock()} is invoked.
+ * {@inheritDoc}
+ * <p>
+ * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}.
+ * </p>
*
* @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long)
* @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock)
diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
index 4f4bb629b..af8008f0f 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
@@ -42,6 +42,7 @@ import java.util.Map;
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NativeWindowFactoryImpl;
+import jogamp.nativewindow.ToolkitProperties;
import jogamp.nativewindow.ResourceToolkitLock;
import com.jogamp.common.os.Platform;
@@ -87,13 +88,17 @@ public abstract class NativeWindowFactory {
private static boolean isAWTAvailable;
private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ;
+ /** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */
private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util";
+ /** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */
private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil";
+ /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */
private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil";
private static ToolkitLock jawtUtilJAWTToolkitLock;
private static boolean requiresToolkitLock;
+ private static boolean requiresGlobalToolkitLock;
private static volatile boolean isJVMShuttingDown = false;
@@ -156,11 +161,18 @@ public abstract class NativeWindowFactory {
if( null != clazzName ) {
ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl );
- final Boolean res = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl);
- requiresToolkitLock = res.booleanValue();
+ final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl);
+ requiresToolkitLock = res1.booleanValue();
+ if(requiresToolkitLock) {
+ final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresGlobalToolkitLock", null, null, cl);
+ requiresGlobalToolkitLock = res2.booleanValue();
+ } else {
+ requiresGlobalToolkitLock = false;
+ }
} else {
requiresToolkitLock = false;
- }
+ requiresGlobalToolkitLock = false;
+ }
}
private static void shutdownNativeImpl(final ClassLoader cl) {
@@ -261,7 +273,7 @@ public abstract class NativeWindowFactory {
}
if(DEBUG) {
- System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock);
+ System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", requiresGlobalToolkitLock "+requiresGlobalToolkitLock);
System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory);
}
@@ -295,7 +307,12 @@ public abstract class NativeWindowFactory {
/** @return true if the underlying toolkit requires locking, otherwise false. */
public static boolean requiresToolkitLock() {
return requiresToolkitLock;
- }
+ }
+
+ /** @return true if the underlying toolkit requires global locking, otherwise false. */
+ public static boolean requiresGlobalToolkitLock() {
+ return requiresGlobalToolkitLock;
+ }
/** @return true if not headless, AWT Component and NativeWindow's AWT part available */
public static boolean isAWTAvailable() { return isAWTAvailable; }
@@ -331,9 +348,28 @@ public abstract class NativeWindowFactory {
return defaultFactory;
}
+ /**
+ * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null.
+ * <p>
+ * The JAWT based {@link ToolkitLock} also locks the global lock,
+ * which matters if the latter is required.
+ * </p>
+ */
+ public static ToolkitLock getAWTToolkitLock() {
+ return jawtUtilJAWTToolkitLock;
+ }
+
+ public static ToolkitLock getNullToolkitLock() {
+ return NativeWindowFactoryImpl.getNullToolkitLock();
+ }
+
+ public static ToolkitLock getGlobalToolkitLock() {
+ return NativeWindowFactoryImpl.getGlobalToolkitLock();
+ }
+
/**
- * Provides the system default {@link ToolkitLock}, a singleton instance.
- * <br>
+ * Provides the system default {@link ToolkitLock} for the default system windowing type.
+ * @see #getNativeWindowType(boolean)
* @see #getDefaultToolkitLock(java.lang.String)
*/
public static ToolkitLock getDefaultToolkitLock() {
@@ -341,57 +377,44 @@ public abstract class NativeWindowFactory {
}
/**
- * Provides the default {@link ToolkitLock} for <code>type</code>, a singleton instance.
+ * Provides the default {@link ToolkitLock} for <code>type</code>.
* <ul>
- * <li> JAWT {@link ToolkitLock} if required and AWT available, otherwise</li>
+ * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li>
+ * <li> {@link jogamp.nativewindow.GlobalToolkitLock} if required, otherwise</li>
+ * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li>
* <li> {@link jogamp.nativewindow.NullToolkitLock} </li>
* </ul>
*/
public static ToolkitLock getDefaultToolkitLock(String type) {
- if( requiresToolkitLock() ) {
- if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) {
+ if( requiresToolkitLock ) {
+ if( TYPE_AWT == type && isAWTAvailable() ) {
return getAWTToolkitLock();
}
- }
- return NativeWindowFactoryImpl.getNullToolkitLock();
- }
-
- /** Returns the AWT Toolkit (JAWT based) if {@link #isAWTAvailable}, otherwise null. */
- public static ToolkitLock getAWTToolkitLock() {
- return jawtUtilJAWTToolkitLock;
- }
-
- public static ToolkitLock getNullToolkitLock() {
- return NativeWindowFactoryImpl.getNullToolkitLock();
- }
-
- /**
- * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>.
- * <ul>
- * <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( requiresGlobalToolkitLock ) {
+ return NativeWindowFactoryImpl.getGlobalToolkitLock();
+ }
return ResourceToolkitLock.create();
}
return NativeWindowFactoryImpl.getNullToolkitLock();
}
-
+
/**
- * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>.
+ * Provides the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>.
* <ul>
- * <li> JAWT {@link ToolkitLock} if required and AWT available,</li>
+ * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li>
+ * <li> {@link jogamp.nativewindow.GlobalToolkitLock} if required, otherwise</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_AWT == sharedType && isAWTAvailable() ) {
+ public static ToolkitLock getDefaultToolkitLock(String type, long deviceHandle) {
+ if( requiresToolkitLock ) {
+ if( TYPE_AWT == type && isAWTAvailable() ) {
return getAWTToolkitLock();
}
+ if( requiresGlobalToolkitLock ) {
+ return NativeWindowFactoryImpl.getGlobalToolkitLock();
+ }
return ResourceToolkitLock.create();
}
return NativeWindowFactoryImpl.getNullToolkitLock();
diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
index 18b7cf5d9..eccfcfa4f 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java
@@ -37,15 +37,35 @@ import jogamp.nativewindow.Debug;
* 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)}.
+ * One use case is the AWT locking on X11, see {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}.
* </p>
*/
public interface ToolkitLock {
+ public static final boolean DEBUG = Debug.debug("ToolkitLock");
public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true);
+ /**
+ * Blocking until the lock is acquired by this Thread or a timeout is reached.
+ * <p>
+ * Timeout is implementation specific, if used at all.
+ * </p>
+ *
+ * @throws RuntimeException in case of a timeout
+ */
public void lock();
+
+ /**
+ * Release the lock.
+ *
+ * @throws RuntimeException in case the lock is not acquired by this thread.
+ */
public void unlock();
+ /**
+ * @throws RuntimeException if current thread does not hold the lock
+ */
+ public void validateLocked() throws RuntimeException;
+
/**
* Dispose this instance.
* <p>
diff --git a/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java
new file mode 100644
index 000000000..0c2a1e43f
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java
@@ -0,0 +1,75 @@
+/**
+ * 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 javax.media.nativewindow.ToolkitLock;
+
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+/**
+ * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}.
+ * <p>
+ * This is the last resort for unstable driver, e.g. proprietary ATI/X11 12.8 and 12.9,
+ * where multiple X11 display connections to the same connection name are not treated
+ * thread safe within the GL/X11 driver.
+ * </p>
+ */
+public class GlobalToolkitLock implements ToolkitLock {
+ private static final RecursiveLock globalLock = LockFactory.createRecursiveLock();
+
+ /** Singleton via {@link NativeWindowFactoryImpl#getGlobalToolkitLock()} */
+ protected GlobalToolkitLock() { }
+
+ @Override
+ public final void lock() {
+ globalLock.lock();
+ if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.lock()"); }
+ }
+
+ @Override
+ public final void unlock() {
+ if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.unlock()"); }
+ globalLock.unlock(); // implicit lock validation
+ }
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ globalLock.validateLocked();
+ }
+
+ @Override
+ public final void dispose() {
+ // nop
+ }
+
+ public String toString() {
+ return "GlobalToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString()+"]";
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
index 29564da3b..c35cede77 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
@@ -44,9 +44,14 @@ import com.jogamp.common.util.ReflectionUtil.AWTNames;
public class NativeWindowFactoryImpl extends NativeWindowFactory {
private static final ToolkitLock nullToolkitLock = new NullToolkitLock();
+ private static final ToolkitLock globalToolkitLock = new GlobalToolkitLock();
public static ToolkitLock getNullToolkitLock() {
- return nullToolkitLock;
+ return nullToolkitLock;
+ }
+
+ public static ToolkitLock getGlobalToolkitLock() {
+ return globalToolkitLock;
}
// This subclass of NativeWindowFactory handles the case of
diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
index e59910138..211e15955 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
@@ -31,15 +31,16 @@ package jogamp.nativewindow;
import javax.media.nativewindow.ToolkitLock;
/**
- * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock}
- * without any locking. Since there is no locking it all,
- * it is intrinsically recursive.
+ * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock}
+ * without any locking. Since there is no locking it all, it is intrinsically recursive.
*/
public class NullToolkitLock implements ToolkitLock {
-
+ public static final boolean INVALID_LOCKED = Debug.isPropertyDefined("nativewindow.debug.NullToolkitLock.InvalidLocked", true);
+
/** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */
protected NullToolkitLock() { }
+ @Override
public final void lock() {
if(TRACE_LOCK) {
System.err.println("NullToolkitLock.lock()");
@@ -47,10 +48,20 @@ public class NullToolkitLock implements ToolkitLock {
}
}
+ @Override
public final void unlock() {
if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); }
}
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ /* nop */
+ if(INVALID_LOCKED) {
+ throw new RuntimeException("NullToolkitLock does not lock");
+ }
+ }
+
+ @Override
public final void dispose() {
// nop
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java
index a3b0804fa..5b79de0b8 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java
@@ -41,8 +41,6 @@ import com.jogamp.common.util.locks.RecursiveLock;
* </p>
*/
public class ResourceToolkitLock implements ToolkitLock {
- public static final boolean DEBUG = Debug.debug("ToolkitLock");
-
public static final ResourceToolkitLock create() {
return new ResourceToolkitLock();
}
@@ -53,17 +51,24 @@ public class ResourceToolkitLock implements ToolkitLock {
this.lock = LockFactory.createRecursiveLock();
}
-
+ @Override
public final void lock() {
- if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); }
lock.lock();
+ if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); }
}
+ @Override
public final void unlock() {
if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); }
- lock.unlock();
+ lock.unlock(); // implicit lock validation
+ }
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ lock.validateLocked();
}
+ @Override
public final void dispose() {
// nop
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java
index 5d7ae8abb..94d12e6fc 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java
@@ -49,7 +49,6 @@ import com.jogamp.common.util.locks.RecursiveLock;
* </p>
*/
public class SharedResourceToolkitLock implements ToolkitLock {
- public static final boolean DEBUG = Debug.debug("ToolkitLock");
private static final LongObjectHashMap handle2Lock;
static {
handle2Lock = new LongObjectHashMap();
@@ -109,16 +108,24 @@ public class SharedResourceToolkitLock implements ToolkitLock {
}
+ @Override
public final void lock() {
- if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); }
lock.lock();
+ if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); }
}
+ @Override
public final void unlock() {
if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); }
lock.unlock();
}
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ lock.validateLocked();
+ }
+
+ @Override
public final void dispose() {
if(0 < refCount) { // volatile OK
synchronized(handle2Lock) {
diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java
new file mode 100644
index 000000000..2062d1f58
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java
@@ -0,0 +1,51 @@
+package jogamp.nativewindow;
+
+import javax.media.nativewindow.NativeWindowFactory;
+
+/**
+ * Marker interface.
+ * <p>
+ * Implementation requires to provide static methods:
+ * <pre>
+ public static void initSingleton() {}
+
+ public static void shutdown() {}
+
+ public static boolean requiresToolkitLock() {}
+
+ public static boolean requiresGlobalToolkitLock() {}
+ * </pre>
+ * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()},
+ * or {@link NativeWindowFactory#shutdown()} via reflection.
+ * </p>
+ * <p>
+ * If <code>requiresGlobalToolkitLock() == true</code>, then
+ * <code>requiresToolkitLock() == true</code> shall be valid as well.
+ * </p>
+ */
+public interface ToolkitProperties {
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // void initSingleton();
+
+ /**
+ * Cleanup resources.
+ * <p>
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * </p>
+ */
+ // void shutdown();
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // boolean requiresToolkitLock();
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // boolean requiresGlobalToolkitLock();
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
index 7c934b154..2dadfb16b 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
@@ -79,6 +79,8 @@ public class JAWTUtil {
private static final Method sunToolkitAWTLockMethod;
private static final Method sunToolkitAWTUnlockMethod;
private static final boolean hasSunToolkitAWTLock;
+
+ private static volatile Thread exclusiveOwnerThread;
private static final ToolkitLock jawtToolkitLock;
@@ -229,13 +231,23 @@ public class JAWTUtil {
}
hasSunToolkitAWTLock = _hasSunToolkitAWTLock;
// hasSunToolkitAWTLock = false;
+ exclusiveOwnerThread = null;
jawtToolkitLock = new ToolkitLock() {
public final void lock() {
+ NativeWindowFactory.getGlobalToolkitLock().lock();
JAWTUtil.lockToolkit();
+ if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.lock()"); }
}
public final void unlock() {
+ if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.unlock()"); }
JAWTUtil.unlockToolkit();
+ NativeWindowFactory.getGlobalToolkitLock().unlock();
+ }
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ NativeWindowFactory.getGlobalToolkitLock().validateLocked();
+ JAWTUtil.validateLocked();
}
public final void dispose() {
// nop
@@ -312,7 +324,7 @@ public class JAWTUtil {
* JAWT's native Lock() function calls SunToolkit.awtLock(),
* which just uses AWT's global ReentrantLock.<br>
*/
- private static void awtLock() {
+ private static final void awtLock() {
if(hasSunToolkitAWTLock) {
try {
sunToolkitAWTLockMethod.invoke(null, (Object[])null);
@@ -322,6 +334,7 @@ public class JAWTUtil {
} else {
jawtLockObject.Lock();
}
+ exclusiveOwnerThread = Thread.currentThread();
}
/**
@@ -330,7 +343,9 @@ public class JAWTUtil {
* JAWT's native Unlock() function calls SunToolkit.awtUnlock(),
* which just uses AWT's global ReentrantLock.<br>
*/
- private static void awtUnlock() {
+ private static final void awtUnlock() {
+ awtValidateLocked();
+ exclusiveOwnerThread = null;
if(hasSunToolkitAWTLock) {
try {
sunToolkitAWTUnlockMethod.invoke(null, (Object[])null);
@@ -342,6 +357,16 @@ public class JAWTUtil {
}
}
+ private static final void awtValidateLocked() throws RuntimeException {
+ final Thread ct = Thread.currentThread();
+ if( ct != exclusiveOwnerThread ) {
+ if ( null == exclusiveOwnerThread ) {
+ throw new RuntimeException(ct.getName()+": JAWT-ToolkitLock not locked");
+ }
+ throw new RuntimeException(ct.getName()+": Not JAWT-ToolkitLock owner. Owner is "+exclusiveOwnerThread.getName());
+ }
+ }
+
public static void lockToolkit() throws NativeWindowException {
if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock()"); }
if(!headlessMode && !isJava2DQueueFlusherThread()) {
@@ -355,6 +380,13 @@ public class JAWTUtil {
awtUnlock();
}
}
+
+ public static final void validateLocked() throws RuntimeException {
+ if(!headlessMode && !isJava2DQueueFlusherThread()) {
+ awtValidateLocked();
+ }
+ }
+
public static ToolkitLock getJAWTToolkitLock() {
return jawtToolkitLock;
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index b7a83e133..481cbbe39 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -34,13 +34,15 @@ import javax.media.nativewindow.util.Point;
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
+import jogamp.nativewindow.ToolkitProperties;
-public class OSXUtil {
+public class OSXUtil implements ToolkitProperties {
private static boolean isInit = false;
private static final boolean DEBUG = Debug.debug("OSXUtil");
/**
* Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
*/
public static synchronized void initSingleton() {
if(!isInit) {
@@ -60,13 +62,21 @@ public class OSXUtil {
/**
* Called by {@link NativeWindowFactory#shutdown()}
+ * @see ToolkitProperties
*/
- public static void shutdown() {
- }
+ public static void shutdown() { }
- public static boolean requiresToolkitLock() {
- return false;
- }
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static boolean requiresToolkitLock() { return false; }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresGlobalToolkitLock() { return false; }
public static boolean isNSView(long object) {
return isNSView0(object);
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java
index 613c76032..4408a0903 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java
@@ -33,9 +33,10 @@ import javax.media.nativewindow.NativeWindowFactory;
import jogamp.nativewindow.NWJNILibLoader;
import jogamp.nativewindow.Debug;
+import jogamp.nativewindow.ToolkitProperties;
import jogamp.nativewindow.x11.X11Util;
-public class GDIUtil {
+public class GDIUtil implements ToolkitProperties {
private static final boolean DEBUG = Debug.debug("GDIUtil");
private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ;
@@ -44,6 +45,7 @@ public class GDIUtil {
/**
* Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
*/
public static synchronized void initSingleton() {
if(!isInit) {
@@ -67,12 +69,23 @@ public class GDIUtil {
/**
* Called by {@link NativeWindowFactory#shutdown()}
+ * @see ToolkitProperties
*/
public static void shutdown() {
}
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
public static boolean requiresToolkitLock() { return false; }
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresGlobalToolkitLock() { return false; }
+
private static RegisteredClass dummyWindowClass = null;
private static Object dummyWindowSync = new Object();
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
index 30792113d..a331fa940 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
@@ -43,13 +43,15 @@ import javax.media.nativewindow.NativeWindowFactory;
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
+import jogamp.nativewindow.ToolkitProperties;
+
import com.jogamp.common.util.LongObjectHashMap;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
/**
* Contains a thread safe X11 utility to retrieve display connections.
*/
-public class X11Util {
+public class X11Util implements ToolkitProperties {
/**
* See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515
* <p>
@@ -88,11 +90,15 @@ public class X11Util {
private static String nullDisplayName = null;
private static volatile boolean isInit = false;
private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues
+ private static boolean requiresGlobalToolkitLock = false; // ATI/AMD X11 driver issues
private static Object setX11ErrorHandlerLock = new Object();
+ private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI";
+ private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION";
/**
* Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
*/
public static void initSingleton() {
if(!isInit) {
@@ -100,7 +106,7 @@ public class X11Util {
if(!isInit) {
isInit = true;
if(DEBUG) {
- System.out.println("X11UtilUtil.initSingleton()");
+ System.out.println("X11Util.initSingleton()");
}
if(!NWJNILibLoader.loadNativeWindow("x11")) {
throw new NativeWindowException("NativeWindow X11 native library load error.");
@@ -108,6 +114,7 @@ public class X11Util {
final boolean isInitOK = initialize0( XERROR_STACKDUMP );
+ final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION;
final long dpy = X11Lib.XOpenDisplay(null);
if(0 != dpy) {
if(XSYNC_ENABLED) {
@@ -115,17 +122,29 @@ public class X11Util {
}
try {
nullDisplayName = X11Lib.XDisplayString(dpy);
+ hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI);
+ hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION);
} finally {
X11Lib.XCloseDisplay(dpy);
}
} else {
nullDisplayName = "nil";
+ hasX11_EXTENSION_ATIFGLRXDRI = false;
+ hasX11_EXTENSION_ATIFGLEXTENSION = false;
}
+ requiresGlobalToolkitLock = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION;
+ markAllDisplaysUnclosable = ATI_HAS_XCLOSEDISPLAY_BUG && ( hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION );
if(DEBUG) {
- System.err.println("X11Util init OK "+isInitOK+"]"+
- ", X11 Display(NULL) <"+nullDisplayName+">"+
- ", XSynchronize Enabled: "+XSYNC_ENABLED);
+ System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+
+ ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+
+ ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+
+ ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+
+ ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+
+ ",\n\t requiresToolkitLock "+requiresToolkitLock()+
+ ",\n\t requiresGlobalToolkitLock "+requiresGlobalToolkitLock()+
+ ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable()
+ );
// Thread.dumpStack();
}
}
@@ -147,6 +166,7 @@ public class X11Util {
* <p>
* Called by {@link NativeWindowFactory#shutdown()}
* </p>
+ * @see ToolkitProperties
*/
public static void shutdown() {
if(isInit) {
@@ -189,8 +209,20 @@ public class X11Util {
}
}
- public static boolean requiresToolkitLock() {
- return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock.
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresToolkitLock() {
+ return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection.
+ }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresGlobalToolkitLock() {
+ return requiresGlobalToolkitLock; // JAWT locking: yes, instead of native X11 locking w use a global lock.
}
public static void setX11ErrorHandler(boolean onoff, boolean quiet) {
@@ -206,9 +238,6 @@ public class X11Util {
public static boolean getMarkAllDisplaysUnclosable() {
return markAllDisplaysUnclosable;
}
- public static void setMarkAllDisplaysUnclosable(boolean v) {
- markAllDisplaysUnclosable = v;
- }
private X11Util() {}
@@ -373,7 +402,7 @@ public class X11Util {
name = validateDisplayName(name);
boolean reused = false;
- synchronized(globalLock) {
+ synchronized(globalLock) {
for(int i=0; i<reusableDisplayList.size(); i++) {
if(reusableDisplayList.get(i).getName().equals(name)) {
namedDpy = reusableDisplayList.remove(i);
diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c
index 9e2130668..8bfe28f2b 100644
--- a/src/nativewindow/native/x11/Xmisc.c
+++ b/src/nativewindow/native/x11/Xmisc.c
@@ -606,3 +606,38 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio
return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y);
}
+/*
+ * Class: jogamp_nativewindow_x11_X11Lib
+ * Method: QueryExtension0
+ * Signature: (JLjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0
+ (JNIEnv *env, jclass unused, jlong jdisplay, jstring jextensionName)
+{
+ int32_t major_opcode, first_event, first_error;
+ jboolean res = JNI_FALSE;
+ Display * display = (Display *) (intptr_t) jdisplay;
+ const char* extensionName = NULL;
+
+ if(NULL==display) {
+ NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"display\"");
+ return res;
+ }
+ if ( NULL == jextensionName ) {
+ NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"extensionName\"");
+ return res;
+ }
+ extensionName = (*env)->GetStringUTFChars(env, jextensionName, (jboolean*)NULL);
+ if ( NULL == extensionName ) {
+ NativewindowCommon_throwNewRuntimeException(env, "Failed to get UTF-8 chars for argument \"extensionName\"");
+ return res;
+ }
+
+ res = True == XQueryExtension(display, extensionName, &major_opcode, &first_event, &first_error) ? JNI_TRUE : JNI_FALSE;
+
+ if ( NULL != jextensionName ) {
+ (*env)->ReleaseStringUTFChars(env, jextensionName, extensionName);
+ }
+ return res;
+}
+