From c002e04f848116922a1ed7bd96ead54961649bbd Mon Sep 17 00:00:00 2001
From: Sven Gothel
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
+ * After {@link #addGLEventListener(GLEventListener) adding} a {@link GLEventListener} it is
+ * marked uninitialized and added to a list of to be initialized {@link GLEventListener}.
+ * If such uninitialized {@link GLEventListener}'s handler methods (reshape, display)
+ * are about to be invoked, it's {@link GLEventListener#init(GLAutoDrawable) init(..)} method is invoked first.
+ * Afterwards the {@link GLEventListener} is marked initialized
+ * and removed from the list of to be initialized {@link GLEventListener}.
+ *
+ * This methods returns the {@link GLEventListener} initialized state,
+ * i.e. returns
+ * This methods allows manually setting the {@link GLEventListener} initialized state,
+ * i.e. adding it to, or removing it from the list of to be initialized {@link GLEventListener}.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ *
+ * Warning: This method does not validate whether the given {@link GLEventListener listener's}
+ * is member of this drawable queue, i.e. {@link #addGLEventListener(GLEventListener) added}.
+ *
+ * This method is only exposed to allow users full control over the {@link GLEventListener}'s state
+ * and is usually not recommended to change.
+ *
+ * One use case is moving a {@link GLContext} and their initialized {@link GLEventListener}
+ * from one {@link GLAutoDrawable} to another,
+ * where a subsequent {@link GLEventListener#init(GLAutoDrawable) init(..)} call after adding it
+ * to the new owner is neither required nor desired.
+ * See {@link com.jogamp.opengl.util.GLDrawableUtil#swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable) swapGLContextAndAllGLEventListener(..)}.
+ *
+ * If
+ * If an {@link GLAnimatorControl} is being attached and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ *
+ * Note that this is an expensive operation, since {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * is decorated by {@link GLContext#makeCurrent()} and {@link GLContext#release()}.
+ *
+ * Use {@link #removeGLEventListener(GLEventListener) removeGLEventListener(listener)} instead
+ * if you just want to remove the {@link GLEventListener listener} and don't care about the disposal of the it's (OpenGL) resources.
+ *
+ * Also note that 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
+ *
+ * This is an inexpensive operation, since the removed listener's
+ * {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)} method will not be called.
+ *
+ * Use {@link #disposeGLEventListener(GLEventListener, boolean) disposeGLEventListener(listener, true)}
+ * instead to ensure disposal of the {@link GLEventListener listener}'s (OpenGL) resources.
+ *
* Note that if this is done from within a particular drawable's
- * {@link GLEventListener} handler (reshape, display, etc.) that it is not
+ * {@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
+ *
* Registers the usage of an animator, an {@link javax.media.opengl.GLAnimatorControl} implementation.
@@ -236,25 +339,25 @@ public interface GLAutoDrawable extends GLDrawable {
public GLAnimatorControl getAnimator();
/**
- *
* Enqueues a one-shot {@link GLRunnable},
* which will be executed within the next {@link #display()} call
* after all registered {@link GLEventListener}s
* {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
* methods has been called.
- *
* If no {@link GLAnimatorControl} is animating (default),false
if it is included in the list of to be initialized {@link GLEventListener},
+ * otherwise true
.
+ * true
, mark the listener initialized, otherwise uninitialized.
+ */
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized);
+
+ /**
+ * Disposes the given {@link GLEventListener listener} via {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * if it has been initialized and added to this queue.
+ * remove
is true
, the {@link GLEventListener} is removed from this drawable queue before disposal,
+ * otherwise marked uninitialized.
+ * remove
is true
+ * @param remove pass true
to have the listener
removed from this drawable queue, otherwise pass false
+ * @return the disposed and/or removed GLEventListener, or null if no action was performed, i.e. listener was not added
*/
- public void removeGLEventListener(GLEventListener listener);
-
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove);
+
/**
- * Removes a {@link GLEventListener} at the given index from this drawable.
+ * Removes the given {@link GLEventListener listener} from this drawable queue.
+ *
* or if the current thread is the animator thread,
- * a {@link #display()} call is issued after enqueue the GLRunnable
.
- * No extra synchronization is performed in case wait
is true, since it is executed in the current thread.GLRunnable
,
+ * hence the {@link GLRunnable} will be executed right away.
+ *
- * If an {@link GLAnimatorControl} is animating,
- * no {@link #display()} call is issued, since the animator thread performs it.
+ * If an {@link GLAnimatorControl animator} is running,
+ * no explicit {@link #display()} call is issued, allowing the {@link GLAnimatorControl animator} to perform it when it's due.
*
* If wait
is true
the call blocks until the glRunnable
- * has been executed.
+ * has been executed by the {@link GLAnimatorControl animator}, otherwise the method returns immediately. + *
*
* If wait
is true
and
* {@link #isRealized()} returns false
or {@link #getContext()} returns null
,
@@ -266,16 +369,40 @@ public interface GLAutoDrawable extends GLDrawable {
* where all blocked callers are being notified.
*
true
block until execution of glRunnable
is finished, otherwise return immediatly w/o waiting
+ * @param wait if true
block until execution of glRunnable
is finished, otherwise return immediately w/o waiting
* @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
* @return true
if the {@link GLRunnable} has been processed or queued, otherwise false
.
*
* @see #setAnimator(GLAnimatorControl)
* @see #display()
* @see GLRunnable
+ * @see #enqueue(GLRunnable)
*/
public boolean invoke(boolean wait, GLRunnable glRunnable);
+ /**
+ * Enqueues a one-shot {@link GLRunnable},
+ * which will be executed within the next {@link #display()} call
+ * after all registered {@link GLEventListener}s
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * methods has been called.
+ * + * Unlike the {@link #invoke(boolean, GLRunnable)}, this method only enqueues the {@link GLRunnable} + * w/o taking care of it's execution. Hence either a performing {@link GLAnimatorControl animator} + * or explicit user call shall trigger {@link #display()} to ensure it's execution. + *
+ *+ * Method return immediately w/o waiting or blocking + *
+ * + * @param glRunnable the {@link GLRunnable} to execute within the next {@link #display()} call + * + * @see #invoke(boolean, GLRunnable) + * @see #display() + * @see GLRunnable + */ + public void enqueue(GLRunnable glRunnable); + /** Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext. If a window is attached to it's implementation, it shall be closed. diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 1e9fcc95e..5b5f800a4 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -495,7 +495,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing (int) ((getHeight() + bounds.getHeight()) / 2)); return; } - if( ! this.helper.isExternalAnimatorAnimating() ) { + if( ! this.helper.isAnimatorAnimatingOnOtherThread() ) { display(); } } @@ -699,15 +699,37 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } @Override - public void removeGLEventListener(GLEventListener listener) { - helper.removeGLEventListener(listener); + public int getGLEventListenerCount() { + return helper.getGLEventListenerCount(); } @Override - public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { - return helper.removeGLEventListener(index); + public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.getGLEventListener(index); + } + + @Override + public boolean getGLEventListenerInitState(GLEventListener listener) { + return helper.getGLEventListenerInitState(listener); + } + + @Override + public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) { + helper.setGLEventListenerInitState(listener, initialized); } + @Override + public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) { + final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove); + Threading.invoke(true, r, getTreeLock()); + return r.listener; + } + + @Override + public GLEventListener removeGLEventListener(GLEventListener listener) { + return helper.removeGLEventListener(listener); + } + @Override public void setAnimator(GLAnimatorControl animatorControl) { helper.setAnimator(animatorControl); @@ -723,6 +745,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing return helper.invoke(this, wait, glRunnable); } + @Override + public void enqueue(GLRunnable glRunnable) { + helper.enqueue(glRunnable); + } + @Override public GLContext setContext(GLContext newCtx) { final RecursiveLock _lock = lock; @@ -984,15 +1011,12 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } }; - // Workaround for ATI driver bugs related to multithreading issues - // like simultaneous rendering via Animators to canvases that are - // being resized on the AWT event dispatch thread private final Runnable displayOnEDTAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; _lock.lock(); - try { + try { helper.invokeGL(drawable, context, displayAction, initAction); } finally { _lock.unlock(); @@ -1015,6 +1039,26 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } }; + private class DisposeGLEventListenerAction implements Runnable { + GLEventListener listener; + private boolean remove; + private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) { + this.listener = listener; + this.remove = remove; + } + + @Override + public void run() { + final RecursiveLock _lock = lock; + _lock.lock(); + try { + listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove); + } finally { + _lock.unlock(); + } + } + }; + // Disables the AWT's erasing of this Canvas's background on Windows // in Java SE 6. This internal API is not available in previous // releases, but the system property diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index d0b9fb913..08d70211b 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -426,15 +426,47 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } @Override - public void removeGLEventListener(GLEventListener listener) { - helper.removeGLEventListener(listener); + public int getGLEventListenerCount() { + return helper.getGLEventListenerCount(); } @Override - public GLEventListener removeGLEventListener(int index) throws IndexOutOfBoundsException { - return helper.removeGLEventListener(index); - } + public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException { + return helper.getGLEventListener(index); + } + + @Override + public boolean getGLEventListenerInitState(GLEventListener listener) { + return helper.getGLEventListenerInitState(listener); + } + + @Override + public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) { + helper.setGLEventListenerInitState(listener, initialized); + } + + @Override + public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) { + final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove); + if (EventQueue.isDispatchThread()) { + r.run(); + } else { + // Multithreaded redrawing of Swing components is not allowed, + // so do everything on the event dispatch thread + try { + EventQueue.invokeAndWait(r); + } catch (Exception e) { + throw new GLException(e); + } + } + return r.listener; + } + @Override + public GLEventListener removeGLEventListener(GLEventListener listener) { + return helper.removeGLEventListener(listener); + } + @Override public void setAnimator(GLAnimatorControl animatorControl) { helper.setAnimator(animatorControl); @@ -450,6 +482,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return helper.invoke(this, wait, glRunnable); } + @Override + public void enqueue(GLRunnable glRunnable) { + helper.enqueue(glRunnable); + } + @Override public GLContext createContext(GLContext shareWith) { return (null != backend) ? backend.createContext(shareWith) : null; @@ -685,7 +722,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public void dispose(GLAutoDrawable drawable) { - helper.dispose(GLJPanel.this); + helper.disposeAllGLEventListener(GLJPanel.this, false); } @Override @@ -758,6 +795,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } }; + private class DisposeGLEventListenerAction implements Runnable { + GLEventListener listener; + private boolean remove; + private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) { + this.listener = listener; + this.remove = remove; + } + + @Override + public void run() { + listener = helper.disposeGLEventListener(GLJPanel.this, backend.getDrawable(), backend.getContext(), listener, remove); + } + }; + private int getNextPowerOf2(int number) { // Workaround for problems where 0 width or height are transiently // seen during layout -- cgit v1.2.3