diff options
author | Sven Gothel <[email protected]> | 2009-06-13 20:01:06 +0000 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2009-06-13 20:01:06 +0000 |
commit | 11de8a47460ae1c491a84a0a4e0f070d1b910f5d (patch) | |
tree | 18c7bbcc4ef65fad2bc13d5b65921ee12009a301 /src/nativewindow | |
parent | 6c0991646be43f495507a096f945da4d07d6a3ca (diff) |
- Adding GLAutoDrawable.ScreenChangeActionEnabled reflecting the
boolean system property 'jogl.screenchange.action',
wheather to enable or disable (default) the drawable configuration
in case the screen changed ..
- X11Util Changes:
Clarified the documentation a bit.
Renaming for clarification:
getDefaultDisplay() -> getStaticDefaultDisplay()
isXineramaEnabled() -> isXineramaEnabledOnStaticDefaultDisplay()
Removing for clarification:
getDisplayConnection()
Introducing thread current default display,
which returns/creates one display connection for the running thread in TLS.
getThreadLocalDefaultDisplay()
This shall be used with care, to not risc memory leakage.
Currently used for long term objects, ie Pbuffer ..
- Validated the ToolkitLock lock/unlock
in relation with the NativeWindow surface lock/unlock.
Both locking mechanism may be related, e.g. in case of AWT/JAWT.
Here, a JAWT surface lock would implicitly lock the global JAWT.
The latter is actually intended to be done by the JAWT ToolkitLock
implementation we offer. Not calling it would steal it's lock
and we won't benefit from it's recursive behavior.
A followup ToolkitLock lock would deadlock,
since we already have locked it implicitly with the surface lock.
Hence the NativeWindow surface lock needs to be the owner of
the JAWT ToolkitLock 'lock' incl. issuing it's optional native locking.
Massive multithreading tests on multi core machines (X11, Windows, MacOSX)
AWT and NEWT (AWT/Native) .. no deadlocks under
java demos.es[12].RedSquare -GL2 -GL2 -GL2 -GL2
java demos.es[12].RedSquare -awt -GL2 -GL2 -GL2 -GL2
java demos.es[12].RedSquare -GL2 -GL2 -awt -GL2 -GL2
- NEWT Windows:
- Adding fullscreen
- Cleaning up the UserData attachment, adding JNIEnv,
and removing the global reference at window destruction.
The later removes a StackOverflow .. alright,
but still a lack of true multiple top level window.
- NEWT AWTCanvas: Apply Ken's fix for using disableBackgroundEraseMethod
- FIX X11AWTGLXGraphicsConfigurationFactory:
Wow .. I must have been blind, now using the right method
X11SunJDKReflection.graphicsDeviceGetDisplay() :)
However, in case we couldn't determine the display handle,
we will use a thread local display handle.
-
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JOGL_2_SANDBOX@1943 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/nativewindow')
8 files changed, 155 insertions, 62 deletions
diff --git a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTUtil.java b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTUtil.java index fe49db0bc..ec0794b63 100644 --- a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTUtil.java @@ -60,9 +60,9 @@ public class JAWTUtil { public static synchronized void lockToolkit() throws NativeWindowException { if (null!=lockedStack) { lockedStack.printStackTrace(); - throw new NativeWindowException("Toolkit already locked"); + throw new NativeWindowException("JAWT Toolkit already locked - "+Thread.currentThread().getName()); } - lockedStack = new Exception("JAWT - already locked by: "); + lockedStack = new Exception("JAWT Toolkit already locked by: "+Thread.currentThread().getName()); if (headlessMode) { // Workaround for running (to some degree) in headless diff --git a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java index f5a82bff6..a4a529c54 100644 --- a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java @@ -84,21 +84,16 @@ public abstract class JAWTWindow implements NativeWindow { private volatile Exception lockedStack = null; public synchronized int lockSurface() throws NativeWindowException { - if(DEBUG) { - // Not that this is a hard criteria .. - // but it is not recommended locking both, JAWT and the surface - if(JAWTUtil.isToolkitLocked()) { - JAWTUtil.getLockedStack().printStackTrace(); - throw new NativeWindowException("JAWT already locked - "+this); - } - } + // We have to be the owner of the JAWT ToolkitLock 'lock' to benefit from the + // recursive lock capabitlites. Otherwise a followup ToolkitLock would + // deadlock, since we already have locked JAWT with the surface lock. + NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); if (null!=lockedStack) { lockedStack.printStackTrace(); - throw new NativeWindowException("Surface already locked - "+this); + throw new NativeWindowException("JAWT Surface already locked - "+Thread.currentThread().getName()+" "+this); } - - lockedStack = new Exception("JAWTWindow previously locked by "+Thread.currentThread().getName()); + lockedStack = new Exception("JAWT Surface previously locked by "+Thread.currentThread().getName()); return LOCK_SUCCESS; } @@ -106,10 +101,10 @@ public abstract class JAWTWindow implements NativeWindow { public synchronized void unlockSurface() { if (null!=lockedStack) { lockedStack = null; - // notifyAll(); } else { - throw new NativeWindowException("JAWTWindow not locked"); + throw new NativeWindowException("JAWT Surface not locked"); } + NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); } public synchronized boolean isSurfaceLocked() { diff --git a/src/nativewindow/classes/com/sun/nativewindow/impl/x11/X11Util.java b/src/nativewindow/classes/com/sun/nativewindow/impl/x11/X11Util.java index 42e7ab495..731bd3caf 100644 --- a/src/nativewindow/classes/com/sun/nativewindow/impl/x11/X11Util.java +++ b/src/nativewindow/classes/com/sun/nativewindow/impl/x11/X11Util.java @@ -32,51 +32,94 @@ package com.sun.nativewindow.impl.x11; +import java.util.HashMap; + import javax.media.nativewindow.*; import com.sun.nativewindow.impl.*; +/** + * Contains a thread safe X11 utility to retrieve tread local display connection,<br> + * as well as the static global discplay connection.<br> + * + * The TLS variant is thread safe per se, but has the memory leak risk on applications + * heavily utilizing runnables on a new thread.<br> + * + * The static variant is more nice to resources, but involves the default toolkit + * locking mechanism, which invocation you have to provide as shown below.<br> + * <PRE> + NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); + try { + long displayHandle = X11Util.getStaticDefaultDisplay(); + ... + } finally { + NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); + } + * </PRE><br> + * + * We will use the TLS variant, where a long term display connection is being used, + * ie in JOGL's <code>X11AWTGLXGraphicsConfigurationFactory</code>, + * on all other situations where we just query some X11 attributes, + * the locked static variant shall be used instead.<br> + */ public class X11Util { + private static final boolean DEBUG = Debug.debug("X11Util"); + static { NativeLibLoaderBase.loadNativeWindow("x11"); } - private static final boolean DEBUG = Debug.debug("X11Util"); - private X11Util() {} - // Display connection for use by visual selection algorithm and by all offscreen surfaces - private static long staticDisplay=0; - private static boolean xineramaEnabled=false; - public static long getDisplayConnection() { - if (staticDisplay == 0) { - NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); - try { - staticDisplay = X11Lib.XOpenDisplay(null); - if (staticDisplay != 0) { - xineramaEnabled = X11Lib.XineramaEnabled(staticDisplay); + private static ThreadLocal currentDisplayAssociation = new ThreadLocal(); + + private static long staticDefaultDisplay=0; + private static boolean staticDefaultDisplayXineramaEnable=false; + + private static long fetchStaticDefaultDisplay() { + if(0==staticDefaultDisplay) { + synchronized (X11Util.class) { + if(0==staticDefaultDisplay) { + staticDefaultDisplay = X11Lib.XOpenDisplay(null); + if(0==staticDefaultDisplay) { + throw new NativeWindowException("Unable to create a static default display connection"); + } + staticDefaultDisplayXineramaEnable = X11Lib.XineramaEnabled(staticDefaultDisplay); } - } finally { - NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); - } - if (staticDisplay == 0) { - throw new NativeWindowException("Unable to open default display"); } } - return staticDisplay; + return staticDefaultDisplay; } - public static long getDefaultDisplay() { - if (staticDisplay == 0) { - getDisplayConnection(); // will set xineramaEnabled - } - return staticDisplay; + /** Returns the global static default display connection, read the toolkit lock/unlock + * requirements {@link X11Util above} for synchronization. */ + public static long getStaticDefaultDisplay() { + return fetchStaticDefaultDisplay(); + } + + /** Returns the global static default display connection, read the toolkit lock/unlock + * requirements {@link X11Util above} for synchronization. */ + public static boolean isXineramaEnabledOnStaticDefaultDisplay() { + fetchStaticDefaultDisplay(); + return staticDefaultDisplayXineramaEnable; } - public static boolean isXineramaEnabled() { - if (staticDisplay == 0) { - getDisplayConnection(); // will set xineramaEnabled + + /** Returns this thread current default display. */ + public static long getThreadLocalDefaultDisplay() { + Long dpyL = (Long) currentDisplayAssociation.get(); + if(null==dpyL) { + long dpy = X11Lib.XOpenDisplay(null); + if(0==dpy) { + throw new NativeWindowException("Unable to create a default display connection on Thread "+Thread.currentThread().getName()); + } + dpyL = new Long(dpy); + currentDisplayAssociation.set( dpyL ); + if(DEBUG) { + Exception e = new Exception("Created new TLS display connection 0x"+Long.toHexString(dpy)+" for thread "+Thread.currentThread().getName()); + e.printStackTrace(); + } } - return xineramaEnabled; + return dpyL.longValue(); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index ea053e317..2a9782c12 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -70,9 +70,18 @@ public interface NativeWindow { * shall be set and be valid after a successfull call, * ie a return value other than {@link #LOCK_SURFACE_NOT_READY}.<P> * + * The semantics of the underlying native locked resource + * may be related to the {@link ToolkitLock} one. Hence it is + * important that implementation of both harmonize well.<br> + * The implementation may want to aquire the {@link ToolkitLock} + * first to become it's owner before proceeding with it's + * actual surface lock. <P> + * * @return {@link #LOCK_SUCCESS}, {@link #LOCK_SURFACE_CHANGED} or {@link #LOCK_SURFACE_NOT_READY}. * * @throws NativeWindowException if surface is already locked + * + * @see ToolkitLock */ public int lockSurface() throws NativeWindowException ; @@ -83,6 +92,9 @@ public interface NativeWindow { * or the surface handle, see {@link #lockSurface()} <P> * * @throws NativeWindowException if surface is not locked + * + * @see #lockSurface + * @see ToolkitLock */ public void unlockSurface() throws NativeWindowException ; diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index 2b1f10a4c..9fad5f5bd 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -124,7 +124,9 @@ public abstract class NativeWindowFactory { } catch (Exception e) { } } - if(TYPE_X11.equals(nativeWindowingTypeCustom)) { + boolean toolkitLockDisabled = Boolean.getBoolean("nativewindow.toolkitlock.disabled"); // test .. + + if(TYPE_X11.equals(nativeWindowingTypeCustom) && !toolkitLockDisabled) { NativeWindowFactory _factory = null; // FIXME: there are regressions in functionality in the @@ -143,6 +145,7 @@ public abstract class NativeWindowFactory { // makes X calls from multiple threads: for example, the // AWT Toolkit thread and one or more Event Dispatch // Threads. + // CHECK: OK // // In the JOGL API, there are other operations that use an // X display connection which do not involve locking an @@ -159,6 +162,11 @@ public abstract class NativeWindowFactory { // (Semantically this should be allowed, but practically, // it is unclear.) Currently the JOGL implementation locks // the ToolkitLock around pbuffer-related operations. + // CHECK: OK - Using X11GraphicsScreen.createDefault() now, + // utilizing one display per thread. + // However, locking code is still intact. + // FIXME: Shall it really have one new display per + // Pbuffer ? // // Even if the pbuffer case is over-synchronized, there // are definitely cases where synchronization with the @@ -203,14 +211,14 @@ public abstract class NativeWindowFactory { // If it turns out that the AWT is not available, for // example on embedded profiles (CDC / FP), then // synchronization is still needed, for example among - // multiple threads that might create pbuffers. The - // X11NativeWindowFactory provides a simple reentrant lock + // multiple threads that might create pbuffers + // or for threads using the static default display to query information. + // The X11NativeWindowFactory provides a simple reentrant lock // for this purpose. It is expected that third-party // toolkits will either replace this factory, and thereby // the implementation of this lock, if stronger // interoperability is desired, for example full support // for external GLDrawables. - if (null ==_factory) { // Try the non-AWT X11 native window factory try { @@ -226,9 +234,12 @@ public abstract class NativeWindowFactory { } if(null!=componentClass) { - // register either our default factory or (if exist) the X11/AWT one -> NativeWindow + // register either our default factory or (if exist) the X11/AWT one -> AWT Component registerFactory(componentClass, factory); - defaultFactory = factory; + } + defaultFactory = factory; + if(DEBUG) { + System.err.println("NativeWindowFactory defaultFactory "+factory); } } @@ -334,8 +345,8 @@ public abstract class NativeWindowFactory { protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException; /** Returns the object which provides support for synchronizing - with the underlying window toolkit. On most platforms the - returned object does nothing; currently it only has effects on - X11 platforms. */ + with the underlying window toolkit.<br> + @see ToolkitLock + */ public abstract ToolkitLock getToolkitLock(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java index 6b9d25190..27e59d8c8 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -37,8 +37,33 @@ package javax.media.nativewindow; implementation. This mechanism is generally only needed on X11 platforms. Currently it is only used when the AWT is in use. Implementations of this lock, if they are not no-ops, must support - reentrant locking and unlocking. */ + reentrant locking and unlocking. <P> + + The ToolkitLock implementation can be aquired by + {@link NativeWindowFactory#getToolkitLock NativeWindowFactory's getToolkitLock()}.<P> + All toolkit shared resources shall be accessed by encapsulating the + code with a locking block as follows. + <PRE> + NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); + try { + long displayHandle = X11Util.getStaticDefaultDisplay(); + ... + } finally { + NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); + } + </PRE><P> + + The underlying toolkit's locking mechanism may relate to {@link NativeWindow}'s + {@link NativeWindow#lockSurface lockSurface()}. Hence it is important + that both implementation harmonize well, ie {@link NativeWindow#lockSurface lockSurface()} + shall issue a ToolkitLock lock befor it aquires it's surface lock. This is true + in the AWT implementation for example. Otherwise the surface lock would <i>steal</i> + the ToolkitLock's lock and a deadlock would be unavoidable.<P> + + However the necessity of needing a global state synchronization will of course + impact your performance very much, especially in case of a multithreaded/multiwindow case. + */ public interface ToolkitLock { /** Locks the toolkit. */ public void lock(); diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java index 5e1871b18..911b8f416 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java @@ -43,6 +43,9 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl /** Constructs a new X11GraphicsDevice corresponding to the given native display handle. */ public X11GraphicsDevice(long display) { super(NativeWindowFactory.TYPE_X11, display); + if(0==display) { + throw new NativeWindowException("null display"); + } } public Object clone() { diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java index afee33688..f434050f2 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java @@ -54,31 +54,35 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl return new X11GraphicsScreen(new X11GraphicsDevice(display), screenIdx); } + /** Creates a new X11GraphicsScreen using a thread local display connection */ public static AbstractGraphicsScreen createDefault() { - long display = X11Util.getDefaultDisplay(); + long display = X11Util.getThreadLocalDefaultDisplay(); int scrnIdx = X11Lib.DefaultScreen(display); return createScreenDevice(display, scrnIdx); } public long getDefaultVisualID() { - long display = X11Util.getDefaultDisplay(); - int scrnIdx = X11Lib.DefaultScreen(display); - return X11Lib.DefaultVisualID(display, scrnIdx); + // It still could be an AWT hold handle .. + NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); + try { + long display = getDevice().getHandle(); + int scrnIdx = X11Lib.DefaultScreen(display); + return X11Lib.DefaultVisualID(display, scrnIdx); + } finally { + NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); + } } private static int fetchScreen(int screen) { - // FIXME NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); - /* + NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); try { - if(!com.sun.nativewindow.impl.x11.X11Util.isXineramaEnabled()) { + if(!com.sun.nativewindow.impl.x11.X11Util.isXineramaEnabledOnStaticDefaultDisplay()) { return screen; } } finally { - // FIXME NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); + NativeWindowFactory.getDefaultFactory().getToolkitLock().unlock(); } return 0; - */ - return screen; } public Object clone() { |