diff options
author | Sven Gothel <[email protected]> | 2010-11-21 03:41:22 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-21 03:41:22 +0100 |
commit | 2aa296771e3e8dd6cf027f27b0455d1803244bfe (patch) | |
tree | 514c532f9ddff7f84e9e6fb75e883f04c71ec74f | |
parent | 6f73de7c5bb85d0175c8dda7c55317923017bbe0 (diff) |
JOGL/NEWT: Animator fixes
Consider use cases with many drawables and no drawables at start,
this had to be reflected all over this patch set, implementation,
usage and test cases.
- GLAnimatorControl
- refine API doc / states
- add 'void remove(GLAutoDrawable drawable);'
- Animator*:
- using RecursiveLock 'stateSync' for all actions out of the big synchronized (animator) block:
- get status methods (thread, isPaused, ..), hence no more synchronized
- display drawables change, utilizing synced ArrayList swap
This removes the need for volatiles usage shouldPause/shouldStop within the display method.
- added blocking wait for state change for add(GLAutoDrawable)/remove(GLAutoDrawable) method
- remove flawed double checked locking in anim thread (pause/idle condition)
- thread is now a daemon thread, hence it won't hinder the JVM from shutdown
-
- Animator use change:
- Always resume after pause, except in case of final destroy -> NEWT invalidate / GLCanvas,
this considers use cases with many drawables and no drawables at start.
- GLDrawableHelper: Don't pause at implicit dispose()
19 files changed, 502 insertions, 344 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 1aa725c94..8304b99b6 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -24,7 +24,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.ExtensionAvailabilityCache" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile -Djogl.debug.GLDrawable" #D_ARGS="-Djogl.debug.GLProfile" - # D_ARGS="-Djogamp.debug.TraceLock" + D_ARGS="-Dnewt.debug.Window -Djogamp.common.utils.locks.Lock.timeout=600000 -Djogl.debug.Animator" # D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.NativeWindow" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" # D_ARGS="-Dnewt.debug.EDT -Dnativewindow.debug.ToolkitLock.TraceLock -Dnativewindow.debug.X11Util.TraceDisplayLifecycle=true" @@ -61,7 +61,7 @@ function testawt() { #testawt com.jogamp.test.junit.jogl.demos.gl2.gears.newt.TestGearsNEWT #testawt com.jogamp.test.junit.newt.TestDisplayLifecycle01NEWT #testawt com.jogamp.test.junit.newt.TestDisplayLifecycle02NEWT -#testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT +testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT #testawt com.jogamp.test.junit.newt.parenting.TestParenting02NEWT #testawt com.jogamp.test.junit.newt.TestScreenMode00NEWT #testnoawt com.jogamp.test.junit.newt.TestScreenMode01NEWT @@ -98,9 +98,13 @@ function testawt() { #testawt com.jogamp.test.junit.newt.parenting.TestParenting03AWT -time 100000 #testawt com.jogamp.test.junit.newt.parenting.TestParenting03bAWT -time 100000 #testawt com.jogamp.test.junit.newt.TestCloseNewtAWT -testawt com.jogamp.test.junit.jogl.caps.TestMultisampleAWT $* +#testawt com.jogamp.test.junit.jogl.caps.TestMultisampleAWT $* #testawt com.jogamp.test.junit.jogl.caps.TestMultisampleNEWT $* +#testawt com.jogamp.test.junit.newt.TestGLWindows02NEWTAnimated $* +#testawt com.jogamp.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 $* +#testawt com.jogamp.test.junit.newt.parenting.TestParenting01NEWT $* + #testawt $* $spath/count-edt-start.sh java-run.log diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java index 5b1858c41..45b04fac1 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java @@ -238,6 +238,10 @@ public class GLDrawableHelper { } } + public final boolean isExternalAnimatorRunning() { + return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ; + } + public final boolean isExternalAnimatorAnimating() { return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ; } @@ -298,8 +302,6 @@ public class GLDrawableHelper { * <br> * Remark: In case this method is called to dispose the GLDrawable/GLAutoDrawable, * <code>initAction</code> shall be <code>null</code> to mark this cause.<br> - * In this case, the locally delegated {@link javax.media.opengl.GLAnimatorControl} via {@link #setAnimator(javax.media.opengl.GLAnimatorControl) setAnimator(animatorControl)} - * is paused first, if {@link javax.media.opengl.GLAnimatorControl#isAnimating()}. * * @param drawable * @param context @@ -323,10 +325,6 @@ public class GLDrawableHelper { if(!context.isCreated()) { throw new GLException("Dispose case (no init action given): Native context must be created: "+context); } - GLAnimatorControl animCtrl = getAnimator(); - if(null!=animCtrl && animCtrl.isAnimating()) { - animCtrl.pause(); - } } // Support for recursive makeCurrent() calls as well as calling diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java index fbad377ad..2240063d9 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java @@ -36,10 +36,16 @@ package com.jogamp.opengl.util; import java.awt.Component; import java.awt.EventQueue; import java.awt.Rectangle; -import java.util.*; -import javax.swing.*; +import java.util.ArrayList; +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.*; +import javax.media.opengl.GLAutoDrawable; /** Abstraction to factor out AWT dependencies from the Animator's implementation in a way that still allows the FPSAnimator to pick @@ -52,37 +58,34 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { private Map repaintManagers = new IdentityHashMap(); private Map dirtyRegions = new IdentityHashMap(); - public void display(AnimatorBase animator, + public void display(ArrayList drawables, boolean ignoreExceptions, boolean printExceptions) { - List drawables = animator.acquireDrawables(); - try { - for (int i=0; - animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size(); - i++) { - GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i); - if (drawable instanceof JComponent) { - // Lightweight components need a more efficient drawing - // scheme than simply forcing repainting of each one in - // turn since drawing one can force another one to be - // drawn in turn + for (int i=0; i<drawables.size(); i++) { + GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i); + if (drawable instanceof JComponent) { + // Lightweight components need a more efficient drawing + // scheme than simply forcing repainting of each one in + // turn since drawing one can force another one to be + // drawn in turn + if(drawable.isRealized()) { lightweights.add(drawable); - } else { - try { + } + } else { + try { + if(drawable.isRealized()) { drawable.display(); - } catch (RuntimeException e) { - if (ignoreExceptions) { - if (printExceptions) { - e.printStackTrace(); - } - } else { - throw(e); + } + } catch (RuntimeException e) { + if (ignoreExceptions) { + if (printExceptions) { + e.printStackTrace(); } + } else { + throw(e); } } } - } finally { - animator.releaseDrawables(); } if (lightweights.size() > 0) { diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 4f24b22a7..2d4727bba 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -44,8 +44,6 @@ import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLException; - - /** <P> An Animator can be attached to one or more {@link GLAutoDrawable}s to drive their display() methods in a loop. </P> @@ -61,9 +59,8 @@ public class Animator extends AnimatorBase { private Runnable runnable; private boolean runAsFastAsPossible; protected boolean isAnimating; - protected boolean isPaused; - protected volatile boolean shouldPause; - protected volatile boolean shouldStop; + protected boolean pauseIssued; + protected volatile boolean stopIssued; public Animator() { super(); @@ -104,62 +101,78 @@ public class Animator extends AnimatorBase { * This method may not have an effect on subclasses. */ public final void setRunAsFastAsPossible(boolean runFast) { - runAsFastAsPossible = runFast; + stateSync.lock(); + try { + runAsFastAsPossible = runFast; + } finally { + stateSync.unlock(); + } + } + + private void setIsAnimatingSynced(boolean v) { + stateSync.lock(); + try { + isAnimating = v; + } finally { + stateSync.unlock(); + } } class MainLoop implements Runnable { public void run() { try { - if(DEBUG) { - System.err.println("Animator started: "+Thread.currentThread()); - } - startTime = System.currentTimeMillis(); - curTime = startTime; - totalFrames = 0; - synchronized (Animator.this) { - isAnimating = true; - isPaused = false; + if(DEBUG) { + System.err.println("Animator started: "+Thread.currentThread()); + } + + startTime = System.currentTimeMillis(); + curTime = startTime; + totalFrames = 0; + + animThread = Thread.currentThread(); + setIsAnimatingSynced(false); // barrier Animator.this.notifyAll(); } - while (!shouldStop) { - // Don't consume CPU unless there is work to be done and not paused - if ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) { - synchronized (Animator.this) { - boolean wasPaused = false; - while ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) { - isAnimating = false; - isPaused = true; - wasPaused = true; - if(DEBUG) { - System.err.println("Animator paused: "+Thread.currentThread()); - } - Animator.this.notifyAll(); - try { - Animator.this.wait(); - } catch (InterruptedException e) { - } + while (!stopIssued) { + synchronized (Animator.this) { + // Don't consume CPU unless there is work to be done and not paused + while (!stopIssued && (pauseIssued || drawablesEmpty)) { + boolean wasPaused = pauseIssued; + if (DEBUG) { + System.err.println("Animator paused: " + Thread.currentThread()); + } + setIsAnimatingSynced(false); // barrier + Animator.this.notifyAll(); + try { + Animator.this.wait(); + } catch (InterruptedException e) { } - if ( wasPaused ) { + + if (wasPaused) { + // resume from pause -> reset counter startTime = System.currentTimeMillis(); - curTime = startTime; + curTime = startTime; totalFrames = 0; - isAnimating = true; - isPaused = false; - if(DEBUG) { - System.err.println("Animator resumed: "+Thread.currentThread()); + if (DEBUG) { + System.err.println("Animator resume: " + Thread.currentThread()); } - Animator.this.notifyAll(); } } - } - if ( !shouldStop && !shouldPause) { - display(); - if ( !runAsFastAsPossible) { - // Avoid swamping the CPU - Thread.yield(); + if (!stopIssued && !isAnimating) { + // resume from pause or drawablesEmpty, + // implies !pauseIssued and !drawablesEmpty + setIsAnimatingSynced(true); + Animator.this.notifyAll(); } + } // sync Animator.this + if (!stopIssued) { + display(); + } + if (!stopIssued && !runAsFastAsPossible) { + // Avoid swamping the CPU + Thread.yield(); } } } finally { @@ -167,27 +180,50 @@ public class Animator extends AnimatorBase { if(DEBUG) { System.err.println("Animator stopped: "+Thread.currentThread()); } - shouldStop = false; - shouldPause = false; - thread = null; - isAnimating = false; - isPaused = false; + stopIssued = false; + pauseIssued = false; + animThread = null; + setIsAnimatingSynced(false); // barrier Animator.this.notifyAll(); } } } } - public final synchronized boolean isStarted() { - return (thread != null); + private final boolean isStartedImpl() { + return animThread != null ; + } + public final boolean isStarted() { + stateSync.lock(); + try { + return animThread != null ; + } finally { + stateSync.unlock(); + } } - public final synchronized boolean isAnimating() { - return (thread != null) && isAnimating; + private final boolean isAnimatingImpl() { + return animThread != null && isAnimating ; + } + public final boolean isAnimating() { + stateSync.lock(); + try { + return animThread != null && isAnimating ; + } finally { + stateSync.unlock(); + } } - public final synchronized boolean isPaused() { - return (thread != null) && isPaused; + private final boolean isPausedImpl() { + return animThread != null && pauseIssued ; + } + public final boolean isPaused() { + stateSync.lock(); + try { + return animThread != null && pauseIssued ; + } finally { + stateSync.unlock(); + } } interface Condition { @@ -202,109 +238,101 @@ public class Animator extends AnimatorBase { // dependencies on the Animator's internal thread. Currently we // use a couple of heuristics to determine whether we should do // the blocking wait(). - boolean doWait = !impl.skipWaitForCompletion(thread); + boolean doWait = !impl.skipWaitForCompletion(animThread); if (doWait) { while (condition.result()) { try { wait(); - } catch (InterruptedException ie) { - } + } catch (InterruptedException ie) { } } } if(DEBUG) { System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished - waited " + doWait + - ", started: " + isStarted() +", animating: " + isAnimating() + - ", paused: " + isPaused()); + ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() + + ", paused: " + isPausedImpl() + ", drawables " + drawables.size()); } } public synchronized void start() { - boolean started = null != thread; - if ( started || isAnimating ) { - throw new GLException("Already running (started "+started+" (false), animating "+isAnimating+" (false))"); + if ( isStartedImpl() ) { + throw new GLException("Start: Already running (started "+isStartedImpl()+" (false))"); } if (runnable == null) { runnable = new MainLoop(); } resetCounter(); - int id; String threadName = Thread.currentThread().getName()+"-"+baseName; + Thread thread; if(null==threadGroup) { thread = new Thread(runnable, threadName); } else { thread = new Thread(threadGroup, runnable, threadName); } + thread.setDaemon(true); // don't stop JVM from shutdown .. thread.start(); - finishLifecycleAction(waitForStartedCondition); } private class WaitForStartedCondition implements Condition { public boolean result() { - // cont waiting until actually is animating - return !isAnimating || thread == null; + return !isStartedImpl() || (!drawablesEmpty && !isAnimating) ; } } Condition waitForStartedCondition = new WaitForStartedCondition(); public synchronized void stop() { - boolean started = null != thread; - if ( !started ) { - throw new GLException("Not started"); + if ( !isStartedImpl() ) { + throw new GLException("Stop: Not running (started "+isStartedImpl()+" (true))"); } - shouldStop = true; + stopIssued = true; notifyAll(); - finishLifecycleAction(waitForStoppedCondition); } private class WaitForStoppedCondition implements Condition { public boolean result() { - return thread != null; + return isStartedImpl(); } } Condition waitForStoppedCondition = new WaitForStoppedCondition(); public synchronized void pause() { - boolean started = null != thread; - if ( !started || !isAnimating || shouldPause ) { - throw new GLException("Invalid state (started "+started+" (true), animating "+isAnimating+" (true), paused "+shouldPause+" (false) )"); + if ( !isStartedImpl() || pauseIssued ) { + throw new GLException("Pause: Invalid state (started "+isStartedImpl()+" (true), paused "+pauseIssued+" (false) )"); + } + stateSync.lock(); + try { + pauseIssued = true; + } finally { + stateSync.unlock(); } - shouldPause = true; notifyAll(); - finishLifecycleAction(waitForPausedCondition); } private class WaitForPausedCondition implements Condition { public boolean result() { // end waiting if stopped as well - return (!isPaused || isAnimating) && thread != null; + return isAnimating && isStartedImpl(); } } Condition waitForPausedCondition = new WaitForPausedCondition(); public synchronized void resume() { - boolean started = null != thread; - if ( !started || !shouldPause ) { - throw new GLException("Invalid state (started "+started+" (true), paused "+shouldPause+" (true) )"); - } - shouldPause = false; + if ( !isStartedImpl() || !pauseIssued ) { + throw new GLException("Resume: Invalid state (started "+isStartedImpl()+" (true), paused "+pauseIssued+" (true) )"); + } + stateSync.lock(); + try { + pauseIssued = false; + } finally { + stateSync.unlock(); + } notifyAll(); - - finishLifecycleAction(waitForResumedCondition); + finishLifecycleAction(waitForResumeCondition); } - private class WaitForResumedCondition implements Condition { + private class WaitForResumeCondition implements Condition { public boolean result() { // end waiting if stopped as well - return (isPaused || !isAnimating) && thread != null; + return !drawablesEmpty && !isAnimating && isStartedImpl(); } } - Condition waitForResumedCondition = new WaitForResumedCondition(); - - protected final boolean getShouldPause() { - return shouldPause; - } - - protected final boolean getShouldStop() { - return shouldStop; - } - + Condition waitForResumeCondition = new WaitForResumeCondition(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index bd5d1ad68..65d6745ed 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -31,13 +31,18 @@ package com.jogamp.opengl.util; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.opengl.impl.Debug; import java.util.ArrayList; -import java.util.List; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLProfile; /** - * Base implementation of GLAnimatorControl + * Base implementation of GLAnimatorControl<br> + * <p> + * The change synchronization is done via synchronized blocks on the AnimatorBase instance.<br> + * Status get / set activity is synced with a RecursiveLock, used as a memory barrier.<br> + * This is suitable, since all change requests are allowed to be expensive + * as they are not expected to be called at every frame. + * </p> */ public abstract class AnimatorBase implements GLAnimatorControl { protected static final boolean DEBUG = Debug.debug("Animator"); @@ -45,20 +50,21 @@ public abstract class AnimatorBase implements GLAnimatorControl { private static int animatorCount = 0; public interface AnimatorImpl { - void display(AnimatorBase animator, boolean ignoreExceptions, boolean printExceptions); + void display(ArrayList drawables, boolean ignoreExceptions, boolean printExceptions); boolean skipWaitForCompletion(Thread thread); } protected ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList(); - protected RecursiveLock drawablesLock = new RecursiveLock(); + protected boolean drawablesEmpty; protected AnimatorImpl impl; protected String baseName; - protected Thread thread; + protected Thread animThread; protected boolean ignoreExceptions; protected boolean printExceptions; protected long startTime; protected long curTime; protected int totalFrames; + protected RecursiveLock stateSync = new RecursiveLock(); /** Creates a new, empty Animator. */ public AnimatorBase() { @@ -75,6 +81,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { synchronized (Animator.class) { animatorCount++; baseName = baseName.concat("-"+animatorCount); + drawablesEmpty = true; } resetCounter(); } @@ -82,25 +89,54 @@ public abstract class AnimatorBase implements GLAnimatorControl { protected abstract String getBaseName(String prefix); public synchronized void add(GLAutoDrawable drawable) { - drawablesLock.lock(); + if(DEBUG) { + System.err.println("Animator add: "+drawable.hashCode()+" - "+Thread.currentThread()); + } + // drawables list may be in use by display + stateSync.lock(); try { - drawables.add(drawable); + ArrayList newDrawables = (ArrayList) drawables.clone(); + newDrawables.add(drawable); + drawables = newDrawables; + drawablesEmpty = drawables.size() == 0; drawable.setAnimator(this); } finally { - drawablesLock.unlock(); + stateSync.unlock(); } notifyAll(); + if(!impl.skipWaitForCompletion(animThread)) { + while(isStarted() && !isPaused() && !isAnimating()) { + try { + wait(); + } catch (InterruptedException ie) { } + } + } } public synchronized void remove(GLAutoDrawable drawable) { - drawablesLock.lock(); + if(DEBUG) { + System.err.println("Animator remove: "+drawable.hashCode()+" - "+Thread.currentThread()); + } + + // drawables list may be in use by display + stateSync.lock(); try { - drawables.remove(drawable); + ArrayList newDrawables = (ArrayList) drawables.clone(); + newDrawables.remove(drawable); + drawables = newDrawables; + drawablesEmpty = drawables.size() == 0; drawable.setAnimator(null); } finally { - drawablesLock.unlock(); + stateSync.unlock(); } notifyAll(); + if(!impl.skipWaitForCompletion(animThread)) { + while(isStarted() && drawablesEmpty && isAnimating()) { + try { + wait(); + } catch (InterruptedException ie) { } + } + } } /** Called every frame to cause redrawing of all of the @@ -109,20 +145,18 @@ public abstract class AnimatorBase implements GLAnimatorControl { components this Animator manages, in particular when multiple lightweight widgets are continually being redrawn. */ protected void display() { - impl.display(this, ignoreExceptions, printExceptions); + ArrayList dl; + stateSync.lock(); + try { + dl = drawables; + } finally { + stateSync.unlock(); + } + impl.display(dl, ignoreExceptions, printExceptions); curTime = System.currentTimeMillis(); totalFrames++; } - public List acquireDrawables() { - drawablesLock.lock(); - return drawables; - } - - public void releaseDrawables() { - drawablesLock.unlock(); - } - public long getCurrentTime() { return curTime; } @@ -139,16 +173,21 @@ public abstract class AnimatorBase implements GLAnimatorControl { return totalFrames; } + public final Thread getThread() { + stateSync.lock(); + try { + return animThread; + } finally { + stateSync.unlock(); + } + } + public synchronized void resetCounter() { startTime = System.currentTimeMillis(); // overwrite startTime to real init one curTime = startTime; totalFrames = 0; } - public final synchronized Thread getThread() { - return thread; - } - /** Sets a flag causing this Animator to ignore exceptions produced while redrawing the drawables. By default this flag is set to false, causing any exception thrown to halt the Animator. */ @@ -165,10 +204,6 @@ public abstract class AnimatorBase implements GLAnimatorControl { } public String toString() { - return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+"]"; + return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]"; } - - protected abstract boolean getShouldPause(); - - protected abstract boolean getShouldStop(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java index 650d2e8ae..f98c4b488 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java @@ -33,37 +33,32 @@ package com.jogamp.opengl.util; -import java.util.*; -import javax.media.opengl.*; +import java.util.ArrayList; +import javax.media.opengl.GLAutoDrawable; /** 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. */ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl { - public void display(AnimatorBase animator, + public void display(ArrayList drawables, boolean ignoreExceptions, boolean printExceptions) { - List drawables = animator.acquireDrawables(); - try { - for (int i=0; - animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size(); - i++) { - GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i); - try { + for (int i=0; i<drawables.size(); i++) { + GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i); + try { + if(drawable.isRealized()) { drawable.display(); - } catch (RuntimeException e) { - if (ignoreExceptions) { - if (printExceptions) { - e.printStackTrace(); - } - } else { - throw(e); + } + } catch (RuntimeException e) { + if (ignoreExceptions) { + if (printExceptions) { + e.printStackTrace(); } + } else { + throw(e); } } - } finally { - animator.releaseDrawables(); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java index 8542000c6..447c72709 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java @@ -88,16 +88,31 @@ public class FPSAnimator extends AnimatorBase { this.scheduleAtFixedRate = scheduleAtFixedRate; } - public final synchronized boolean isStarted() { - return (timer != null); + public final boolean isStarted() { + stateSync.lock(); + try { + return (timer != null); + } finally { + stateSync.unlock(); + } } - public final synchronized boolean isAnimating() { - return (timer != null) && (task != null); + public final boolean isAnimating() { + stateSync.lock(); + try { + return (timer != null) && (task != null); + } finally { + stateSync.unlock(); + } } - public final synchronized boolean isPaused() { - return (timer != null) && (task == null); + public final boolean isPaused() { + stateSync.lock(); + try { + return (timer != null) && (task == null); + } finally { + stateSync.unlock(); + } } private void startTask() { @@ -105,7 +120,8 @@ public class FPSAnimator extends AnimatorBase { task = new TimerTask() { public void run() { if(FPSAnimator.this.shouldRun) { - FPSAnimator.this.thread = Thread.currentThread(); + FPSAnimator.this.animThread = Thread.currentThread(); + // display impl. uses synchronized block on the animator instance display(); } } @@ -125,8 +141,13 @@ public class FPSAnimator extends AnimatorBase { if (timer != null) { throw new GLException("Already started"); } - timer = new Timer(); - startTask(); + stateSync.lock(); + try { + timer = new Timer(); + startTask(); + } finally { + stateSync.unlock(); + } } /** Stops this FPSAnimator. Due to the implementation of the @@ -136,36 +157,43 @@ public class FPSAnimator extends AnimatorBase { if (timer == null) { throw new GLException("Already stopped"); } - shouldRun = false; - task.cancel(); - task = null; - timer.cancel(); - timer = null; - thread = null; + stateSync.lock(); + try { + shouldRun = false; + task.cancel(); + task = null; + timer.cancel(); + timer = null; + animThread = null; + } finally { + stateSync.unlock(); + } } public synchronized void pause() { if (timer == null) { throw new GLException("Not running"); } - shouldRun = false; - task.cancel(); - task = null; - thread = null; + stateSync.lock(); + try { + shouldRun = false; + task.cancel(); + task = null; + animThread = null; + } finally { + stateSync.unlock(); + } } public synchronized void resume() { if (timer == null) { throw new GLException("Not running"); } - startTask(); - } - - protected final boolean getShouldPause() { - return (timer != null) && (task == null); - } - - protected final boolean getShouldStop() { - return (timer == null); + stateSync.lock(); + try { + startTask(); + } finally { + stateSync.unlock(); + } } } diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java index 01e5646f9..98d7bc48b 100644 --- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java +++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java @@ -79,7 +79,7 @@ public interface GLAnimatorControl { public void resetCounter(); /** - * Indicates whether this animator is currently running, ie started. + * Indicates whether this animator is running, ie. has been started and not stopped. * * @see #start() * @see #stop() @@ -89,7 +89,8 @@ public interface GLAnimatorControl { boolean isStarted(); /** - * Indicates whether this animator is currently running and not paused. + * Indicates whether this animator is running and animating,<br> + * the latter is true if it has {@link GLAutoDrawable}s to render and is not paused. * * @see #start() * @see #stop() @@ -99,7 +100,7 @@ public interface GLAnimatorControl { boolean isAnimating(); /** - * Indicates whether this animator is currently running and paused. + * Indicates whether this animator is running and paused. * * @see #start() * @see #stop() @@ -109,7 +110,7 @@ public interface GLAnimatorControl { boolean isPaused(); /** - * @return The animation thread if started, ie running. + * @return The animation thread if running, otherwise null. * * @see #start() * @see #stop() @@ -158,7 +159,7 @@ public interface GLAnimatorControl { * * @see #resume() * @see #isAnimating() - * @throws GLException if not started or not animating or already paused + * @throws GLException if not started or already paused */ void pause(); @@ -177,4 +178,15 @@ public interface GLAnimatorControl { * @throws GLException if not started or not paused */ void resume(); + + /** + * Removes a drawable from the animator's list of rendering drawables.<br> + * This method should get called in case a drawable becomes invalid, + * and will not be recovered.<br> + * This allows the animator thread to become idle in case the last drawable + * has reached it's end of life.<br> + * + * @param drawable the to be removed drawable + */ + void remove(GLAutoDrawable drawable); } diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index 12ded8736..cde327a07 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -40,7 +40,6 @@ package javax.media.opengl; -import javax.media.opengl.glu.*; import com.jogamp.opengl.impl.Debug; import java.security.*; diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilities.java b/src/jogl/classes/javax/media/opengl/GLCapabilities.java index 3d2e2bcc9..82f83dc82 100644 --- a/src/jogl/classes/javax/media/opengl/GLCapabilities.java +++ b/src/jogl/classes/javax/media/opengl/GLCapabilities.java @@ -59,7 +59,7 @@ public class GLCapabilities extends Capabilities implements Cloneable, GLCapabil private boolean doubleBuffered = true; private boolean stereo = false; private boolean hardwareAccelerated = true; - private int depthBits = 24; + private int depthBits = 16; private int stencilBits = 0; private int accumRedBits = 0; private int accumGreenBits = 0; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index f2016a23c..265c7ff49 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -347,10 +347,17 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } if(null!=context) { - boolean animatorWasAnimating = false; + boolean animatorPaused = false; GLAnimatorControl animator = getAnimator(); if(null!=animator) { - animatorWasAnimating = animator.isAnimating(); + if(regenerate) { + if(animator.isStarted() && !animator.isPaused()) { + animator.pause(); + animatorPaused = true; + } + } else { + animator.remove(this); + } } disposeRegenerate=regenerate; @@ -376,8 +383,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { drawableHelper.invokeGL(drawable, context, disposeAction, null); } - if(regenerate && animatorWasAnimating && animator.isPaused()) { - animator.resume(); + if(animatorPaused) { + animator.resume(); } } if(!regenerate) { diff --git a/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java b/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java index 8f56f6f46..fef0e5ad6 100644 --- a/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java +++ b/src/junit/com/jogamp/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java @@ -256,20 +256,25 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { Screen screen = win0.getScreen(); win0.setPosition(screen.getWidth()-150, 0); win0.addGLEventListener(new Gears()); - Animator anim0 = new Animator(win0); - anim0.start(); + Animator anim = new Animator(win0); + anim.start(); GLWindow win1 = GLWindow.create(caps); NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(win1); - Animator anim1 = new Animator(win1); - anim1.start(); + anim.add(win1); runTestGL(newtCanvasAWT, win1); win0.destroy(); - Assert.assertEquals(false, anim0.isAnimating()); + Assert.assertEquals(true, anim.isAnimating()); newtCanvasAWT.destroy(); - Assert.assertEquals(false, anim1.isAnimating()); + + win0.invalidate(); + Assert.assertEquals(true, anim.isAnimating()); + win1.invalidate(); + Assert.assertEquals(false, anim.isAnimating()); + + anim.stop(); System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.test01NewtCanvasAWT(): End"); } @@ -280,6 +285,9 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { GLProfile glp = GLProfile.getDefault(); GLCapabilities caps = new GLCapabilities(glp); + Animator anim = new Animator(); + anim.start(); + /** * Using GLCanvas _and_ NEWT side by side currently causes a deadlock * in AWT with AMD drivers ! @@ -290,23 +298,18 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { Screen screen = win0.getScreen(); win0.setPosition(screen.getWidth()-150, 0); win0.addGLEventListener(new Gears()); - Animator anim0 = new Animator(win0); - anim0.start(); + anim.add(win0); */ GLCanvas glCanvas = new GLCanvas(caps); - Animator anim1 = new Animator(glCanvas); - anim1.start(); + anim.add(glCanvas); runTestGL(glCanvas, glCanvas); - Thread.sleep(100); // wait 1/10Hz to allow animation to be paused - Assert.assertEquals(false, anim1.isAnimating()); - /** win0.destroy(); - Assert.assertEquals(false, anim0.isAnimating()); + Assert.assertEquals(true, anim.isAnimating()); */ - + anim.stop(); System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.test02GLCanvas(): End"); } diff --git a/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java b/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java index e79d57a4f..a019de72d 100644 --- a/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java +++ b/src/junit/com/jogamp/test/junit/newt/TestGLWindows02NEWTAnimated.java @@ -28,19 +28,11 @@ package com.jogamp.test.junit.newt; -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; import org.junit.Assert; -import org.junit.Before; import org.junit.BeforeClass; -import org.junit.After; -import org.junit.AfterClass; import org.junit.Test; -import javax.media.nativewindow.*; import javax.media.opengl.*; import com.jogamp.opengl.util.Animator; @@ -131,7 +123,8 @@ public class TestGLWindows02NEWTAnimated extends UITestCase { Thread.sleep(100); } destroyWindow(window); - Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(true, animator.isAnimating()); + animator.stop(); } @Test @@ -146,7 +139,8 @@ public class TestGLWindows02NEWTAnimated extends UITestCase { } destroyWindow(window); destroyWindow(window); - Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(true, animator.isAnimating()); + animator.stop(); } @Test @@ -167,20 +161,44 @@ public class TestGLWindows02NEWTAnimated extends UITestCase { Assert.assertNotNull(window2); window2.setPosition(screen.getWidth()-width, 0); - Animator animator1 = new Animator(window1); - animator1.start(); - Animator animator2 = new Animator(window2); - animator2.start(); - while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { + Animator animator = new Animator(); + Assert.assertEquals(false, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.start(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.add(window1); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.add(window2); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + while(animator.isAnimating() && animator.getDuration()<durationPerTest) { Thread.sleep(100); } + window1.invalidate(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); - destroyWindow(window1); - Assert.assertEquals(false, animator1.isAnimating()); - - destroyWindow(window2); - Assert.assertEquals(false, animator2.isAnimating()); + while(animator.isAnimating() && animator.getDuration()<2*durationPerTest) { + Thread.sleep(100); + } + window2.invalidate(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + animator.stop(); } + @Test public void testWindowDecor03TwoWinTwoDisplays() throws InterruptedException { GLCapabilities caps = new GLCapabilities(glp); @@ -204,19 +222,56 @@ public class TestGLWindows02NEWTAnimated extends UITestCase { Assert.assertNotNull(window2); window2.setPosition(screen2.getWidth()-width, 0); - Animator animator1 = new Animator(window1); - animator1.start(); - Animator animator2 = new Animator(window2); - animator2.start(); - while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { + Animator animator = new Animator(); + Assert.assertEquals(false, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.start(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.add(window1); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.add(window2); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + while(animator.isAnimating() && animator.getDuration()<durationPerTest) { Thread.sleep(100); } - destroyWindow(window1); - Assert.assertEquals(false, animator1.isAnimating()); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + while(animator.isAnimating() && animator.getDuration()<2*durationPerTest) { + Thread.sleep(100); + } destroyWindow(window2); - Assert.assertEquals(false, animator2.isAnimating()); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.pause(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(true, animator.isPaused()); + + animator.resume(); + Assert.assertEquals(true, animator.isStarted()); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); + + animator.stop(); + Assert.assertEquals(false, animator.isStarted()); + Assert.assertEquals(false, animator.isAnimating()); + Assert.assertEquals(false, animator.isPaused()); } public static void setDemoFields(GLEventListener demo, GLWindow glWindow) { diff --git a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java index 1f45c6c1d..97589ed3a 100644 --- a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java +++ b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01NEWT.java @@ -709,17 +709,7 @@ public class TestParenting01NEWT extends UITestCase { } System.err.println("durationPerTest: "+durationPerTest); String tstname = TestParenting01NEWT.class.getName(); - org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { - tstname, - "filtertrace=true", - "haltOnError=false", - "haltOnFailure=false", - "showoutput=true", - "outputtoformatters=true", - "logfailedtests=true", - "logtestlistenerevents=true", - "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", - "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); + org.junit.runner.JUnitCore.main(tstname); } } diff --git a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java index 2c3455cb0..fd52c86a1 100644 --- a/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java +++ b/src/junit/com/jogamp/test/junit/newt/parenting/TestParenting01aAWT.java @@ -216,6 +216,8 @@ public class TestParenting01aAWT extends UITestCase { Animator animator1 = new Animator(glWindow1); animator1.start(); + Assert.assertEquals(true, animator1.isStarted()); + Assert.assertEquals(true, animator1.isAnimating()); while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { Thread.sleep(100); } diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 8b9e7bb4e..99db47168 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -31,7 +31,6 @@ package com.jogamp.newt; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseListener; -import com.jogamp.newt.event.ScreenModeListener; import com.jogamp.newt.impl.Debug; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; @@ -43,7 +42,7 @@ import javax.media.nativewindow.util.Insets; * Specifying the public Window functionality for the * using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}. */ -public interface Window extends NativeWindow, ScreenModeListener { +public interface Window extends NativeWindow { public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent"); public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent"); public static final boolean DEBUG_WINDOW_EVENT = Debug.debug("Window.WindowEvent"); diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java index f0aa9effd..fd5c1b662 100644 --- a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -68,7 +68,7 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; -public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenModeListener +public abstract class WindowImpl implements Window, NEWTEventConsumer { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); @@ -112,6 +112,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod private ArrayList windowListeners; private boolean repaintQueued = false; + ScreenModeListenerImpl screenModeListenerImpl = new ScreenModeListenerImpl(); + private void initializeStates() { invalidate(true); @@ -250,9 +252,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod * Invoked for expensive modifications, ie while reparenting and ScreenMode change.<br> * No lock is hold when invoked.<br> * + * @return true is paused, otherwise false. If true {@link #resumeRenderingAction()} shall be issued. + * * @see #resumeRenderingAction() */ - void pauseRenderingAction(); + boolean pauseRenderingAction(); /** * Invoked for expensive modifications, ie while reparenting and ScreenMode change. @@ -280,7 +284,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod screenReferenceAdded = true; createNativeImpl(); setVisibleImpl(true, x, y, width, height); - screen.addScreenModeListener(this); + screen.addScreenModeListener(screenModeListenerImpl); } } finally { if(null!=parentWindow) { @@ -308,7 +312,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod try { if( null != screen ) { if( 0 != windowHandle ) { - screen.removeScreenModeListener(WindowImpl.this); + screen.removeScreenModeListener(screenModeListenerImpl); closeNativeImpl(); removeScreenReference(); } @@ -438,20 +442,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod public final int lockSurface() { int res = LOCK_SURFACE_NOT_READY; - windowLock.lock(); - AbstractGraphicsDevice adevice = screen.getDisplay().getGraphicsDevice(); - adevice.lock(); - try { - res = lockSurfaceImpl(); - } finally { - if(!isNativeValid()) { - adevice.unlock(); - windowLock.unlock(); - res = LOCK_SURFACE_NOT_READY; + if(isNativeValid()) { + AbstractGraphicsDevice adevice = screen.getDisplay().getGraphicsDevice(); + adevice.lock(); + try { + res = lockSurfaceImpl(); + } finally { + if( LOCK_SURFACE_NOT_READY == res ) { + adevice.unlock(); + } } } + if( LOCK_SURFACE_NOT_READY == res ) { + windowLock.unlock(); + } return res; } @@ -752,14 +758,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod //Exception ee = new Exception(msg); //ee.printStackTrace(); } + boolean animatorPaused = false; if(null!=lifecycleHook) { - lifecycleHook.pauseRenderingAction(); + animatorPaused = lifecycleHook.pauseRenderingAction(); } if(null!=lifecycleHook) { lifecycleHook.destroyActionPreLock(); } runOnEDTIfAvail(true, destroyAction); - if(null!=lifecycleHook) { + if(animatorPaused) { lifecycleHook.resumeRenderingAction(); } } @@ -1134,15 +1141,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { int reparentActionStrategy = ReparentAction.ACTION_INVALID; if(isValid()) { + boolean animatorPaused = false; if(null!=lifecycleHook) { - lifecycleHook.pauseRenderingAction(); + animatorPaused = lifecycleHook.pauseRenderingAction(); } try { ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); runOnEDTIfAvail(true, reparentAction); reparentActionStrategy = reparentAction.getStrategy(); } finally { - if(null!=lifecycleHook) { + if(animatorPaused) { lifecycleHook.resumeRenderingAction(); } } @@ -1531,31 +1539,35 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod return this.fullscreen; } - public void screenModeChangeNotify(ScreenMode sm) { - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("Window.screenModeChangeNotify: "+sm); - } + class ScreenModeListenerImpl implements ScreenModeListener { + boolean animatorPaused = false; - if(null!=lifecycleHook) { - lifecycleHook.pauseRenderingAction(); - } - } + public void screenModeChangeNotify(ScreenMode sm) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChangeNotify: "+sm); + } - public void screenModeChanged(ScreenMode sm, boolean success) { - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("Window.screenModeChanged: "+sm+", success: "+success); + if(null!=lifecycleHook) { + animatorPaused = lifecycleHook.pauseRenderingAction(); + } } - if(success) { - DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution(); - if ( getHeight() > screenSize.getHeight() || - getWidth() > screenSize.getWidth() ) { - setSize(screenSize.getWidth(), screenSize.getHeight()); + public void screenModeChanged(ScreenMode sm, boolean success) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChanged: "+sm+", success: "+success); } - } - if(null!=lifecycleHook) { - lifecycleHook.resumeRenderingAction(); + if(success) { + DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution(); + if ( getHeight() > screenSize.getHeight() || + getWidth() > screenSize.getWidth() ) { + setSize(screenSize.getWidth(), screenSize.getHeight()); + } + } + + if(animatorPaused) { + lifecycleHook.resumeRenderingAction(); + } sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } } diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java index 5d7bcd7b3..d4f4f77ea 100644 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java @@ -59,7 +59,7 @@ public class WindowsWindow extends WindowImpl { hdc = GetDC0(getWindowHandle()); hmon = MonitorFromWindow0(getWindowHandle()); } - return LOCK_SUCCESS; + return ( 0 != hdc ) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; } protected void unlockSurfaceImpl() { diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index dc5c12b58..da22a6217 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -86,11 +86,11 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { public void windowDestroyNotify(WindowEvent e) { // Is an animator thread perform rendering? - if (GLWindow.this.helper.isExternalAnimatorAnimating()) { + if (GLWindow.this.helper.isExternalAnimatorRunning()) { // Pause animations before initiating safe destroy. GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator(); ctrl.pause(); - + destroy(); ctrl.resume(); @@ -251,15 +251,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { public final void addChild(NativeWindow win) { window.addChild(win); } - - public void screenModeChangeNotify(ScreenMode sm) { - window.screenModeChangeNotify(sm); - } - - public void screenModeChanged(ScreenMode sm, boolean success) { - window.screenModeChanged(sm, success); - } - + //---------------------------------------------------------------------- // Window.LifecycleHook Implementation // @@ -299,12 +291,10 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { } DisposeAction disposeAction = new DisposeAction(); - /** Window.LifecycleHook */ public synchronized void destroyActionPreLock() { // nop } - /** Window.LifecycleHook */ public synchronized void destroyActionInLock() { if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { String msg = new String("GLWindow.destroy() "+Thread.currentThread()+", start"); @@ -334,7 +324,6 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { } } - /** Window.LifecycleHook */ public synchronized void invalidate(boolean unrecoverable) { if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { String msg = new String("GLWindow.invalidate("+unrecoverable+") "+Thread.currentThread()+", start"); @@ -344,14 +333,13 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { } if(unrecoverable) { GLAnimatorControl ctrl = GLWindow.this.getAnimator(); - if ( null!=ctrl && ctrl.isStarted() ) { - ctrl.stop(); + if ( null!=ctrl ) { + ctrl.remove(GLWindow.this); } helper=null; } } - /** Window.LifecycleHook */ public synchronized void resetCounter() { if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { System.err.println("GLWindow.resetCounter() "+Thread.currentThread()); @@ -394,21 +382,20 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { //e1.printStackTrace(); } } - - boolean animatorPaused = false; - - public synchronized void pauseRenderingAction() { + + public synchronized boolean pauseRenderingAction() { + boolean animatorPaused = false; GLAnimatorControl ctrl = GLWindow.this.getAnimator(); - if ( null!=ctrl && ctrl.isAnimating() && ctrl.getThread() != Thread.currentThread() ) { + if ( null!=ctrl && ctrl.isStarted() && !ctrl.isPaused()) { animatorPaused = true; ctrl.pause(); } + return animatorPaused; } public synchronized void resumeRenderingAction() { GLAnimatorControl ctrl = GLWindow.this.getAnimator(); - if ( null!=ctrl && animatorPaused ) { - animatorPaused = false; + if ( null!=ctrl && ctrl.isPaused() ) { ctrl.resume(); } } @@ -517,10 +504,11 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { setVisible(true); } - if( isVisible() && isNativeValid() && null != context ) { - if(forceReshape) { - sendReshape = true; - } + if(forceReshape) { + sendReshape = true; + } + + if( isVisible() && null != context ) { if( NativeSurface.LOCK_SURFACE_NOT_READY < lockSurface() ) { try { helper.invokeGL(drawable, context, displayAction, initAction); |