diff options
author | Sven Gothel <[email protected]> | 2012-07-04 18:02:11 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-07-04 18:02:11 +0200 |
commit | 9b35c57425b0a5f6b789b9b43a62a8b64be51d86 (patch) | |
tree | 04a4e082e00fd4d313346aa8dfc2ce4e5d3ab145 | |
parent | eed8508ae1132e5f45f788e9cb3f3d5a1050ac70 (diff) |
GLAutoDrawable* refinement of abstraction / generalization - API Change!
- GLAutoDrawable (compat change - recompile):
- 'void invoke(boolean wait, GLRunnable glRunnable)' -> 'boolean invoke(boolean wait, GLRunnable glRunnable)'
Allows notifying caller whether the task has been executed or at least enqueued.
- GLAutoDrawable add 'GLEventListener removeGLEventListener(int index)'
- This allow one to remove a specific GLEventListener and reusing it (return value).
- GLDrawableImpl remove 'destroy()' to favor 'setRealized(false)'
- Using more common code of GLAutoDrawableBase, i.e. GLPbufferImpl can use defaultDestroyOp().
- Removes redundancy of methods
- GLAutoDrawableBase/Delegate
- better 'default' names to emphasize it's purpose, adding API doc
- includes more generic functionality
- defaultWindowDestroyNotify()
- defaultDestroyOp()
- TestGLAutoDrawableDelegateNEWT demonstrates a simple example w/ all window events handled.
- Fix TestParenting01cSwingAWT's threading use (gl disturbance thread)
27 files changed, 582 insertions, 311 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index 31b679077..62b496891 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -107,7 +107,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { //private static final boolean useSWTThread = ThreadingImpl.getMode() != ThreadingImpl.WORKER; /* GL Stuff */ - private final GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private final GLDrawableHelper helper = new GLDrawableHelper(); private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display private GLContext context; @@ -130,7 +130,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final Runnable initAction = new Runnable() { @Override public void run() { - drawableHelper.init(GLCanvas.this); + helper.init(GLCanvas.this); } }; @@ -143,10 +143,10 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void run() { if (sendReshape) { - drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); + helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); sendReshape = false; } - drawableHelper.display(GLCanvas.this); + helper.display(GLCanvas.this); } }; @@ -154,7 +154,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final Runnable makeCurrentAndDisplayAction = new Runnable() { @Override public void run() { - drawableHelper.invokeGL(drawable, context, displayAction, initAction); + helper.invokeGL(drawable, context, displayAction, initAction); } }; @@ -170,7 +170,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final Runnable makeCurrentAndSwapBuffersAction = new Runnable() { @Override public void run() { - drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction); + helper.invokeGL(drawable, context, swapBuffersAction, initAction); } }; @@ -191,7 +191,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final Runnable disposeOnEDTGLAction = new Runnable() { @Override public void run() { - drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); + helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); } }; @@ -266,7 +266,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { addPaintListener(new PaintListener() { @Override public void paintControl(final PaintEvent arg0) { - if (!drawableHelper.isExternalAnimatorAnimating()) { + if (!helper.isExternalAnimatorAnimating()) { display(); } } @@ -284,12 +284,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void addGLEventListener(final GLEventListener arg0) { - drawableHelper.addGLEventListener(arg0); + helper.addGLEventListener(arg0); } @Override public void addGLEventListener(final int arg0, final GLEventListener arg1) throws IndexOutOfBoundsException { - drawableHelper.addGLEventListener(arg0, arg1); + helper.addGLEventListener(arg0, arg1); } /** @@ -312,12 +312,12 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public GLAnimatorControl getAnimator() { - return drawableHelper.getAnimator(); + return helper.getAnimator(); } @Override public boolean getAutoSwapBufferMode() { - return drawableHelper.getAutoSwapBufferMode(); + return helper.getAutoSwapBufferMode(); } @Override @@ -336,30 +336,34 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } @Override - public void invoke(final boolean wait, final GLRunnable run) { - /* Queue task for running during the next display(). */ - drawableHelper.invoke(this, wait, run); + public boolean invoke(final boolean wait, final GLRunnable run) { + return helper.invoke(this, wait, run); } @Override public void removeGLEventListener(final GLEventListener arg0) { - drawableHelper.removeGLEventListener(arg0); + helper.removeGLEventListener(arg0); } @Override + public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.removeGLEventListener(index); + } + + @Override public void setAnimator(final GLAnimatorControl arg0) throws GLException { - drawableHelper.setAnimator(arg0); + helper.setAnimator(arg0); } @Override public void setAutoSwapBufferMode(final boolean arg0) { - drawableHelper.setAutoSwapBufferMode(arg0); + helper.setAutoSwapBufferMode(arg0); } @Override public GLContext setContext(GLContext newCtx) { final GLContext oldCtx = context; - final boolean newCtxCurrent = drawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; if(newCtxCurrent) { context.makeCurrent(); @@ -477,7 +481,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { if (Threading.isSingleThreaded() && !Threading.isOpenGLThread()) { runInDesignatedGLThread(disposeOnEDTGLAction); } else if (context.isCreated()) { - drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); + helper.disposeGL(GLCanvas.this, drawable, context, postDisposeGLAction); } } @@ -537,7 +541,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { runInDesignatedGLThread(asyncAction); } else { /* Run in current thread... */ - drawableHelper.invokeGL(drawable, context, syncAction, initAction); + helper.invokeGL(drawable, context, syncAction, initAction); } } diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index e4aaad23d..80d4f796c 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -165,16 +165,32 @@ public interface GLAutoDrawable extends GLDrawable { * @param listener The GLEventListener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addGLEventListener(int index, GLEventListener listener) - throws IndexOutOfBoundsException; + public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException; - /** Removes a {@link GLEventListener} from this drawable. Note that - if this is done from within a particular drawable's {@link - GLEventListener} handler (reshape, display, etc.) that it is not - guaranteed that all other listeners will be evaluated properly - during this update cycle. */ + /** + * Removes a {@link GLEventListener} from this drawable. + * Note that if this is done from within a particular drawable's + * {@link GLEventListener} handler (reshape, display, etc.) that it is not + * guaranteed that all other listeners will be evaluated properly + * during this update cycle. + * @param listener The GLEventListener object to be removed + */ public void removeGLEventListener(GLEventListener listener); + /** + * Removes a {@link GLEventListener} at the given index from this drawable. + * Note that if this is done from within a particular drawable's + * {@link GLEventListener} handler (reshape, display, etc.) that it is not + * guaranteed that all other listeners will be evaluated properly + * during this update cycle. + * @param index Position of the listener to be removed. + * Should be within (0 <= index && index < size()). + * An index value of -1 is interpreted as last listener, size()-1. + * @return The removed GLEventListener object + * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index < size()), or -1 + */ + public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException; + /** * <p> * Registers the usage of an animator, an {@link javax.media.opengl.GLAnimatorControl} implementation. @@ -221,14 +237,30 @@ public interface GLAutoDrawable extends GLDrawable { * <p> * If an {@link GLAnimatorControl} is animating,<br> * no {@link #display()} call is issued, since the animator thread performs it.<br> - * If <code>wait</code> is true, the implementation waits until the <code>GLRunnable</code> is executed.<br> - * </p><br> + * </p> + * <p> + * If <code>wait</code> is <code>true</code> the call blocks until the <code>glRunnable</code> + * has been executed.<p> + * <p> + * If <code>wait</code> is <code>true</code> <b>and</b> + * {@link #isRealized()} returns <code>false</code> <i>or</i> {@link #getContext()} returns <code>null</code>, + * the call is ignored and returns <code>false</code>.<br> + * This helps avoiding deadlocking the caller. + * </p> + * <p> + * The internal queue of {@link GLRunnable}'s is being flushed with {@link #destroy()} + * where all blocked callers are being notified. + * </p> * + * @param wait if <code>true</code> block until execution of <code>glRunnable</code> is finished, otherwise return immediatly w/o waiting + * @param glRunnable the {@link GLRunnable} to execute within {@link #display()} + * @return <code>true</code> if the {@link GLRunnable} has been processed or queued, otherwise <code>false</code>. + * * @see #setAnimator(GLAnimatorControl) * @see #display() * @see GLRunnable */ - public void invoke(boolean wait, GLRunnable glRunnable); + public boolean invoke(boolean wait, GLRunnable glRunnable); /** Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext. diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java index 992bf9fee..89d5cc4cb 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawableDelegate.java @@ -28,6 +28,9 @@ package javax.media.opengl; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + import jogamp.opengl.Debug; import jogamp.opengl.GLAutoDrawableBase; import jogamp.opengl.GLContextImpl; @@ -39,11 +42,16 @@ import jogamp.opengl.GLDrawableImpl; * utilizing already created created {@link GLDrawable} and {@link GLContext} instances. * <p> * Since no native windowing system events are being processed, it is recommended - * to handle at least {@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize}, - * {@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} - * and maybe {@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint}. - * The latter is only required if no {@link GLAnimatorControl} is being used. - * </p> + * to handle at least: + * <ul> + * <li>{@link com.jogamp.newt.event.WindowListener#windowRepaint(com.jogamp.newt.event.WindowUpdateEvent) repaint} using {@link #defaultWindowRepaintOp()}</li> + * <li>{@link com.jogamp.newt.event.WindowListener#windowResized(com.jogamp.newt.event.WindowEvent) resize} using {@link #defaultWindowResizedOp()}</li> + * <li>{@link com.jogamp.newt.event.WindowListener#windowDestroyNotify(com.jogamp.newt.event.WindowEvent) destroy-notify} using {@link #defaultWindowDestroyNotifyOp()}</li> + * </ul> + * </p> + * <p> + * See example {@link com.jogamp.opengl.test.junit.jogl.acore.TestGLAutoDrawableDelegateNEWT TestGLAutoDrawableDelegateNEWT}. + * </p> */ public class GLAutoDrawableDelegate extends GLAutoDrawableBase { public static final boolean DEBUG = Debug.debug("GLAutoDrawableDelegate"); @@ -52,36 +60,64 @@ public class GLAutoDrawableDelegate extends GLAutoDrawableBase { super((GLDrawableImpl)drawable, (GLContextImpl)context); } - public void defaultRepaintOp() { - super.defaultRepaintOp(); + // + // make protected methods accessible + // + + public void defaultWindowRepaintOp() { + super.defaultWindowRepaintOp(); + } + + public void defaultWindowResizedOp() { + super.defaultWindowResizedOp(); } - public void defaultReshapeOp() { - super.defaultReshapeOp(); + public void defaultWindowDestroyNotifyOp() { + super.defaultWindowDestroyNotifyOp(); } // // Complete GLAutoDrawable // + private RecursiveLock lock = LockFactory.createRecursiveLock(); // instance wide lock + /** * {@inheritDoc} * <p> - * This implementation simply removes references to drawable and context. + * This implementation calls {@link #defaultDestroyOp()}. + * </p> + * <p> + * User still needs to destroy the upstream window, which details are hidden from this aspect. * </p> */ @Override public void destroy() { - drawable = null; - context = null; + lock.lock(); + try { + defaultDestroyOp(); + } finally { + lock.unlock(); + } } @Override public void display() { - if( null == drawable || !drawable.isRealized() || null == context ) { return; } - - // surface is locked/unlocked implicit by context's makeCurrent/release - helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction); + if( sendDestroy ) { + sendDestroy=false; + destroy(); + return; + } + + lock.lock(); // sync: context/drawable could been recreated/destroyed while animating + try { + if( null != drawable && drawable.isRealized() && null != context ) { + // surface is locked/unlocked implicit by context's makeCurrent/release + helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction); + } + } finally { + lock.unlock(); + } } // diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 8c6e594b5..3161f898d 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -153,7 +153,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private static final boolean DEBUG = Debug.debug("GLCanvas"); - private final GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private final GLDrawableHelper helper = new GLDrawableHelper(); private AWTGraphicsConfiguration awtConfig; private volatile GLDrawable drawable; // volatile avoids locking all accessors. FIXME still need to sync destroy/display private GLContextImpl context; @@ -510,7 +510,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing (int) ((getHeight() + bounds.getHeight()) / 2)); return; } - if( ! this.drawableHelper.isAnimatorAnimating() ) { + if( ! this.helper.isAnimatorAnimating() ) { display(); } } @@ -670,38 +670,43 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void addGLEventListener(GLEventListener listener) { - drawableHelper.addGLEventListener(listener); + helper.addGLEventListener(listener); } @Override - public void addGLEventListener(int index, GLEventListener listener) { - drawableHelper.addGLEventListener(index, listener); + public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException { + helper.addGLEventListener(index, listener); } @Override public void removeGLEventListener(GLEventListener listener) { - drawableHelper.removeGLEventListener(listener); + helper.removeGLEventListener(listener); } @Override + public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.removeGLEventListener(index); + } + + @Override public void setAnimator(GLAnimatorControl animatorControl) { - drawableHelper.setAnimator(animatorControl); + helper.setAnimator(animatorControl); } @Override public GLAnimatorControl getAnimator() { - return drawableHelper.getAnimator(); + return helper.getAnimator(); } @Override - public void invoke(boolean wait, GLRunnable glRunnable) { - drawableHelper.invoke(this, wait, glRunnable); + public boolean invoke(boolean wait, GLRunnable glRunnable) { + return helper.invoke(this, wait, glRunnable); } @Override public GLContext setContext(GLContext newCtx) { final GLContext oldCtx = context; - final boolean newCtxCurrent = drawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; if(newCtxCurrent) { context.makeCurrent(); @@ -736,12 +741,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void setAutoSwapBufferMode(boolean onOrOff) { - drawableHelper.setAutoSwapBufferMode(onOrOff); + helper.setAutoSwapBufferMode(onOrOff); } @Override public boolean getAutoSwapBufferMode() { - return drawableHelper.getAutoSwapBufferMode(); + return helper.getAutoSwapBufferMode(); } @Override @@ -849,7 +854,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable disposeOnEDTAction = new Runnable() { @Override public void run() { - drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); + helper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); } }; @@ -897,7 +902,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable initAction = new Runnable() { @Override public void run() { - drawableHelper.init(GLCanvas.this); + helper.init(GLCanvas.this); } }; @@ -910,11 +915,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } // Note: we ignore the given x and y within the parent component // since we are drawing directly into this heavyweight component. - drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); + helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); sendReshape = false; } - drawableHelper.display(GLCanvas.this); + helper.display(GLCanvas.this); } }; @@ -931,14 +936,14 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable displayOnEDTAction = new Runnable() { @Override public void run() { - drawableHelper.invokeGL(drawable, context, displayAction, initAction); + helper.invokeGL(drawable, context, displayAction, initAction); } }; private final Runnable swapBuffersOnEDTAction = new Runnable() { @Override public void run() { - drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction); + helper.invokeGL(drawable, context, swapBuffersAction, initAction); } }; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index c6c7cf9a1..cd18c5098 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -125,7 +125,7 @@ import com.jogamp.opengl.util.GLBuffers; public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol { private static final boolean DEBUG = Debug.debug("GLJPanel"); - private GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private GLDrawableHelper helper = new GLDrawableHelper(); private volatile boolean isInitialized; // Data used for either pbuffers or pixmap-based offscreen surfaces @@ -413,32 +413,37 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public void addGLEventListener(GLEventListener listener) { - drawableHelper.addGLEventListener(listener); + helper.addGLEventListener(listener); } @Override public void addGLEventListener(int index, GLEventListener listener) { - drawableHelper.addGLEventListener(index, listener); + helper.addGLEventListener(index, listener); } @Override public void removeGLEventListener(GLEventListener listener) { - drawableHelper.removeGLEventListener(listener); + helper.removeGLEventListener(listener); } @Override + public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.removeGLEventListener(index); + } + + @Override public void setAnimator(GLAnimatorControl animatorControl) { - drawableHelper.setAnimator(animatorControl); + helper.setAnimator(animatorControl); } @Override public GLAnimatorControl getAnimator() { - return drawableHelper.getAnimator(); + return helper.getAnimator(); } @Override - public void invoke(boolean wait, GLRunnable glRunnable) { - drawableHelper.invoke(this, wait, glRunnable); + public boolean invoke(boolean wait, GLRunnable glRunnable) { + return helper.invoke(this, wait, glRunnable); } @Override @@ -461,7 +466,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return null; } final GLContext oldCtx = backend.getContext(); - final boolean newCtxCurrent = drawableHelper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags); + final boolean newCtxCurrent = helper.switchContext(backend.getDrawable(), oldCtx, newCtx, additionalCtxCreationFlags); backend.setContext(newCtx); if(newCtxCurrent) { newCtx.makeCurrent(); @@ -662,13 +667,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (!backend.preGL(g)) { return; } - drawableHelper.init(GLJPanel.this); + helper.init(GLJPanel.this); backend.postGL(g, false); } @Override public void dispose(GLAutoDrawable drawable) { - drawableHelper.dispose(GLJPanel.this); + helper.dispose(GLJPanel.this); } @Override @@ -680,11 +685,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (DEBUG) { System.err.println(getThreadName()+": GLJPanel.display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")"); } - drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight); + helper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight); sendReshape = false; } - drawableHelper.display(GLJPanel.this); + helper.display(GLJPanel.this); backend.postGL(g, true); } @@ -716,7 +721,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private final Runnable disposeAction = new Runnable() { @Override public void run() { - drawableHelper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); + helper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); } }; @@ -1035,7 +1040,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } if (offscreenDrawable != null) { final AbstractGraphicsDevice adevice = offscreenDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); - offscreenDrawable.destroy(); + offscreenDrawable.setRealized(false); offscreenDrawable = null; if(null != adevice) { adevice.close(); @@ -1094,7 +1099,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override protected void doPaintComponentImpl() { - drawableHelper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction); + helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction); } @Override @@ -1711,7 +1716,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing ((Java2DGLContext) joglContext).setGraphics(g); } - drawableHelper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction); + helper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction); } } finally { j2dContext.release(); diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index 3f50fe420..5c6d7446a 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -31,6 +31,8 @@ package jogamp.opengl; import java.io.PrintStream; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode; import javax.media.opengl.FPSCounter; import javax.media.opengl.GL; import javax.media.opengl.GLAnimatorControl; @@ -76,7 +78,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { /** Returns the delegated GLDrawable */ public final GLDrawable getDelegatedDrawable() { return drawable; } - protected void defaultRepaintOp() { + /** Default implementation to handle repaint events from the windowing system */ + protected void defaultWindowRepaintOp() { if( null != drawable && drawable.isRealized() ) { if( !drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) { display(); @@ -84,16 +87,74 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } } - protected void defaultReshapeOp() { + /** Default implementation to handle resize events from the windowing system */ + protected void defaultWindowResizedOp() { if( null!=drawable ) { if(DEBUG) { System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); } sendReshape = true; - defaultRepaintOp(); + defaultWindowRepaintOp(); } } - + + /** Default implementation to handle destroy notifications from the windowing system */ + protected void defaultWindowDestroyNotifyOp() { + final NativeSurface ns = getNativeSurface(); + final boolean shallClose; + if(ns instanceof WindowClosingProtocol) { + shallClose = WindowClosingMode.DISPOSE_ON_CLOSE == ((WindowClosingProtocol)ns).getDefaultCloseOperation(); + } else { + shallClose = true; + } + if( shallClose ) { + // Is an animator thread perform rendering? + if (helper.isExternalAnimatorRunning()) { + // Pause animations before initiating safe destroy. + final GLAnimatorControl ctrl = helper.getAnimator(); + final boolean isPaused = ctrl.pause(); + destroy(); + if(isPaused) { + ctrl.resume(); + } + } else if (null != ns && ns.isSurfaceLockedByOtherThread()) { + // surface is locked by another thread + // Flag that destroy should be performed on the next + // attempt to display. + sendDestroy = true; + } else { + // Without an external thread animating or locking the + // surface, we are safe. + destroy (); + } + } + } + + /** + * Default implementation to destroys the drawable and context of this GLAutoDrawable: + * <ul> + * <li>issues the GLEventListener dispose call, if drawable and context are valid</li> + * <li>destroys the GLContext, if valid</li> + * <li>destroys the GLDrawable, if valid</li> + * </ul> + */ + protected void defaultDestroyOp() { + if( null != drawable && drawable.isRealized() ) { + if( null != context && context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.disposeGL(this, drawable, context, null); + } catch (GLException gle) { + gle.printStackTrace(); + } + } + drawable.setRealized(false); + } + context = null; + drawable = null; + } + // // GLAutoDrawable // @@ -157,8 +218,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } @Override - public final void addGLEventListener(int index, GLEventListener listener) - throws IndexOutOfBoundsException { + public final void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException { helper.addGLEventListener(index, listener); } @@ -166,7 +226,12 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { public final void removeGLEventListener(GLEventListener listener) { helper.removeGLEventListener(listener); } - + + @Override + public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.removeGLEventListener(index); + } + @Override public final void setAnimator(GLAnimatorControl animatorControl) throws GLException { @@ -179,8 +244,8 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } @Override - public final void invoke(boolean wait, GLRunnable glRunnable) { - helper.invoke(this, wait, glRunnable); + public final boolean invoke(boolean wait, GLRunnable glRunnable) { + return helper.invoke(this, wait, glRunnable); } @Override diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index e7651eaab..0c01aa676 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -61,13 +61,13 @@ public class GLDrawableHelper { private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); protected static final boolean DEBUG = GLDrawableImpl.DEBUG; - private Object listenersLock = new Object(); - private ArrayList<GLEventListener> listeners; - private HashSet<GLEventListener> listenersToBeInit; + private final Object listenersLock = new Object(); + private final ArrayList<GLEventListener> listeners = new ArrayList<GLEventListener>(); + private final HashSet<GLEventListener> listenersToBeInit = new HashSet<GLEventListener>(); + private final Object glRunnablesLock = new Object(); + private volatile ArrayList<GLRunnableTask> glRunnables = new ArrayList<GLRunnableTask>(); private boolean autoSwapBufferMode; private Thread skipContextReleaseThread; - private Object glRunnablesLock = new Object(); - private ArrayList<GLRunnable> glRunnables; private GLAnimatorControl animatorCtrl; public GLDrawableHelper() { @@ -76,13 +76,13 @@ public class GLDrawableHelper { public final void reset() { synchronized(listenersLock) { - listeners = new ArrayList<GLEventListener>(); - listenersToBeInit = new HashSet<GLEventListener>(); + listeners.clear(); + listenersToBeInit.clear(); } autoSwapBufferMode = true; skipContextReleaseThread = null; synchronized(glRunnablesLock) { - glRunnables = new ArrayList<GLRunnable>(); + glRunnables.clear(); } animatorCtrl = null; } @@ -105,6 +105,46 @@ public class GLDrawableHelper { return sb.toString(); } + /** + * Associate a new context to the drawable and also propagates the context/drawable switch by + * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. + * <p> + * If the old context's drawable was an {@link GLAutoDrawable}, it's reference to the given drawable + * is being cleared by calling + * {@link GLAutoDrawable#setContext(GLContext) ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null)}. + * </p> + * <p> + * If the old or new context was current on this thread, it is being released before switching the drawable. + * </p> + * + * @param drawable the drawable which context is changed + * @param newCtx the new context + * @param oldCtx the old context + * @return true if the newt context was current, otherwise false + * + * @see GLAutoDrawable#setContext(GLContext) + */ + public final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int additionalCtxCreationFlags) { + if(null != oldCtx && oldCtx.isCurrent()) { + oldCtx.release(); + } + final boolean newCtxCurrent; + if(null!=newCtx) { + newCtxCurrent = newCtx.isCurrent(); + if(newCtxCurrent) { + newCtx.release(); + } + newCtx.setContextCreationFlags(additionalCtxCreationFlags); + newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch + } else { + newCtxCurrent = false; + } + if(null!=oldCtx && oldCtx.getGLDrawable() instanceof GLAutoDrawable) { + ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null); + } + return newCtxCurrent; + } + public final void addGLEventListener(GLEventListener listener) { addGLEventListener(-1, listener); } @@ -128,6 +168,16 @@ public class GLDrawableHelper { } } + public final GLEventListener removeGLEventListener(int index) + throws IndexOutOfBoundsException { + synchronized(listenersLock) { + if(0>index) { + index = listeners.size()-1; + } + return listeners.remove(index); + } + } + /** * Issues {@link javax.media.opengl.GLEventListener#dispose(javax.media.opengl.GLAutoDrawable)} * to all listeners. @@ -144,18 +194,19 @@ public class GLDrawableHelper { } } } - - private boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { + + private final boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { if(listenersToBeInit.remove(l)) { l.init(drawable); if(sendReshape) { - reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false); + reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */); } return true; } return false; } + /** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */ public final void init(GLAutoDrawable drawable) { synchronized(listenersLock) { for (int i=0; i < listeners.size(); i++) { @@ -166,7 +217,7 @@ public class GLDrawableHelper { // hence the must always be initialized unconditional. listenersToBeInit.add(listener); - if ( ! init( listener, drawable, false ) ) { + if ( ! init( listener, drawable, true /* sendReshape */) ) { throw new GLException("GLEventListener "+listener+" already initialized: "+drawable); } } @@ -179,24 +230,26 @@ public class GLDrawableHelper { displayImpl(drawable); } } - private void displayImpl(GLAutoDrawable drawable) { + private final void displayImpl(GLAutoDrawable drawable) { synchronized(listenersLock) { for (int i=0; i < listeners.size(); i++) { final GLEventListener listener = listeners.get(i) ; // GLEventListener may need to be init, // in case this one is added after the realization of the GLAutoDrawable - init( listener, drawable, true ) ; + init( listener, drawable, true /* sendReshape */) ; listener.display(drawable); } } } - private void reshape(GLEventListener listener, GLAutoDrawable drawable, - int x, int y, int width, int height, boolean setViewport, boolean checkInit) { + private final void reshape(GLEventListener listener, GLAutoDrawable drawable, + int x, int y, int width, int height, boolean setViewport, boolean checkInit) { if(checkInit) { // GLEventListener may need to be init, - // in case this one is added after the realization of the GLAutoDrawable - init( listener, drawable, false ) ; + // in case this one is added after the realization of the GLAutoDrawable + synchronized(listenersLock) { + init( listener, drawable, false /* sendReshape */) ; + } } if(setViewport) { drawable.getGL().glViewport(x, y, width, height); @@ -212,27 +265,50 @@ public class GLDrawableHelper { } } - private boolean execGLRunnables(GLAutoDrawable drawable) { + private final boolean execGLRunnables(GLAutoDrawable drawable) { boolean res = true; - if(glRunnables.size()>0) { + if(glRunnables.size()>0) { // volatile OK // swap one-shot list asap - ArrayList<GLRunnable> _glRunnables = null; + final ArrayList<GLRunnableTask> _glRunnables; synchronized(glRunnablesLock) { if(glRunnables.size()>0) { _glRunnables = glRunnables; - glRunnables = new ArrayList<GLRunnable>(); + glRunnables = new ArrayList<GLRunnableTask>(); + } else { + _glRunnables = null; } } if(null!=_glRunnables) { for (int i=0; i < _glRunnables.size(); i++) { - res = _glRunnables.get(i).run(drawable) && res; + res = _glRunnables.get(i).run(drawable) && res; } } } return res; } + public final void flushGLRunnables() { + if(glRunnables.size()>0) { // volatile OK + // swap one-shot list asap + final ArrayList<GLRunnableTask> _glRunnables; + synchronized(glRunnablesLock) { + if(glRunnables.size()>0) { + _glRunnables = glRunnables; + glRunnables = new ArrayList<GLRunnableTask>(); + } else { + _glRunnables = null; + } + } + + if(null!=_glRunnables) { + for (int i=0; i < _glRunnables.size(); i++) { + _glRunnables.get(i).flush(); + } + } + } + } + public final void setAnimator(GLAnimatorControl animator) throws GLException { synchronized(glRunnablesLock) { if(animatorCtrl!=animator && null!=animator && null!=animatorCtrl) { @@ -264,10 +340,28 @@ public class GLDrawableHelper { return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ; } - public final void invoke(GLAutoDrawable drawable, boolean wait, GLRunnable glRunnable) { - if( null == drawable || null == glRunnable ) { - return; + /** + * <p> + * If <code>wait</code> is <code>true</code> the call blocks until the <code>glRunnable</code> + * has been executed.<p> + * <p> + * If <code>wait</code> is <code>true</code> <b>and</b> + * {@link GLDrawable#isRealized()} returns <code>false</code> <i>or</i> {@link GLAutoDrawable#getContext()} returns <code>null</code>, + * the call is ignored and returns <code>false</code>.<br> + * This helps avoiding deadlocking the caller. + * </p> + * + * @param drawable the {@link GLAutoDrawable} to be used + * @param wait if <code>true</code> block until execution of <code>glRunnable</code> is finished, otherwise return immediatly w/o waiting + * @param glRunnable the {@link GLRunnable} to execute within {@link #display()} + * @return <code>true</code> if the {@link GLRunnable} has been processed or queued, otherwise <code>false</code>. + */ + public final boolean invoke(GLAutoDrawable drawable, boolean wait, GLRunnable glRunnable) { + if( null == glRunnable || null == drawable || + wait && ( !drawable.isRealized() || null==drawable.getContext() ) ) { + return false; } + Throwable throwable = null; GLRunnableTask rTask = null; Object rTaskLock = new Object(); @@ -299,6 +393,7 @@ public class GLDrawableHelper { } } } + return true; } public final void setAutoSwapBufferMode(boolean enable) { @@ -439,6 +534,7 @@ public class GLDrawableHelper { try { if(isDisposeAction) { context.destroy(); + flushGLRunnables(); } else if( GLContext.CONTEXT_NOT_CURRENT != res ) { context.release(); } @@ -526,6 +622,7 @@ public class GLDrawableHelper { try { if(isDisposeAction) { context.destroy(); + flushGLRunnables(); ctxDestroyed = true; } else if( res != GLContext.CONTEXT_NOT_CURRENT && (null == skipContextReleaseThread || currentThread != skipContextReleaseThread) ) { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index b3884830a..58a4ac6b4 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -70,20 +70,6 @@ public abstract class GLDrawableImpl implements GLDrawable { return (GLDrawableFactoryImpl) getFactory(); } - /** For offscreen GLDrawables (pbuffers and "pixmap" drawables), - indicates that native resources should be reclaimed. */ - public void destroy() { - surface.getGraphicsConfiguration().getScreen().getDevice().lock(); - try { - destroyImpl(); - } finally { - surface.getGraphicsConfiguration().getScreen().getDevice().unlock(); - } - } - protected void destroyImpl() { - throw new GLException("Should not call this (should only be called for offscreen GLDrawables)"); - } - @Override public final void swapBuffers() throws GLException { if( !realized ) { @@ -164,7 +150,7 @@ public abstract class GLDrawableImpl implements GLDrawable { AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice(); if(realizedArg) { if(NativeSurface.LOCK_SURFACE_NOT_READY >= lockSurface()) { - throw new GLException("GLDrawableImpl.setRealized(true): already realized, but surface not ready (lockSurface)"); + throw new GLException("GLDrawableImpl.setRealized(true): Surface not ready (lockSurface)"); } } else { aDevice.lock(); diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index d98b41bdc..a8277fd71 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -40,7 +40,6 @@ package jogamp.opengl; -import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; @@ -114,36 +113,19 @@ public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { @Override public void destroy() { - if(drawable.isRealized()) { - final AbstractGraphicsDevice adevice = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); - - if (null != context && context.isCreated()) { - try { - helper.disposeGL(GLPbufferImpl.this, drawable, context, null); - } catch (GLException gle) { - gle.printStackTrace(); - } - context = null; - // drawableHelper.reset(); - } - drawable.destroy(); - drawable = null; - - if(null != adevice) { - adevice.close(); - } - } + defaultDestroyOp(); } @Override public GLDrawableFactory getFactory() { - return drawable.getFactory(); + return drawable.getFactory(); } @Override public void display() { - if( null == drawable || !drawable.isRealized() || null == context ) { return; } + if( null != drawable && drawable.isRealized() && null != context ) { helper.invokeGL(drawable, context, defaultDisplayAction, initAction); + } } //---------------------------------------------------------------------- diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java index 448f68423..244a3fd79 100644 --- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java +++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java @@ -39,7 +39,8 @@ public class GLRunnableTask implements GLRunnable { GLRunnable runnable; Object notifyObject; boolean catchExceptions; - boolean isExecuted; + volatile boolean isExecuted; + volatile boolean isFlushed; Throwable runnableException; @@ -48,6 +49,7 @@ public class GLRunnableTask implements GLRunnable { this.notifyObject = notifyObject ; this.catchExceptions = catchExceptions; isExecuted = false; + isFlushed = false; } public boolean run(GLAutoDrawable drawable) { @@ -84,8 +86,41 @@ public class GLRunnableTask implements GLRunnable { } return res; } - + + /** + * Simply flush this task and notify a waiting executor. + * The executor which might have been blocked until notified + * will be unblocked and the task removed from the queue. + * + * @see #isFlushed() + * @see #isInQueue() + */ + public void flush() { + if(!isExecuted() && null != notifyObject) { + synchronized (notifyObject) { + isFlushed=true; + notifyObject.notifyAll(); + } + } + } + + /** + * @return !{@link #isExecuted()} && !{@link #isFlushed()} + */ + public boolean isInQueue() { return !isExecuted && !isFlushed; } + + /** + * @return whether this task has been executed. + * @see #isInQueue() + */ public boolean isExecuted() { return isExecuted; } + + /** + * @return whether this task has been flushed. + * @see #isInQueue() + */ + public boolean isFlushed() { return isFlushed; } + public Throwable getThrowable() { return runnableException; } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index f18b8cd02..b2217c095 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -56,11 +56,6 @@ public class EGLPbufferDrawable extends EGLDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { final AbstractGraphicsConfiguration config = getNativeSurface().getGraphicsConfiguration(); final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index cae60702b..257635b8c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -151,8 +151,7 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { if (haveSetOpenGLMode) { throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once"); } - - destroyImpl(); + setRealized(false); if (DEBUG) { System.err.println("MacOSXCGLDrawable: Switching context mode " + openGLMode + " -> " + mode); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 6bdabbf59..4e9d18fed 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -250,7 +250,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } } } - drawable.destroy(); + drawable.setRealized(false); } } sr = new SharedResource(sharedDevice, madeCurrent, hasNPOTTextures, hasRECTTextures, hasAppleFloatPixels); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index 33021c521..242cea068 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -80,11 +80,6 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected void setRealizedImpl() { if(realized) { createPbuffer(); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java index dc3b58cfa..296d53ce3 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java @@ -62,11 +62,6 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected void setRealizedImpl() { if(realized) { createBitmap(); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java index 244c1553f..05d6d9862 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java @@ -70,7 +70,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { System.err.println("WindowsDummyWGLDrawable: "+config); } } catch (Throwable t) { - destroyImpl(); + setRealized(false); throw new GLException(t); } finally { unlockSurface(); @@ -96,11 +96,14 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { } @Override - protected void destroyImpl() { - if (handleHwndLifecycle && hwnd != 0) { - GDI.ShowWindow(hwnd, GDI.SW_HIDE); - GDIUtil.DestroyDummyWindow(hwnd); - hwnd = 0; + protected void setRealizedImpl() { + super.setRealizedImpl(); + if(!realized) { + if (handleHwndLifecycle && hwnd != 0) { + GDI.ShowWindow(hwnd, GDI.SW_HIDE); + GDIUtil.DestroyDummyWindow(hwnd); + hwnd = 0; + } } } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java index 762bea3b1..b00c796ec 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java @@ -67,11 +67,6 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected void setRealizedImpl() { if(realized) { createPbuffer(); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index ddcb898a9..ca7886e7f 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -62,15 +62,13 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl { @Override protected void setRealizedImpl() { - if(!realized) { - return; // nothing todo .. - } - - NativeSurface ns = getNativeSurface(); - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration(); - config.updateGraphicsConfiguration(getFactory(), ns, null); - if (DEBUG) { - System.err.println("WindowsWGLDrawable.setRealized(true): "+config); + if(realized) { + NativeSurface ns = getNativeSurface(); + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration(); + config.updateGraphicsConfiguration(getFactory(), ns, null); + if (DEBUG) { + System.err.println("WindowsWGLDrawable.setRealized(true): "+config); + } } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 054e1fe90..176d27a71 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -373,7 +373,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } if (null != sr.drawable) { - sr.drawable.destroy(); + sr.drawable.setRealized(false); sr.drawable = null; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java index 65f65a2ec..8914e2db9 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java @@ -86,13 +86,17 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable { public int getHeight() { return 1; } - + + @Override - protected void destroyImpl() { - if(0!=dummyWindow) { - destroyHandle(); - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration(); - X11Lib.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow); + protected void setRealizedImpl() { + super.setRealizedImpl(); + if(!realized) { + if(0!=dummyWindow) { + destroyHandle(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration(); + X11Lib.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow); + } } } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 77af0d698..9a563bdb8 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -304,7 +304,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { if (null != sr.drawable) { // may cause JVM SIGSEGV: - sr.drawable.destroy(); + sr.drawable.setRealized(false); sr.drawable = null; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java index 29003ef52..cdf81ebd3 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java @@ -59,11 +59,6 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected void setRealizedImpl() { if(realized) { createPbuffer(); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java index 18aa780b6..1e7b89828 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java @@ -59,11 +59,6 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { } @Override - protected void destroyImpl() { - setRealized(false); - } - - @Override protected void setRealizedImpl() { if(realized) { createPixmap(); diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 6a328ed07..96baab3ae 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -53,7 +53,6 @@ import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import jogamp.newt.WindowImpl; @@ -109,37 +108,17 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind window.addWindowListener(new WindowAdapter() { @Override public void windowRepaint(WindowUpdateEvent e) { - defaultRepaintOp(); + defaultWindowRepaintOp(); } @Override public void windowResized(WindowEvent e) { - defaultReshapeOp(); + defaultWindowResizedOp(); } @Override public void windowDestroyNotify(WindowEvent e) { - if( WindowClosingMode.DISPOSE_ON_CLOSE == GLWindow.this.getDefaultCloseOperation() ) { - // Is an animator thread perform rendering? - if (GLWindow.this.helper.isExternalAnimatorRunning()) { - // Pause animations before initiating safe destroy. - final GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator(); - boolean isPaused = ctrl.pause(); - destroy(); - if(isPaused) { - ctrl.resume(); - } - } else if (GLWindow.this.window.isWindowLockedByOtherThread()) { - // Window is locked by another thread - // Flag that destroy should be performed on the next - // attempt to display. - sendDestroy = true; - } else { - // Without an external thread animating or locking the - // surface, we are safe. - destroy (); - } - } + defaultWindowDestroyNotifyOp(); } }); this.window.setLifecycleHook(new GLLifecycleHook()); @@ -453,20 +432,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind //e1.printStackTrace(); } - if( window.isNativeValid() && null != drawable && drawable.isRealized() ) { - if( null != context && context.isCreated() ) { - // Catch dispose GLExceptions by GLEventListener, just 'print' them - // so we can continue with the destruction. - try { - helper.disposeGL(GLWindow.this, drawable, context, null); - } catch (GLException gle) { - gle.printStackTrace(); - } - } - drawable.setRealized(false); - } - context = null; - drawable = null; + defaultDestroyOp(); if(Window.DEBUG_IMPLEMENTATION) { System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin"); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java index be9ae223b..a2d060a8c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateNEWT.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -30,60 +30,95 @@ package com.jogamp.opengl.test.junit.jogl.acore; import java.io.IOException; -import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLAutoDrawableDelegate; import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import org.junit.Assert; import org.junit.Test; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.event.WindowUpdateEvent; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; -import com.jogamp.opengl.test.junit.util.NEWTGLContext; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.test.junit.util.UITestCase; +/** + * Demonstrates a full featured custom GLAutoDrawable implementation + * utilizing {@link GLAutoDrawableDelegate}. + */ public class TestGLAutoDrawableDelegateNEWT extends UITestCase { - @Test - public void test01() throws GLException, InterruptedException { - final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow( - new GLCapabilities(GLProfile.getGL2ES2()), 640, 480, false); - winctx.context.release(); + /** Note: Creates a full featured GLAutoDrawable w/ all window events connected. */ + private GLAutoDrawable createGLAutoDrawable(GLCapabilities caps, int x, int y, int width, int height, WindowListener wl) throws InterruptedException { + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + window.setPosition(x, y); + window.setSize(width, height); + window.setVisible(true); + Assert.assertTrue(AWTRobotUtil.waitForVisible(window, true)); + Assert.assertTrue(AWTRobotUtil.waitForRealized(window, true)); + + GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); + GLDrawable drawable = factory.createGLDrawable(window); + Assert.assertNotNull(drawable); + + drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); + + GLContext context = drawable.createContext(null); + Assert.assertNotNull(context); + + int res = context.makeCurrent(); + Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); + context.release(); + + final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(drawable, context) { + @Override + public void destroy() { + super.destroy(); // destroys drawable/context + window.destroy(); // destroys the actual window + } + }; - final GLAutoDrawableDelegate glad = new GLAutoDrawableDelegate(winctx.drawable, winctx.context); - glad.addGLEventListener(new GearsES2(1)); - // add basic window interaction - winctx.window.addWindowListener(new WindowAdapter() { + window.addWindowListener(new WindowAdapter() { @Override public void windowRepaint(WindowUpdateEvent e) { - glad.defaultRepaintOp(); + glad.defaultWindowRepaintOp(); } @Override public void windowResized(WindowEvent e) { - glad.defaultReshapeOp(); + glad.defaultWindowResizedOp(); } @Override public void windowDestroyNotify(WindowEvent e) { - final GLAnimatorControl ctrl = glad.getAnimator(); - boolean isPaused = ctrl.pause(); - glad.destroy(); - NEWTGLContext.destroyWindow(winctx); - if(isPaused) { - ctrl.resume(); - } + glad.defaultWindowDestroyNotifyOp(); } }); + window.addWindowListener(wl); + return glad; + } + + @Test + public void test01() throws GLException, InterruptedException { final QuitAdapter quitAdapter = new QuitAdapter(); - winctx.window.addWindowListener(quitAdapter); - + GLAutoDrawable glad = createGLAutoDrawable(new GLCapabilities(GLProfile.getGL2ES2()), 0, 0, 640, 480, quitAdapter); + glad.addGLEventListener(new GearsES2(1)); + final Animator animator = new Animator(glad); animator.setUpdateFPSFrames(60, null); animator.start(); @@ -93,7 +128,8 @@ public class TestGLAutoDrawableDelegateNEWT extends UITestCase { } animator.stop(); - NEWTGLContext.destroyWindow(winctx); + + glad.destroy(); } static long duration = 2000; // ms diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java index 22ed7c6fd..41c69336c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java @@ -66,6 +66,57 @@ public class TestParenting01cSwingAWT extends UITestCase { glCaps = new GLCapabilities(null); } + static class GLDisturbanceAction implements Runnable { + public boolean isRunning = false; + private volatile boolean shallStop = false; + private final GLAutoDrawable glad; + private final GLRunnable glRunnable; + + public GLDisturbanceAction(GLAutoDrawable glad) { + this.glad = glad; + this.glRunnable = new GLRunnableDummy(); + } + + public void waitUntilRunning() { + synchronized(this) { + while(!isRunning) { + try { + this.wait(); + } catch (InterruptedException e) { e.printStackTrace(); } + } + } + } + + public void stopAndWaitUntilDone() { + shallStop = true; + synchronized(this) { + while(isRunning) { + try { + this.wait(); + } catch (InterruptedException e) { e.printStackTrace(); } + } + } + } + + public void run() { + synchronized(this) { + isRunning = true; + this.notifyAll(); + System.out.println("$"); + } + while(!shallStop) { + try { + glad.invoke(true, glRunnable); + Thread.sleep(100); + } catch (Throwable t) {} + } + synchronized(this) { + isRunning = false; + this.notifyAll(); + } + } + } + @Test public void testWindowParenting01CreateVisibleDestroy1() throws InterruptedException, InvocationTargetException { /** @@ -84,22 +135,9 @@ public class TestParenting01cSwingAWT extends UITestCase { animator1.setUpdateFPSFrames(1, null); animator1.start(); - final GLWindow _glWindow1 = glWindow1; - final GLRunnable _glRunnable = new GLRunnableDummy(); - Thread disturbanceThread = new Thread(new Runnable() { - public void run() { - System.out.println("$"); - while(true) - { - try { - _glWindow1.invoke(true, _glRunnable); - Thread.sleep(100); - } catch (Throwable t) {} - } - } - }); - disturbanceThread.start(); - + final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1); + new Thread(disturbanceAction).start(); + disturbanceAction.waitUntilRunning(); final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); Assert.assertNotNull(newtCanvasAWT); @@ -175,6 +213,7 @@ public class TestParenting01cSwingAWT extends UITestCase { } }); Assert.assertEquals(true, glWindow1.isNativeValid()); + disturbanceAction.stopAndWaitUntilDone(); glWindow1.destroy(); Assert.assertEquals(false, glWindow1.isNativeValid()); } @@ -192,26 +231,33 @@ public class TestParenting01cSwingAWT extends UITestCase { glWindow1.setTitle("testWindowParenting01CreateVisibleDestroy"); GLEventListener demo1 = new RedSquareES2(); setDemoFields(demo1, glWindow1, false); + /* + glWindow1.addGLEventListener(new GLEventListener() { + @Override + public void init(GLAutoDrawable drawable) { + System.err.println("XXX init"); + } + @Override + public void dispose(GLAutoDrawable drawable) { + System.err.println("XXX dispose"); + // Thread.dumpStack(); + } + @Override + public void display(GLAutoDrawable drawable) {} + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + System.err.println("XXX reshape"); + // Thread.dumpStack(); + } + }); */ glWindow1.addGLEventListener(demo1); Animator animator1 = new Animator(glWindow1); animator1.setUpdateFPSFrames(1, null); animator1.start(); - - final GLWindow _glWindow1 = glWindow1; - final GLRunnable _glRunnable = new GLRunnableDummy(); - Thread disturbanceThread = new Thread(new Runnable() { - public void run() { - System.out.println("$"); - while(true) - { - try { - _glWindow1.invoke(true, _glRunnable); - Thread.sleep(100); - } catch (Throwable t) {} - } - } - }); - disturbanceThread.start(); + + final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1); + new Thread(disturbanceAction).start(); + disturbanceAction.waitUntilRunning(); final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); Assert.assertNotNull(newtCanvasAWT); @@ -298,6 +344,8 @@ public class TestParenting01cSwingAWT extends UITestCase { animator1.stop(); Assert.assertEquals(false, animator1.isAnimating()); + disturbanceAction.stopAndWaitUntilDone(); + SwingUtilities.invokeAndWait(new Runnable() { public void run() { jFrame1.setVisible(false); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java index bc3988338..8e2c73e9d 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java @@ -111,8 +111,8 @@ public class TestParenting02NEWT extends UITestCase { Assert.assertEquals(height,glWindow1.getHeight()); glWindow1.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - PARENT"); glWindow1.setPosition(x,y); - glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); - glWindow1.addWindowListener(new TraceWindowAdapter()); + //glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + //glWindow1.addWindowListener(new TraceWindowAdapter()); GLEventListener demo1 = new RedSquareES2(); setDemoFields(demo1, window1, glWindow1, false); @@ -132,8 +132,8 @@ public class TestParenting02NEWT extends UITestCase { //Assert.assertEquals(height/2,glWindow2.getHeight()); glWindow2.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - CHILD"); glWindow2.setPosition(glWindow1.getWidth()/2, glWindow1.getHeight()/2); - glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); - glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); + //glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + //glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); // glWindow2.addMouseListener(new TraceMouseAdapter()); GLEventListener demo2 = new GearsES2(); |