aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-08-06 05:59:08 +0200
committerSven Gothel <[email protected]>2014-08-06 05:59:08 +0200
commit88eef9e4eae8e63762252f1d11bca2bd0fde809b (patch)
tree1a70cb2f54ada3a654928ec30432d5fca6ef822e /src
parent07a4801f3b5bfd4fba9a1a4a542ce2f2eae4396a (diff)
Bug 1039 - Specify behavior of GLEventListener Exceptions occurring while GLAutoDrawable processing [part-3]
Add GLAnimatorControl.UncaughtGLAnimatorExceptionHandler interface to optionally handle uncaught exception within an animator thread by the user. Implementation also requires to flush all enqueued GLRunnable instances via GLAutoDrawable.invoked(..) in case such exception occurs. Hence 'GLAutoDrawable.flushGLRunnables()' has been added. Only subsequent exceptions, which cannot be thrown are dumped to System.stderr. +++ Handling of exceptions during dispose() Exception in NEWT's disposeGL*() are also caught and re-thrown after the NEWT window has been destroyed in WindowImpl.destroyAction: - GLEventListener.dispose(..) - GLDrawableHelper.disposeAllGLEventListener(..) - GLDrawableHelper.disposeGL(..) - GLAutoDrawableBase.destroyImplInLock(..) - GLWindow.GLLifecycleHook.destroyActionInLock(..) - WindowImpl.destroyAction on NEWT-EDT - WindowImpl.destroy Further more, exceptions occuring in native windowing toolkit triggered destroy() are ignored: - GLAutoDrawableBase.defaultWindowDestroyNotifyOp(..) It has to be seen whether such exception handling for dispose() shall be added to AWT/SWT. +++ TestGLException01NEWT covers all GLEventListener exception cases on-thread and off-thread (via animator). +++
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java5
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java12
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Animator.java29
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java76
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java11
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java72
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAnimatorControl.java52
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java17
-rw-r--r--src/jogl/classes/javax/media/opengl/GLDrawable.java1
-rw-r--r--src/jogl/classes/javax/media/opengl/GLException.java10
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java5
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java5
-rw-r--r--src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java13
-rw-r--r--src/jogl/classes/jogamp/opengl/GLDrawableHelper.java23
-rw-r--r--src/jogl/classes/jogamp/opengl/GLRunnableTask.java2
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java14
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLException01NEWT.java259
17 files changed, 502 insertions, 104 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
index c409bb253..e33ceeefb 100644
--- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java
@@ -789,6 +789,11 @@ public class GLCanvas extends Canvas implements GLAutoDrawable, GLSharedContextS
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public void setAnimator(final GLAnimatorControl arg0) throws GLException {
helper.setAnimator(arg0);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
index 496fb88c0..62df3faca 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
@@ -41,12 +41,14 @@ import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+
import javax.swing.JComponent;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
-
import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException;
+
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
up this behavior if desired. */
@@ -61,7 +63,7 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
@Override
public void display(final ArrayList<GLAutoDrawable> drawables,
final boolean ignoreExceptions,
- final boolean printExceptions) {
+ final boolean printExceptions) throws UncaughtAnimatorException {
for (int i=0; i<drawables.size(); i++) {
final GLAutoDrawable drawable = drawables.get(i);
if (drawable instanceof JComponent) {
@@ -73,13 +75,13 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
} else {
try {
drawable.display();
- } catch (final RuntimeException e) {
+ } catch (final Throwable t) {
if (ignoreExceptions) {
if (printExceptions) {
- e.printStackTrace();
+ t.printStackTrace();
}
} else {
- throw(e);
+ throw new UncaughtAnimatorException(drawable, t);
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 634e83353..d9a957199 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -132,7 +132,7 @@ public class Animator extends AnimatorBase {
@Override
public void run() {
- GLException displayCaught = null;
+ UncaughtAnimatorException displayCaught = null;
try {
synchronized (Animator.this) {
@@ -161,9 +161,9 @@ public class Animator extends AnimatorBase {
ectCleared = true;
setDrawablesExclCtxState(false);
try {
- display(); // propagate exclusive change!
- } catch (final Throwable t) {
- displayCaught = GLException.newGLException(t);
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
stopIssued = true;
isAnimating = false;
break; // end pause loop
@@ -189,15 +189,15 @@ public class Animator extends AnimatorBase {
// Resume from pause or drawablesEmpty,
// implies !pauseIssued and !drawablesEmpty
isAnimating = true;
- setDrawablesExclCtxState(exclusiveContext);
+ setDrawablesExclCtxState(exclusiveContext); // may re-enable exclusive context
Animator.this.notifyAll();
}
} // sync Animator.this
if (!stopIssued) {
try {
display();
- } catch (final Throwable t) {
- displayCaught = GLException.newGLException(t);
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
stopIssued = true;
isAnimating = false;
break; // end animation loop
@@ -216,14 +216,13 @@ public class Animator extends AnimatorBase {
} finally {
if( exclusiveContext && !drawablesEmpty ) {
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
try {
- display(); // propagate exclusive change!
- } catch (final Throwable t) {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
if( null == displayCaught ) {
- displayCaught = GLException.newGLException(t);
+ displayCaught = dre;
} else {
- GLException.newGLException(t).printStackTrace();
+ dre.printStackTrace();
}
}
}
@@ -237,12 +236,12 @@ public class Animator extends AnimatorBase {
}
stopIssued = false;
pauseIssued = false;
- animThread = null;
isAnimating = false;
- Animator.this.notifyAll();
if( null != displayCaught ) {
- throw displayCaught;
+ handleUncaughtException(displayCaught);
}
+ animThread = null;
+ Animator.this.notifyAll();
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index a5bdb9350..ed23a78ba 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -67,8 +67,25 @@ public abstract class AnimatorBase implements GLAnimatorControl {
*/
public static final int MODE_EXPECT_AWT_RENDERING_THREAD = 1 << 0;
- public interface AnimatorImpl {
- void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions);
+
+ @SuppressWarnings("serial")
+ public static class UncaughtAnimatorException extends RuntimeException {
+ final GLAutoDrawable drawable;
+ public UncaughtAnimatorException(final GLAutoDrawable drawable, final Throwable cause) {
+ super(cause);
+ this.drawable = drawable;
+ }
+ public final GLAutoDrawable getGLAutoDrawable() { return drawable; }
+ }
+
+ public static interface AnimatorImpl {
+ /**
+ * @param drawables
+ * @param ignoreExceptions
+ * @param printExceptions
+ * @throws UncaughtAnimatorException as caused by {@link GLAutoDrawable#display()}
+ */
+ void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions) throws UncaughtAnimatorException;
boolean blockUntilDone(Thread thread);
}
@@ -83,6 +100,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
protected boolean printExceptions;
protected boolean exclusiveContext;
protected Thread userExclusiveContextThread;
+ protected UncaughtGLAnimatorExceptionHandler uncaughtExceptionHandler;
protected FPSCounterImpl fpsCounter = new FPSCounterImpl();
private final static Class<?> awtAnimatorImplClazz;
@@ -313,11 +331,16 @@ public abstract class AnimatorBase implements GLAnimatorControl {
}
}
final Thread dECT = enable ? ( null != _exclusiveContextThread ? _exclusiveContextThread : animThread ) : null ;
+ UncaughtAnimatorException displayCaught = null;
if( propagateState ) {
setDrawablesExclCtxState(enable);
if( !enable ) {
if( Thread.currentThread() == getThread() || Thread.currentThread() == _exclusiveContextThread ) {
- display();
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
+ }
} else {
final boolean resumed = isAnimating() ? false : resume();
int counter = 10;
@@ -338,6 +361,13 @@ public abstract class AnimatorBase implements GLAnimatorControl {
}
if(DEBUG) {
System.err.println("AnimatorBase.setExclusiveContextThread: all-GLAD Ok: "+validateDrawablesExclCtxState(dECT)+", "+this);
+ if( null != displayCaught ) {
+ System.err.println("AnimatorBase.setExclusiveContextThread: caught: "+displayCaught.getMessage());
+ displayCaught.printStackTrace();
+ }
+ }
+ if( null != displayCaught ) {
+ throw displayCaught;
}
return oldExclusiveContext;
}
@@ -412,7 +442,7 @@ public abstract class AnimatorBase implements GLAnimatorControl {
this to get the most optimized painting behavior for the set of
components this Animator manages, in particular when multiple
lightweight widgets are continually being redrawn. */
- protected final void display() {
+ protected final void display() throws UncaughtAnimatorException {
impl.display(drawables, ignoreExceptions, printExceptions);
fpsCounter.tickFPS();
}
@@ -482,7 +512,43 @@ public abstract class AnimatorBase implements GLAnimatorControl {
this.printExceptions = printExceptions;
}
- protected interface Condition {
+ @Override
+ public final UncaughtGLAnimatorExceptionHandler getUncaughtExceptionHandler() {
+ return uncaughtExceptionHandler;
+ }
+
+ @Override
+ public final void setUncaughtExceptionHandler(final UncaughtGLAnimatorExceptionHandler handler) {
+ uncaughtExceptionHandler = handler;
+ }
+
+ /**
+ * Should be called in case of an uncaught exception
+ * from within the animator thread to flush all animator
+ */
+ protected final synchronized void handleUncaughtException(final UncaughtAnimatorException ue) {
+ if( null != uncaughtExceptionHandler ) {
+ try {
+ uncaughtExceptionHandler.uncaughtException(this, ue.getGLAutoDrawable(), ue.getCause());
+ } catch (final Throwable t) { /* ignore intentionally */ }
+ flushGLRunnables();
+ } else {
+ flushGLRunnables();
+ throw ue;
+ }
+ }
+
+ /**
+ * Should be called in case of an uncaught exception
+ * from within the animator thread to flush all animator
+ */
+ protected final synchronized void flushGLRunnables() {
+ for (int i=0; i<drawables.size(); i++) {
+ drawables.get(i).flushGLRunnables();
+ }
+ }
+
+ protected static interface Condition {
/**
* @return true if branching (continue waiting, action), otherwise false
*/
diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
index 7fa4011f8..6b1485a6a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java
@@ -34,8 +34,11 @@
package com.jogamp.opengl.util;
import java.util.ArrayList;
+
import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException;
+
/** Abstraction to factor out AWT dependencies from the Animator's
implementation in a way that still allows the FPSAnimator to pick
up this behavior if desired. */
@@ -44,18 +47,18 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl {
@Override
public void display(final ArrayList<GLAutoDrawable> drawables,
final boolean ignoreExceptions,
- final boolean printExceptions) {
+ final boolean printExceptions) throws UncaughtAnimatorException {
for (int i=0; i<drawables.size(); i++) {
final GLAutoDrawable drawable = drawables.get(i);
try {
drawable.display();
- } catch (final RuntimeException e) {
+ } catch (final Throwable t) {
if (ignoreExceptions) {
if (printExceptions) {
- e.printStackTrace();
+ t.printStackTrace();
}
} else {
- throw(e);
+ throw new UncaughtAnimatorException(drawable, t);
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
index 746b642c2..9ae880414 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java
@@ -148,6 +148,8 @@ public class FPSAnimator extends AnimatorBase {
@Override
public void run() {
+ UncaughtAnimatorException displayCaught = null;
+
if( justStarted ) {
justStarted = false;
synchronized (FPSAnimator.this) {
@@ -160,7 +162,7 @@ public class FPSAnimator extends AnimatorBase {
shouldRun = false; // isAnimating:=false @ pause below
} else {
shouldRun = true;
- setDrawablesExclCtxState(exclusiveContext);
+ setDrawablesExclCtxState(exclusiveContext); // may re-enable exclusive context
FPSAnimator.this.notifyAll();
}
if(DEBUG) {
@@ -168,46 +170,76 @@ public class FPSAnimator extends AnimatorBase {
}
}
}
- if( shouldRun ) {
- display();
- } else if( shouldStop ) { // STOP
+ if( shouldRun && !shouldStop ) { // RUN
+ try {
+ display();
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
+ shouldRun = false;
+ shouldStop = true;
+ }
+ } else if( !shouldRun && !shouldStop ) { // PAUSE
if(DEBUG) {
- System.err.println("FPSAnimator P4: "+alreadyStopped+", "+ Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator pausing: "+alreadyPaused+", "+ Thread.currentThread() + ": " + toString());
}
this.cancel();
- if( !alreadyStopped ) {
- alreadyStopped = true;
+ if( !alreadyPaused ) { // PAUSE
+ alreadyPaused = true;
if( exclusiveContext && !drawablesEmpty ) {
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ displayCaught = dre;
+ shouldRun = false;
+ shouldStop = true;
+ }
}
- synchronized (FPSAnimator.this) {
- if(DEBUG) {
- System.err.println("FPSAnimator stop " + Thread.currentThread() + ": " + toString());
+ if( null == displayCaught ) {
+ synchronized (FPSAnimator.this) {
+ if(DEBUG) {
+ System.err.println("FPSAnimator pause " + Thread.currentThread() + ": " + toString());
+ }
+ isAnimating = false;
+ FPSAnimator.this.notifyAll();
}
- animThread = null;
- isAnimating = false;
- FPSAnimator.this.notifyAll();
}
}
- } else {
+ }
+ if( shouldStop ) { // STOP
if(DEBUG) {
- System.err.println("FPSAnimator P5: "+alreadyPaused+", "+ Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator stopping: "+alreadyStopped+", "+ Thread.currentThread() + ": " + toString());
}
this.cancel();
- if( !alreadyPaused ) { // PAUSE
- alreadyPaused = true;
+ if( !alreadyStopped ) {
+ alreadyStopped = true;
if( exclusiveContext && !drawablesEmpty ) {
setDrawablesExclCtxState(false);
- display(); // propagate exclusive change!
+ try {
+ display(); // propagate exclusive context -> off!
+ } catch (final UncaughtAnimatorException dre) {
+ if( null == displayCaught ) {
+ displayCaught = dre;
+ } else {
+ dre.printStackTrace();
+ }
+ }
}
synchronized (FPSAnimator.this) {
if(DEBUG) {
- System.err.println("FPSAnimator pause " + Thread.currentThread() + ": " + toString());
+ System.err.println("FPSAnimator stop " + Thread.currentThread() + ": " + toString());
+ if( null != displayCaught ) {
+ System.err.println("AnimatorBase.setExclusiveContextThread: caught: "+displayCaught.getMessage());
+ displayCaught.printStackTrace();
+ }
}
isAnimating = false;
+ if( null != displayCaught ) {
+ handleUncaughtException(displayCaught);
+ }
+ animThread = null;
FPSAnimator.this.notifyAll();
}
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
index 827145654..50f7e9bbb 100644
--- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
+++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java
@@ -33,6 +33,38 @@ package javax.media.opengl;
* which implementation may drive a {@link javax.media.opengl.GLAutoDrawable} animation.
*/
public interface GLAnimatorControl extends FPSCounter {
+ /**
+ * A {@link GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler) registered}
+ * {@link UncaughtGLAnimatorExceptionHandler} instance is invoked when an {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @see #uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler)
+ * @since 2.2
+ */
+ public static interface UncaughtGLAnimatorExceptionHandler {
+ /**
+ * Method invoked when the given {@link GLAnimatorControl} is {@link GLAnimatorControl#stop() stopped} due to the
+ * given uncaught exception happened on the given {@link GLAutoDrawable}.
+ * <p>
+ * The animator thread can still be retrieved via {@link GLAnimatorControl#getThread()}.
+ * </p>
+ * <p>
+ * All {@link GLAnimatorControl} states already reflect its stopped state.
+ * </p>
+ * <p>
+ * After this handler method is called, the {@link GLAnimatorControl} is stopped.
+ * </p>
+ * <p>
+ * Any exception thrown by this method will be ignored.
+ * </p>
+ * @param animator the {@link GLAnimatorControl}
+ * @param drawable the causing {@link GLAutoDrawable}
+ * @param cause the uncaught exception
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler)
+ * @since 2.2
+ */
+ void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause);
+ }
/**
* Indicates whether this animator has been {@link #start() started}.
@@ -181,4 +213,24 @@ public interface GLAnimatorControl extends FPSCounter {
* @throws IllegalArgumentException if drawable was not added to this animator
*/
void remove(GLAutoDrawable drawable);
+
+ /**
+ * Returns the {@link UncaughtGLAnimatorExceptionHandler} invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * <p>
+ * Default is <code>null</code>.
+ * </p>
+ * @since 2.2
+ */
+ UncaughtGLAnimatorExceptionHandler getUncaughtExceptionHandler();
+
+ /**
+ * Set the handler invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @param handler the {@link UncaughtGLAnimatorExceptionHandler} to use as this {@link GLAnimatorControl animator}'s uncaught exception
+ * handler. Pass <code>null</code> to unset the handler.
+ * @see UncaughtGLAnimatorExceptionHandler#uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @since 2.2
+ */
+ void setUncaughtExceptionHandler(final UncaughtGLAnimatorExceptionHandler handler);
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 5745e197f..bded88d20 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -229,6 +229,7 @@ public interface GLAutoDrawable extends GLDrawable {
/**
* Returns true if all added {@link GLEventListener} are initialized, otherwise false.
+ * @since 2.2
*/
boolean areAllGLEventListenerInitialized();
@@ -458,6 +459,7 @@ public interface GLAutoDrawable extends GLDrawable {
* @see #display()
* @see GLRunnable
* @see #invoke(boolean, List)
+ * @see #flushGLRunnables()
*/
public boolean invoke(boolean wait, GLRunnable glRunnable) throws IllegalStateException ;
@@ -469,9 +471,22 @@ public interface GLAutoDrawable extends GLDrawable {
* @return <code>true</code> if the {@link GLRunnable}s has been processed or queued, otherwise <code>false</code>.
* @throws IllegalStateException in case of a detected deadlock situation ahead, see {@link #invoke(boolean, GLRunnable)}.
* @see #invoke(boolean, GLRunnable)
+ * @see #flushGLRunnables()
*/
public boolean invoke(boolean wait, List<GLRunnable> glRunnables) throws IllegalStateException;
+ /**
+ * Flushes all {@link #invoke(boolean, GLRunnable) enqueued} {@link GLRunnable} of this {@link GLAutoDrawable}
+ * including notifying waiting executor.
+ * <p>
+ * The executor which might have been blocked until notified
+ * will be unblocked and all tasks removed from the queue.
+ * </p>
+ * @see #invoke(boolean, GLRunnable)
+ * @since 2.2
+ */
+ public void flushGLRunnables();
+
/** Destroys all resources associated with this GLAutoDrawable,
inclusive the GLContext.
If a window is attached to it's implementation, it shall be closed.
@@ -602,6 +617,7 @@ public interface GLAutoDrawable extends GLDrawable {
* <p>
* See <a href="#locking">GLAutoDrawable Locking</a>.
* </p>
+ * @since 2.2
*/
public RecursiveLock getUpstreamLock();
@@ -613,6 +629,7 @@ public interface GLAutoDrawable extends GLDrawable {
* whether {@link #display()} performs the OpenGL commands on the current thread directly
* or spawns them on the dedicated OpenGL thread.
* </p>
+ * @since 2.2
*/
public boolean isThreadGLCapable();
diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java
index ac8644640..7ed057ea4 100644
--- a/src/jogl/classes/javax/media/opengl/GLDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java
@@ -201,6 +201,7 @@ public interface GLDrawable extends NativeSurfaceHolder {
</p>
@return The immutable queried instance.
@see #getChosenGLCapabilities()
+ @since 2.2
*/
public GLCapabilitiesImmutable getRequestedGLCapabilities();
diff --git a/src/jogl/classes/javax/media/opengl/GLException.java b/src/jogl/classes/javax/media/opengl/GLException.java
index dff9b9dad..3f76a6299 100644
--- a/src/jogl/classes/javax/media/opengl/GLException.java
+++ b/src/jogl/classes/javax/media/opengl/GLException.java
@@ -69,14 +69,18 @@ public class GLException extends RuntimeException {
/**
* Constructs a GLException object with the specified root
* cause with a decorating message including the current thread name.
+ * @since 2.2
*/
public static GLException newGLException(final Throwable t) {
return new GLException("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName(), t);
}
- /** Dumps a Throwable in a decorating message including the current thread name, and stack trace. */
- public static void dumpThrowable(final Throwable t) {
- System.err.println("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
+ /**
+ * Dumps a Throwable in a decorating message including the current thread name, and stack trace.
+ * @since 2.2
+ */
+ public static void dumpThrowable(final String additionalDescr, final Throwable t) {
+ System.err.println("Caught "+additionalDescr+" "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
t.printStackTrace();
}
}
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index ca5cf0e45..dba1dbc04 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -1059,6 +1059,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) {
final RecursiveLock _lock = lock;
_lock.lock();
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index d08839b7f..1682c6d2a 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -958,6 +958,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public GLContext createContext(final GLContext shareWith) {
final Backend b = backend;
if ( null == b ) {
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
index e1cd59a04..6e6aaf58d 100644
--- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
+++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java
@@ -279,7 +279,13 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe
shallClose = true;
}
if( shallClose ) {
- destroyAvoidAwareOfLocking();
+ try {
+ destroyAvoidAwareOfLocking();
+ } catch( final Throwable t ) {
+ // Intentionally catch and ignore exception,
+ // so the destroy mechanism of the native windowing system is not corrupted!
+ GLException.dumpThrowable("ignored", t);
+ }
}
}
@@ -602,6 +608,11 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe
}
@Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
public final void setAutoSwapBufferMode(final boolean enable) {
helper.setAutoSwapBufferMode(enable);
}
diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
index 945ca5479..f91e1bdba 100644
--- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
+++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java
@@ -526,8 +526,9 @@ public class GLDrawableHelper {
} catch (final Throwable t) {
if( null == firstCaught ) {
firstCaught = t;
+ } else {
+ GLException.dumpThrowable("subsequent", t);
}
- GLException.dumpThrowable(t);
}
disposeCount++;
}
@@ -541,8 +542,9 @@ public class GLDrawableHelper {
} catch (final Throwable t) {
if( null == firstCaught ) {
firstCaught = t;
+ } else {
+ GLException.dumpThrowable("subsequent", t);
}
- GLException.dumpThrowable(t);
}
listenersToBeInit.add(listener);
disposeCount++;
@@ -1125,8 +1127,7 @@ public class GLDrawableHelper {
final Runnable initAction) {
if(null==context) {
if (DEBUG) {
- final Exception e = new GLException("Info: GLDrawableHelper " + this + ".invokeGL(): NULL GLContext");
- GLException.dumpThrowable(e);
+ GLException.dumpThrowable("informal", new GLException("Info: GLDrawableHelper " + this + ".invokeGL(): NULL GLContext"));
}
return;
}
@@ -1196,7 +1197,6 @@ public class GLDrawableHelper {
forceNativeRelease(context);
}
} catch (final Throwable t) {
- GLException.dumpThrowable(t);
contextCloseCaught = t;
}
flushGLRunnables(); // always flush GLRunnables at dispose
@@ -1208,6 +1208,9 @@ public class GLDrawableHelper {
}
}
if( null != disposeCaught ) {
+ if( null != contextCloseCaught ) {
+ GLException.dumpThrowable("subsequent", contextCloseCaught);
+ }
throw disposeCaught;
}
if( null != contextCloseCaught ) {
@@ -1283,7 +1286,6 @@ public class GLDrawableHelper {
drawable.swapBuffers();
}
} catch (final Throwable t) {
- GLException.dumpThrowable(t);
glEventListenerCaught = t;
} finally {
if( _releaseExclusiveThread ) {
@@ -1296,7 +1298,6 @@ public class GLDrawableHelper {
try {
context.release();
} catch (final Throwable t) {
- GLException.dumpThrowable(t);
contextReleaseCaught = t;
}
}
@@ -1311,6 +1312,9 @@ public class GLDrawableHelper {
}
if( null != glEventListenerCaught ) {
flushGLRunnables();
+ if( null != contextReleaseCaught ) {
+ GLException.dumpThrowable("subsequent", contextReleaseCaught);
+ }
throw GLException.newGLException(glEventListenerCaught);
}
if( null != contextReleaseCaught ) {
@@ -1401,7 +1405,6 @@ public class GLDrawableHelper {
tdS = tdX - tdS; // swapBuffers
}
} catch (final Throwable t) {
- GLException.dumpThrowable(t);
glEventListenerCaught = t;
} finally {
if( _releaseExclusiveThread ) {
@@ -1416,7 +1419,6 @@ public class GLDrawableHelper {
context.release();
ctxReleased = true;
} catch (final Throwable t) {
- GLException.dumpThrowable(t);
contextReleaseCaught = t;
}
}
@@ -1432,6 +1434,9 @@ public class GLDrawableHelper {
}
if( null != glEventListenerCaught ) {
flushGLRunnables();
+ if( null != contextReleaseCaught ) {
+ GLException.dumpThrowable("subsequent", contextReleaseCaught);
+ }
throw GLException.newGLException(glEventListenerCaught);
}
if( null != contextReleaseCaught ) {
diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
index 0ceef6bf7..ca1c1869e 100644
--- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
+++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java
@@ -90,8 +90,10 @@ public class GLRunnableTask implements GLRunnable {
/**
* Simply flush this task and notify a waiting executor.
+ * <p>
* The executor which might have been blocked until notified
* will be unblocked and the task removed from the queue.
+ * </p>
*
* @see #isFlushed()
* @see #isInQueue()
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index ca6ffa18b..b62628962 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -1104,6 +1104,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=lifecycleHook) {
lifecycleHook.destroyActionPreLock();
}
+ RuntimeException lifecycleCaughtInLock = null;
final RecursiveLock _lock = windowLock;
_lock.lock();
try {
@@ -1133,7 +1134,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(null!=lifecycleHook) {
// send synced destroy notification for proper cleanup, eg GLWindow/OpenGL
- lifecycleHook.destroyActionInLock();
+ try {
+ lifecycleHook.destroyActionInLock();
+ } catch (final RuntimeException re) {
+ lifecycleCaughtInLock = re;
+ }
}
if( isNativeValid() ) {
@@ -1156,6 +1161,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(DEBUG_IMPLEMENTATION) {
System.err.println("Window.destroy() END "+getThreadName()/*+", "+WindowImpl.this*/);
+ if( null != lifecycleCaughtInLock ) {
+ System.err.println("Window.destroy() caught: "+lifecycleCaughtInLock.getMessage());
+ lifecycleCaughtInLock.printStackTrace();
+ }
+ }
+ if( null != lifecycleCaughtInLock ) {
+ throw lifecycleCaughtInLock;
}
} finally {
// update states before release window lock
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLException01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLException01NEWT.java
index a2dca2dda..83d5e9cc5 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLException01NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLException01NEWT.java
@@ -28,6 +28,8 @@
package com.jogamp.opengl.test.junit.jogl.acore;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.jogamp.newt.opengl.GLWindow;
@@ -36,10 +38,12 @@ import com.jogamp.opengl.test.junit.util.UITestCase;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
+import javax.media.opengl.GLRunnable;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -52,6 +56,19 @@ public class TestGLException01NEWT extends UITestCase {
static GLProfile glp;
static int width, height;
+ @SuppressWarnings("serial")
+ static class AnimException extends RuntimeException {
+ final Thread thread;
+ final GLAnimatorControl animator;
+ final GLAutoDrawable drawable;
+ public AnimException(final Thread thread, final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) {
+ super(cause);
+ this.thread = thread;
+ this.animator = animator;
+ this.drawable = drawable;
+ }
+ }
+
@BeforeClass
public static void initClass() {
glp = GLProfile.getGL2ES2();
@@ -67,72 +84,129 @@ public class TestGLException01NEWT extends UITestCase {
protected void runTestGL(final GLCapabilities caps, final boolean onThread,
final boolean throwInInit, final boolean throwInDisplay,
- final boolean throwInReshape, final boolean throwInDispose) throws InterruptedException {
+ final boolean throwInReshape, final boolean throwInInvoke,
+ final boolean throwInDispose) throws InterruptedException {
final GLWindow glWindow = GLWindow.create(caps);
Assert.assertNotNull(glWindow);
- glWindow.setTitle("NEWT Exception Test");
+ glWindow.setTitle(getTestMethodName());
final GearsES2 demo1 = new GearsES2();
demo1.setVerbose(false);
glWindow.addGLEventListener(demo1);
- final AtomicInteger initCount = new AtomicInteger();
- final AtomicInteger disposeCount = new AtomicInteger();
- final AtomicInteger displayCount = new AtomicInteger();
- final AtomicInteger reshapeCount = new AtomicInteger();
+ final AtomicInteger cleanInitCount = new AtomicInteger();
+ final AtomicInteger cleanDisposeCount = new AtomicInteger();
+ final AtomicInteger cleanDisplayCount = new AtomicInteger();
+ final AtomicInteger cleanReshapeCount = new AtomicInteger();
+ final AtomicInteger cleanInvokeCount = new AtomicInteger();
+ final AtomicInteger allInitCount = new AtomicInteger();
+ final AtomicInteger allDisposeCount = new AtomicInteger();
+ final AtomicInteger allDisplayCount = new AtomicInteger();
+ final AtomicInteger allReshapeCount = new AtomicInteger();
+ final AtomicInteger allInvokeCount = new AtomicInteger();
final AtomicInteger exceptionSent = new AtomicInteger();
glWindow.addGLEventListener(new GLEventListener() {
@Override
public void init(final GLAutoDrawable drawable) {
- if( throwInInit && 0 == exceptionSent.get() ) {
+ if( throwInInit ) {
exceptionSent.incrementAndGet();
- throw new RuntimeException("Injected GLEventListener exception in init");
+ throw new RuntimeException("<Injected GLEventListener exception in init: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
}
}
@Override
public void dispose(final GLAutoDrawable drawable) {
- if( throwInDispose && 0 == exceptionSent.get() ) {
+ if( throwInDispose ) {
exceptionSent.incrementAndGet();
- throw new RuntimeException("Injected GLEventListener exception in dispose");
+ throw new RuntimeException("<Injected GLEventListener exception in dispose: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
}
}
@Override
public void display(final GLAutoDrawable drawable) {
- if( throwInDisplay && 0 == exceptionSent.get() ) {
+ if( throwInDisplay ) {
exceptionSent.incrementAndGet();
- throw new RuntimeException("Injected GLEventListener exception in display");
+ throw new RuntimeException("<Injected GLEventListener exception in display: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
}
}
@Override
public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
- if( throwInReshape && 0 == exceptionSent.get() ) {
+ if( throwInReshape ) {
exceptionSent.incrementAndGet();
- throw new RuntimeException("Injected GLEventListener exception in reshape");
+ throw new RuntimeException("<Injected GLEventListener exception in reshape: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
}
}
});
+ final GLRunnable glRunnableInject = new GLRunnable() {
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ if( throwInInvoke ) {
+ exceptionSent.incrementAndGet();
+ throw new RuntimeException("<Injected GLEventListener exception in invoke: #"+exceptionSent.get()+" on thread "+Thread.currentThread().getName()+">");
+ }
+ return true;
+ }
+ };
+ final GLRunnable glRunnableCount = new GLRunnable() {
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ if( 0 == exceptionSent.get() ) {
+ cleanInvokeCount.incrementAndGet();
+ }
+ allInvokeCount.incrementAndGet();
+ return true;
+ }
+ };
+
glWindow.addGLEventListener(new GLEventListener() {
@Override
public void init(final GLAutoDrawable drawable) {
- initCount.incrementAndGet();
+ if( 0 == exceptionSent.get() ) {
+ cleanInitCount.incrementAndGet();
+ }
+ allInitCount.incrementAndGet();
}
@Override
public void dispose(final GLAutoDrawable drawable) {
- disposeCount.incrementAndGet();
+ if( 0 == exceptionSent.get() ) {
+ cleanDisposeCount.incrementAndGet();
+ }
+ allDisposeCount.incrementAndGet();
}
@Override
public void display(final GLAutoDrawable drawable) {
- displayCount.incrementAndGet();
+ if( 0 == exceptionSent.get() ) {
+ cleanDisplayCount.incrementAndGet();
+ }
+ allDisplayCount.incrementAndGet();
}
@Override
public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
- reshapeCount.incrementAndGet();
+ if( 0 == exceptionSent.get() ) {
+ cleanReshapeCount.incrementAndGet();
+ }
+ allReshapeCount.incrementAndGet();
}
});
- RuntimeException execptionAtInitReshapeDisplay = null;
- RuntimeException execptionAtDispose = null;
+ RuntimeException exceptionAtInitReshapeDisplay = null;
+ RuntimeException exceptionAtInvoke = null;
+ RuntimeException exceptionAtDispose = null;
+ final List<AnimException> exceptionsAtGLAnimatorControl = new ArrayList<AnimException>();
+ final GLAnimatorControl.UncaughtGLAnimatorExceptionHandler uncaughtGLAnimatorExceptionHandler;
- final Animator animator = !onThread ? new Animator(glWindow) : null;
+ final Animator animator;
+ if( onThread ) {
+ animator = null;
+ uncaughtGLAnimatorExceptionHandler = null;
+ } else {
+ animator = new Animator(glWindow);
+ uncaughtGLAnimatorExceptionHandler = new GLAnimatorControl.UncaughtGLAnimatorExceptionHandler() {
+ @Override
+ public void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause) {
+ final AnimException ae = new AnimException(animator.getThread(), animator, drawable, cause);
+ exceptionsAtGLAnimatorControl.add(ae);
+ dumpThrowable(ae);
+ } };
+ animator.setUncaughtExceptionHandler(uncaughtGLAnimatorExceptionHandler);
+ }
glWindow.setSize(width, height);
@@ -143,7 +217,15 @@ public class TestGLException01NEWT extends UITestCase {
try {
glWindow.setVisible(true);
} catch (final RuntimeException re) {
- execptionAtInitReshapeDisplay = re;
+ exceptionAtInitReshapeDisplay = re;
+ dumpThrowable(re);
+ }
+
+ try {
+ glWindow.invoke(true, glRunnableInject);
+ glWindow.invoke(true, glRunnableCount);
+ } catch (final RuntimeException re) {
+ exceptionAtInvoke = re;
dumpThrowable(re);
}
@@ -154,7 +236,7 @@ public class TestGLException01NEWT extends UITestCase {
try {
glWindow.display();
} catch (final RuntimeException re) {
- execptionAtInitReshapeDisplay = re;
+ exceptionAtInitReshapeDisplay = re;
dumpThrowable(re);
}
}
@@ -168,23 +250,81 @@ public class TestGLException01NEWT extends UITestCase {
try {
glWindow.destroy();
} catch (final RuntimeException re) {
- execptionAtDispose = re;
+ exceptionAtDispose = re;
dumpThrowable(re);
}
- if( throwInInit || throwInReshape || throwInDisplay || throwInDispose ) {
- Assert.assertEquals("Not one exception sent", 1, exceptionSent.get());
- if( throwInInit ) {
- Assert.assertNotNull("No exception forwarded from init", execptionAtInitReshapeDisplay);
- }
- if( throwInReshape ) {
- Assert.assertNotNull("No exception forwarded from reshape", execptionAtInitReshapeDisplay);
- }
- if( throwInDisplay ) {
- Assert.assertNotNull("No exception forwarded from display", execptionAtInitReshapeDisplay);
+ final boolean onAnimThread = !onThread && !throwInDispose; /** dispose happens on [AWT|NEWT] EDT, not on animator thread! */
+
+ System.err.println("This-Thread : "+onThread);
+ System.err.println("Anim-Thread : "+onAnimThread);
+ System.err.println("ExceptionSent : "+exceptionSent.get());
+ System.err.println("Exception @ Init/Reshape/Display: "+(null != exceptionAtInitReshapeDisplay));
+ System.err.println("Exception @ Invoke : "+(null != exceptionAtInvoke));
+ System.err.println("Exception @ Dispose : "+(null != exceptionAtDispose));
+ System.err.println("Exception @ GLAnimatorControl : "+exceptionsAtGLAnimatorControl.size());
+ System.err.println("Init Count : "+cleanInitCount.get()+" / "+allInitCount.get());
+ System.err.println("Reshape Count : "+cleanReshapeCount.get()+" / "+allReshapeCount.get());
+ System.err.println("Display Count : "+cleanDisplayCount.get()+" / "+allDisplayCount.get());
+ System.err.println("Invoke Count : "+cleanInvokeCount.get()+" / "+allInvokeCount.get());
+ System.err.println("Dispose Count : "+cleanDisposeCount.get()+" / "+allDisposeCount.get());
+
+ if( throwInInit || throwInReshape || throwInDisplay || throwInDispose || throwInInvoke ) {
+ Assert.assertTrue("Not one exception sent, but "+exceptionSent.get(), 0 < exceptionSent.get());
+ if( onAnimThread ) {
+ Assert.assertEquals("No exception forwarded from init to animator-handler", 1, exceptionsAtGLAnimatorControl.size());
+ Assert.assertNull("Exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay);
}
- if( throwInDispose ) {
- Assert.assertNotNull("No exception forwarded from dispose", execptionAtDispose);
+ if( throwInInit ) {
+ if( !onAnimThread ) {
+ Assert.assertNotNull("No exception forwarded from init, on-thread", exceptionAtInitReshapeDisplay);
+ Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
+ }
+ Assert.assertEquals("Init Count", 0, cleanInitCount.get());
+ Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get());
+ Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
+ Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
+ Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
+ } else if( throwInReshape ) {
+ if( !onAnimThread ) {
+ Assert.assertNotNull("No exception forwarded from reshape, on-thread", exceptionAtInitReshapeDisplay);
+ Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
+ }
+ Assert.assertEquals("Init Count", 1, cleanInitCount.get());
+ Assert.assertEquals("Reshape Count", 0, cleanReshapeCount.get());
+ Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
+ Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
+ Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
+ } else if( throwInDisplay ) {
+ if( !onAnimThread ) {
+ Assert.assertNotNull("No exception forwarded from display, on-thread", exceptionAtInitReshapeDisplay);
+ Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
+ }
+ Assert.assertEquals("Init Count", 1, cleanInitCount.get());
+ Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
+ Assert.assertEquals("Display Count", 0, cleanDisplayCount.get());
+ Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
+ Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
+ } else if( throwInInvoke ) {
+ if( !onAnimThread ) {
+ Assert.assertNotNull("No exception forwarded from invoke, on-thread", exceptionAtInvoke);
+ Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
+ }
+ Assert.assertEquals("Init Count", 1, cleanInitCount.get());
+ Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
+ Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get());
+ Assert.assertEquals("Invoke Count", 0, cleanInvokeCount.get());
+ Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
+ } else if( throwInDispose ) {
+ if( !onAnimThread ) {
+ Assert.assertNotNull("No exception forwarded from dispose, on-thread", exceptionAtDispose);
+ Assert.assertEquals("Exception forwarded from init to animator-handler", 0, exceptionsAtGLAnimatorControl.size());
+ }
+ Assert.assertEquals("Init Count", 1, cleanInitCount.get());
+ Assert.assertEquals("Reshape Count", 1, cleanReshapeCount.get());
+ Assert.assertTrue ("Display count not greater-equal 1, but "+cleanDisplayCount.get(), 1 <= cleanDisplayCount.get());
+ Assert.assertEquals("Invoke Count", 1, cleanInvokeCount.get());
+ Assert.assertEquals("Dispose Count", 0, cleanDisposeCount.get());
}
}
}
@@ -193,25 +333,62 @@ public class TestGLException01NEWT extends UITestCase {
public void test01OnThreadAtInit() throws InterruptedException {
final GLCapabilities caps = new GLCapabilities(glp);
caps.setBackgroundOpaque(true); // default
- runTestGL(caps, true /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* dispose */);
+ runTestGL(caps, true /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
}
@Test
public void test02OnThreadAtReshape() throws InterruptedException {
final GLCapabilities caps = new GLCapabilities(glp);
caps.setBackgroundOpaque(true); // default
- runTestGL(caps, true /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* dispose */);
+ runTestGL(caps, true /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */);
}
@Test
public void test03OnThreadAtDisplay() throws InterruptedException {
final GLCapabilities caps = new GLCapabilities(glp);
caps.setBackgroundOpaque(true); // default
- runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* dispose */);
+ runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
+ }
+ @Test
+ public void test04OnThreadAtInvoke() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, true /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */);
+ }
+ @Test
+ public void test05OnThreadAtDispose() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, true /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */);
+ }
+
+ @Test
+ public void test11OffThreadAtInit() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, false /* onThread */, true /* init */, false /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
+ }
+ @Test
+ public void test12OffThreadAtReshape() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, false /* onThread */, false /* init */, false /* display */, true /* reshape */, false /* invoke */, false /* dispose */);
+ }
+ @Test
+ public void test13OffThreadAtDisplay() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, false /* invoke */, false /* dispose */);
+ }
+ @Test
+ public void test14OffThreadAtInvoke() throws InterruptedException {
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setBackgroundOpaque(true); // default
+ runTestGL(caps, false /* onThread */, false /* init */, true /* display */, false /* reshape */, true /* invoke */, false /* dispose */);
}
@Test
- public void test04OnThreadAtDispose() throws InterruptedException {
+ public void test15OffThreadAtDispose() throws InterruptedException {
final GLCapabilities caps = new GLCapabilities(glp);
caps.setBackgroundOpaque(true); // default
- runTestGL(caps, true /* onThread */, false /* init */, false /* display */, false /* reshape */, true /* dispose */);
+ runTestGL(caps, false /* onThread */, false /* init */, false /* display */, false /* reshape */, false /* invoke */, true /* dispose */);
}
static long duration = 500; // ms