aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-06-23 01:21:30 +0200
committerSven Gothel <[email protected]>2013-06-23 01:21:30 +0200
commit2d32b056c7b1b6b3d071d79fb4c2d4e9113b59d5 (patch)
tree65bd4a21fa8263a05d90edbd1ee6b4c23052a2d8 /src
parent41c626d8a27981e694b3b728a9a2f2bc8def939d (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/newt/classes/com/jogamp/newt/Display.java2
-rw-r--r--src/newt/classes/jogamp/newt/DisplayImpl.java45
-rw-r--r--src/newt/classes/jogamp/newt/ScreenImpl.java45
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java53
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java46
5 files changed, 155 insertions, 36 deletions
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<Display> displayList = new ArrayList<Display>();
+ protected static final ArrayList<Display> displayList = new ArrayList<Display>();
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; i<dCount && displayList.size()>0; 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<Object>() {
- 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<Object>() {
- 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; i<sCount && screenList.size()>0; 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<WindowImpl> windowList = new ArrayList<WindowImpl>();
+
+ 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; i<wCount && windowList.size()>0; 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 <code>value</code> is <code>true</code>, otherwise clears preservation flag.
+ * @param value <code>true</code> 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()) {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
index 0756399c1..a876b5c96 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
@@ -90,6 +90,8 @@ public class TestGearsES2NEWT extends UITestCase {
static boolean mainRun = false;
static boolean exclusiveContext = false;
static boolean useAnimator = true;
+ static enum SysExit { none, testExit, testError, displayExit, displayError };
+ static SysExit sysExit = SysExit.none;
@BeforeClass
public static void initClass() {
@@ -272,6 +274,36 @@ public class TestGearsES2NEWT extends UITestCase {
Assert.assertEquals(exclusiveContext ? animator.getThread() : null, glWindow.getExclusiveContextThread());
}
+ if( SysExit.displayError == sysExit || SysExit.displayExit == sysExit ) {
+ glWindow.addGLEventListener(new GLEventListener() {
+
+ @Override
+ public void init(GLAutoDrawable drawable) {}
+
+ @Override
+ public void dispose(GLAutoDrawable drawable) { }
+
+ @Override
+ public void display(GLAutoDrawable drawable) {
+ final GLAnimatorControl anim = drawable.getAnimator();
+ if( null != anim && anim.isAnimating() ) {
+ if( anim.getTotalFPSDuration() >= duration/2 ) {
+ if( SysExit.displayError == sysExit ) {
+ throw new Error("test error send from GLEventListener");
+ } else if ( SysExit.displayExit == sysExit ) {
+ System.err.println("exit(0) send from GLEventListener");
+ System.exit(0);
+ }
+ }
+ } else {
+ System.exit(0);
+ }
+ }
+ @Override
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }
+ });
+ }
+
glWindow.setVisible(true);
if( useAnimator ) {
animator.setUpdateFPSFrames(60, showFPS ? System.err : null);
@@ -296,6 +328,16 @@ public class TestGearsES2NEWT extends UITestCase {
while(!quitAdapter.shouldQuit() && t1-t0<duration) {
Thread.sleep(100);
t1 = System.currentTimeMillis();
+ if( t1-t0 >= duration/2 ) {
+ if( SysExit.testError == sysExit || SysExit.testExit == sysExit ) {
+ if( SysExit.testError == sysExit ) {
+ throw new Error("test error send from test thread");
+ } else if ( SysExit.testExit == sysExit ) {
+ System.err.println("exit(0) send from test thread");
+ System.exit(0);
+ }
+ }
+ }
}
if( useAnimator ) {
@@ -429,6 +471,9 @@ public class TestGearsES2NEWT extends UITestCase {
loops = MiscUtils.atoi(args[i], 1);
} else if(args[i].equals("-loop-shutdown")) {
loop_shutdown = true;
+ } else if(args[i].equals("-sysExit")) {
+ i++;
+ sysExit = SysExit.valueOf(args[i]);
}
}
wsize = new Dimension(w, h);
@@ -458,6 +503,7 @@ public class TestGearsES2NEWT extends UITestCase {
System.err.println("swapInterval "+swapInterval);
System.err.println("exclusiveContext "+exclusiveContext);
System.err.println("useAnimator "+useAnimator);
+ System.err.println("sysExitWithin "+sysExit);
if(waitForKey) {
UITestCase.waitForKey("Start");