From 2d32b056c7b1b6b3d071d79fb4c2d4e9113b59d5 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 23 Jun 2013 01:21:30 +0200 Subject: Fix Bug 761 (part 2/2): NEWT registers one customShutdownHook @ NativeWindowFactory.shutdownHook head, allowing proper resource cleanup. 1 WindowImpl.shutdownAll(): - For all instances: - mark invalid (causes any user thread to disregard the window) 2 ScreenImpl.shutdownAll(): - Removed own shutdown-hook! - For all instances: - Reset ScreenMonitorState 3 DisplayImpl.shutdownAll(): - For all instances: - Remove EDT - closeNativeImpl Manually tested on X11 w/ NV and ATI Catalyst (fglrx) - DFLAGS="-Djogl.debug.GLDrawable -Dnativewindow.debug.X11Util -Dnativewindow.debug.NativeWindow -Dnewt.debug.Display -Dnewt.debug.Screen -Dnewt.debug.Window" - java $DFLAGS com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -time 2000 -sysExit testExit - valid arguments for sysExit: testExit, testError, displayExit, displayError --- src/newt/classes/com/jogamp/newt/Display.java | 2 +- src/newt/classes/jogamp/newt/DisplayImpl.java | 45 +++++++++++++++++++++-- src/newt/classes/jogamp/newt/ScreenImpl.java | 45 +++++++++-------------- src/newt/classes/jogamp/newt/WindowImpl.java | 53 ++++++++++++++++++++++++--- 4 files changed, 109 insertions(+), 36 deletions(-) (limited to 'src/newt') diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 993aa33eb..d6ddd9613 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -178,7 +178,7 @@ public abstract class Display { public abstract void dispatchMessages(); // Global Displays - protected static ArrayList displayList = new ArrayList(); + protected static final ArrayList displayList = new ArrayList(); protected static int displaysActive = 0; public static void dumpDisplayList(String prefix) { diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index d4842ba2f..3edb532db 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -45,10 +45,24 @@ import java.util.ArrayList; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; public abstract class DisplayImpl extends Display { private static int serialno = 1; + static { + NativeWindowFactory.addCustomShutdownHook(true /* head */, new Runnable() { + public void run() { + WindowImpl.shutdownAll(); + ScreenImpl.shutdownAll(); + DisplayImpl.shutdownAll(); + } + }); + } + + /** Ensure static init has been run. */ + /* pp */static void initSingleton() { } + private static Class getDisplayClass(String type) throws ClassNotFoundException { @@ -232,11 +246,10 @@ public abstract class DisplayImpl extends Display { if(DEBUG) { System.err.println("Display.destroy(): "+this+" "+getThreadName()); } - final AbstractGraphicsDevice f_aDevice = aDevice; final DisplayImpl f_dpy = this; - removeEDT( new Runnable() { + removeEDT( new Runnable() { // blocks! public void run() { - if ( null != f_aDevice ) { + if ( null != aDevice ) { f_dpy.closeNativeImpl(); } } @@ -247,6 +260,32 @@ public abstract class DisplayImpl extends Display { dumpDisplayList("Display.destroy("+getFQName()+") END"); } } + + /** Maybe utilized at a shutdown hook, impl. does not synchronize, however the EDT removal blocks. */ + /* pp */ static final void shutdownAll() { + final int dCount = displayList.size(); + if(DEBUG) { + dumpDisplayList("Display.shutdownAll "+dCount+" instances, on thread "+getThreadName()); + } + for(int i=0; i0; i++) { // be safe .. + final DisplayImpl d = (DisplayImpl) displayList.remove(0); + if(0 < displaysActive) { + displaysActive--; + } + if(DEBUG) { + System.err.println("Display.shutdownAll["+(i+1)+"/"+dCount+"]: "+d); + } + d.removeEDT( new Runnable() { + public void run() { + if ( null != d.getGraphicsDevice() ) { + d.closeNativeImpl(); + } + } + } ); + d.aDevice = null; + d.refCount=0; + } + } public synchronized final int addReference() { if(DEBUG) { diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index 7edf7b63a..f63d1499e 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -34,8 +34,6 @@ package jogamp.newt; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -64,6 +62,13 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { public static final int default_sm_rate = 60; public static final int default_sm_rotation = 0; + static { + DisplayImpl.initSingleton(); + } + + /** Ensure static init has been run. */ + /* pp */static void initSingleton() { } + protected DisplayImpl display; protected int screen_idx; protected String fqname; @@ -77,15 +82,6 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { private long tCreated; // creationTime - static { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - registerShutdownHook(); - return null; - } - }); - } - private static Class getScreenClass(String type) throws ClassNotFoundException { final Class screenClass = NewtFactory.getCustomClass(type, "ScreenDriver"); @@ -660,23 +656,18 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { ScreenMonitorState.unmapScreenMonitorStateUnlocked(getFQName()); } } - private static final void shutdownAll() { - for(int i=0; i < screenList.size(); i++) { - ((ScreenImpl)screenList.get(i)).shutdown(); - } - } - private static synchronized void registerShutdownHook() { - final Thread shutdownHook = new Thread(new Runnable() { - public void run() { - ScreenImpl.shutdownAll(); - } - }); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - Runtime.getRuntime().addShutdownHook(shutdownHook); - return null; + /** pp */ static final void shutdownAll() { + final int sCount = screenList.size(); + if(DEBUG) { + System.err.println("Screen.shutdownAll "+sCount+" instances, on thread "+Display.getThreadName()); + } + for(int i=0; i0; i++) { // be safe .. + final ScreenImpl s = (ScreenImpl) screenList.remove(0); + if(DEBUG) { + System.err.println("Screen.shutdownAll["+(i+1)+"/"+sCount+"]: "+s); } - }); + s.shutdown(); + } } } diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index dca287c6b..1ac97b07c 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -82,6 +82,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); + protected static final ArrayList windowList = new ArrayList(); + + static { + ScreenImpl.initSingleton(); + } + + /** Maybe utilized at a shutdown hook, impl. does not synchronize, however the Window destruction and EDT removal blocks. */ + public static final void shutdownAll() { + final int wCount = windowList.size(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.shutdownAll "+wCount+" instances, on thread "+getThreadName()); + } + for(int i=0; i0; i++) { // be safe .. + final WindowImpl w = windowList.remove(0); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.shutdownAll["+(i+1)+"/"+wCount+"]: "+toHexString(w.getWindowHandle())); + } + w.markInvalid(); + } + } + /** Timeout of queued events (repaint and resize) */ static final long QUEUED_EVENT_TO = 1200; // ms @@ -186,6 +207,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer window.screen = (ScreenImpl) screen; window.capsRequested = (CapabilitiesImmutable) caps.cloneMutable(); window.instantiationFinished(); + synchronized( windowList ) { + windowList.add(window); + } return window; } catch (Throwable t) { t.printStackTrace(); @@ -207,12 +231,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; window.screen = (ScreenImpl) screen; window.capsRequested = (CapabilitiesImmutable) caps.cloneMutable(); + window.instantiationFinished(); + synchronized( windowList ) { + windowList.add(window); + } return window; } catch (Throwable t) { throw new NativeWindowException(t); } } + /** Fast invalidation of instance w/o any blocking function call. */ + private final void markInvalid() { + setWindowHandle(0); + visible = false; + fullscreen = false; + fullscreenMonitors = null; + fullscreenUseMainMonitor = true; + hasFocus = false; + parentWindowHandle = 0; + } + protected final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) { config = cfg; } @@ -233,9 +272,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** * Notifies the receiver to preserve resources (GL, ..) - * for the next destroy*() calls (only). + * for the next destroy*() calls (only), if supported and if value is true, otherwise clears preservation flag. + * @param value true to set the one-shot preservation if supported, otherwise clears it. */ - void preserveGLStateAtDestroy(); + void preserveGLStateAtDestroy(boolean value); /** * Invoked before Window destroy action, @@ -995,13 +1035,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public void destroy() { + synchronized( windowList ) { + windowList.remove(this); + } visible = false; // Immediately mark synchronized visibility flag, avoiding possible recreation runOnEDTIfAvail(true, destroyAction); } protected void destroy(boolean preserveResources) { - if( preserveResources && null != WindowImpl.this.lifecycleHook ) { - WindowImpl.this.lifecycleHook.preserveGLStateAtDestroy(); + if( null != lifecycleHook ) { + lifecycleHook.preserveGLStateAtDestroy( preserveResources ); } destroy(); } @@ -1108,7 +1151,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } // Destroy this window and use parent's Screen. // It may be created properly when the parent is made visible. - destroy(false); + destroy( false ); setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); operation = ReparentOperation.ACTION_NATIVE_CREATION_PENDING; } else if(newParentWindow != getParent()) { -- cgit v1.2.3