summaryrefslogtreecommitdiffstats
path: root/src/jogl
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java141
-rw-r--r--src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java10
-rwxr-xr-xsrc/jogl/classes/com/jogamp/opengl/util/Animator.java20
-rw-r--r--src/jogl/classes/javax/media/opengl/GLAutoDrawable.java100
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLCanvas.java19
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java13
6 files changed, 218 insertions, 85 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
index 8fefe149e..1e954af1d 100644
--- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
+++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
@@ -46,75 +46,123 @@ import javax.media.opengl.*;
methods to be able to share it between GLCanvas and GLJPanel. */
public class GLDrawableHelper {
- private volatile List listeners = new ArrayList();
private static final boolean DEBUG = Debug.debug("GLDrawableHelper");
private static final boolean VERBOSE = Debug.verbose();
- private static final boolean NVIDIA_CRASH_WORKAROUND = Debug.isPropertyDefined("jogl.nvidia.crash.workaround", true);
+ private Object listenersLock = new Object();
+ private List listeners = new ArrayList();
+ private Set listenersToBeInit = new HashSet();
private boolean autoSwapBufferMode = true;
+ private Object glRunnablesLock = new Object();
private ArrayList glRunnables = new ArrayList(); // one shot GL tasks
+ private Thread animatorThread = null; // default
public GLDrawableHelper() {
}
- public synchronized String toString() {
+ public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("GLEventListeners num "+listeners.size()+" [");
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- sb.append(iter.next()+", ");
+ synchronized(listenersLock) {
+ sb.append("GLEventListeners num "+listeners.size()+" [");
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ Object l = iter.next();
+ sb.append(l);
+ sb.append("[init ");
+ sb.append( !listenersToBeInit.contains(l) );
+ sb.append("], ");
+ }
}
sb.append("]");
return sb.toString();
}
- public synchronized void addGLEventListener(GLEventListener listener) {
+ public void addGLEventListener(GLEventListener listener) {
addGLEventListener(-1, listener);
}
- public synchronized void addGLEventListener(int index, GLEventListener listener) {
- if(0>index) {
- index = listeners.size();
+ public void addGLEventListener(int index, GLEventListener listener) {
+ synchronized(listenersLock) {
+ if(0>index) {
+ index = listeners.size();
+ }
+ listenersToBeInit.add(listener);
+ listeners.add(index, listener);
}
- List newListeners = (List) ((ArrayList) listeners).clone();
- newListeners.add(index, listener);
- listeners = newListeners;
}
- public synchronized void removeGLEventListener(GLEventListener listener) {
- List newListeners = (List) ((ArrayList) listeners).clone();
- newListeners.remove(listener);
- listeners = newListeners;
+ public void removeGLEventListener(GLEventListener listener) {
+ synchronized(listenersLock) {
+ listeners.remove(listener);
+ listenersToBeInit.remove(listener);
+ }
}
- public synchronized void dispose(GLAutoDrawable drawable) {
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- ((GLEventListener) iter.next()).dispose(drawable);
+ public void dispose(GLAutoDrawable drawable) {
+ synchronized(listenersLock) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ GLEventListener listener = (GLEventListener) iter.next() ;
+ listener.dispose(drawable);
+ listenersToBeInit.add(listener);
+ }
}
}
+ 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 */);
+ }
+ return true;
+ }
+ return false;
+ }
+
public void init(GLAutoDrawable drawable) {
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- ((GLEventListener) iter.next()).init(drawable);
+ synchronized(listenersLock) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ GLEventListener listener = (GLEventListener) iter.next() ;
+ if ( ! init( listener, drawable, false ) ) {
+ throw new GLException("GLEventListener "+listener+" already initialized: "+drawable);
+ }
+ }
}
}
public void display(GLAutoDrawable drawable) {
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- ((GLEventListener) iter.next()).display(drawable);
+ synchronized(listenersLock) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ GLEventListener listener = (GLEventListener) iter.next() ;
+ // GLEventListener may need to be init,
+ // in case this one is added after the realization of the GLAutoDrawable
+ init( listener, drawable, true ) ;
+ listener.display(drawable);
+ }
}
execGLRunnables(drawable);
}
- public void reshape(GLAutoDrawable drawable,
- int x, int y, int width, int height) {
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- ((GLEventListener) iter.next()).reshape(drawable, x, y, width, height);
+ private final void reshape(GLEventListener listener, GLAutoDrawable drawable,
+ int x, int y, int width, int height, boolean setViewport) {
+ if(setViewport) {
+ drawable.getGL().glViewport(x, y, width, height);
+ }
+ listener.reshape(drawable, x, y, width, height);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ synchronized(listenersLock) {
+ int i=0;
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); i++) {
+ reshape((GLEventListener) iter.next(), drawable, x, y, width, height, 0==i);
+ }
}
}
private void execGLRunnables(GLAutoDrawable drawable) {
if(glRunnables.size()>0) {
+ // swap one-shot list asap
ArrayList _glRunnables = null;
- synchronized(glRunnables) {
+ synchronized(glRunnablesLock) {
if(glRunnables.size()>0) {
_glRunnables = glRunnables;
glRunnables = new ArrayList();
@@ -128,23 +176,38 @@ public class GLDrawableHelper {
}
}
- private void invokeLater(GLRunnable glRunnable) {
- synchronized(glRunnables) {
- glRunnables.add(glRunnable);
- glRunnables.notifyAll();
+ public void setAnimator(Thread animator) throws GLException {
+ synchronized(glRunnablesLock) {
+ if(animator!=animatorThread && null!=animator && null!=animatorThread) {
+ throw new GLException("Trying to register animator thread "+animator+", where "+animatorThread+" is already registered. Unregister first.");
+ }
+ animatorThread = animator;
+ }
+ }
+
+ public Thread getAnimator() {
+ synchronized(glRunnablesLock) {
+ return animatorThread;
}
}
- public void invoke(boolean wait, GLRunnable glRunnable) {
- if(glRunnable == null) {
+ public void invoke(GLAutoDrawable drawable, boolean wait, GLRunnable glRunnable) {
+ if( null == drawable || null == glRunnable ) {
return;
}
- Object lock = new Object();
- GLRunnableTask rTask = new GLRunnableTask(glRunnable, wait?lock:null/*, true*/);
Throwable throwable = null;
+ Object lock = new Object();
+ GLRunnableTask rTask = null;
synchronized(lock) {
- invokeLater(rTask);
- if( wait ) {
+ boolean callDisplay;
+ synchronized(glRunnablesLock) {
+ callDisplay = null == animatorThread || animatorThread == Thread.currentThread() ;
+ rTask = new GLRunnableTask(glRunnable, ( !callDisplay && wait ) ? lock : null);
+ glRunnables.add(rTask);
+ }
+ if( callDisplay ) {
+ drawable.display();
+ } else if( wait ) {
try {
lock.wait();
} catch (InterruptedException ie) {
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java
index 071ac1378..c2efb3f4e 100644
--- a/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java
@@ -138,8 +138,16 @@ public class GLPbufferImpl implements GLPbuffer {
drawableHelper.removeGLEventListener(listener);
}
+ public void setAnimator(Thread animator) {
+ drawableHelper.setAnimator(animator);
+ }
+
+ public Thread getAnimator() {
+ return drawableHelper.getAnimator();
+ }
+
public void invoke(boolean wait, GLRunnable glRunnable) {
- drawableHelper.invoke(wait, glRunnable);
+ drawableHelper.invoke(this, wait, glRunnable);
}
public void setContext(GLContext ctx) {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 15b9d5eb9..66d3d5b88 100755
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -218,6 +218,9 @@ public class Animator {
} else {
thread = new Thread(threadGroup, runnable);
}
+ for(Iterator iter = drawables.iterator(); iter.hasNext(); ) {
+ ((GLAutoDrawable) iter.next()).setAnimator(thread);
+ }
thread.start();
}
@@ -241,15 +244,16 @@ public class Animator {
// dependencies on the Animator's internal thread. Currently we
// use a couple of heuristics to determine whether we should do
// the blocking wait().
- if (impl.skipWaitForStop(thread)) {
- return;
- }
-
- while (shouldStop && thread != null) {
- try {
- wait();
- } catch (InterruptedException ie) {
+ if (!impl.skipWaitForStop(thread)) {
+ while (shouldStop && thread != null) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ }
}
}
+ for(Iterator iter = drawables.iterator(); iter.hasNext(); ) {
+ ((GLAutoDrawable) iter.next()).setAnimator(null);
+ }
}
}
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 7236aa533..1b5c56c95 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -161,14 +161,49 @@ public interface GLAutoDrawable extends GLDrawable {
during this update cycle. */
public void removeGLEventListener(GLEventListener listener);
+ /**
+ * <p>
+ * Indicates whether a running animator thread is periodically issuing {@link #display()} calls or not.</p><br>
+ * <p>
+ * This method shall be called by an animator implementation only,<br>
+ * e.g. {@link com.jogamp.opengl.util.Animator#start()}, passing the animator thread,<br>
+ * and {@link com.jogamp.opengl.util.Animator#start()}, passing <code>null</code>.</p><br>
+ * <p>
+ * Impacts {@link #display()} and {@link #invoke(boolean, GLRunnable)} semantics.</p><br>
+ *
+ * @param animator <code>null</code> reference indicates no running animator thread
+ * issues {@link #display()} calls on this <code>GLAutoDrawable</code>,<br>
+ * a valid reference indicates a running animator thread
+ * periodically issuing {@link #display()} calls.
+ *
+ * @throws GLException if a running animator thread is already registered and you try to register a different one without unregistering the previous one.
+ * @see #display()
+ * @see #invoke(boolean, GLRunnable)
+ */
+ public void setAnimator(Thread animator) throws GLException;
+
+ /**
+ * @return the value of the registered animator thread
+ *
+ * @see #setAnimator(Thread)
+ */
+ public Thread getAnimator();
+
/**
- * Enqueues the one-shot {@link javax.media.opengl.GLRunnable} into the queue,
- * which will be executed at the next {@link #display()} call.
* <p>
- * Warning: We cannot verify if the caller runs in the same thread
- * as the display caller, hence we cannot avoid a deadlock
- * in such case. You have to know what you are doing,
- * ie call this only in a I/O event listener, or such.<br></p>
+ * Enqueues a one-shot {@link javax.media.opengl.GLRunnable},
+ * which will be executed with the next {@link #display()} call.</p><br>
+ * <p>
+ * If {@link #setAnimator(Thread)} has not registered no running animator thread, the default,<br>
+ * or if the current thread is the animator thread,<br>
+ * a {@link #display()} call has to be issued after enqueueing the <code>GLRunnable</code>.<br>
+ * No extra synchronization must be performed in case <code>wait</code> is true, since it is executed in the current thread.</p><br>
+ * <p>
+ * If {@link #setAnimator(Thread)} has registered a valid animator thread,<br>
+ * no call of {@link #display()} must be issued, since the animator thread performs it.<br>
+ * If <code>wait</code> is true, the implementation must wait until the <code>GLRunnable</code> is excecuted.</p><br>
+ *
+ * @see #setAnimator(Thread)
* @see #display()
* @see javax.media.opengl.GLRunnable
*/
@@ -190,28 +225,37 @@ public interface GLAutoDrawable extends GLDrawable {
routine may be called manually. */
public void destroy();
- /** <p>Causes OpenGL rendering to be performed for this GLAutoDrawable
- in the following order:
- <ul>
- <li> Calling {@link GLEventListener#display display(..)} for all
- registered {@link GLEventListener}s. </li>
- <li> Execute and dismiss all one-shot {@link javax.media.opengl.GLRunnable},
- enqueued via {@link #invoke(boolean, GLRunnable)}.</li>
- </ul></p>
- <p>
- Called automatically by the
- window system toolkit upon receiving a repaint() request.</p>
- <p>
- This routine may be called manually for better control over the
- rendering process. It is legal to call another GLAutoDrawable's
- display method from within the {@link GLEventListener#display
- display(..)} callback.</p>
- <p>
- In case of a new generated OpenGL context,
- the implementation shall call {@link GLEventListener#init init(..)} for all
- registered {@link GLEventListener}s <i>before</i> making the
- actual {@link GLEventListener#display display(..)} calls,
- in case this has not been done yet.</p> */
+ /**
+ * <p>
+ * Causes OpenGL rendering to be performed for this GLAutoDrawable
+ * in the following order:
+ * <ul>
+ * <li> Calling {@link GLEventListener#display display(..)} for all
+ * registered {@link GLEventListener}s. </li>
+ * <li> Executes all one-shot {@link javax.media.opengl.GLRunnable},
+ * enqueued via {@link #invoke(boolean, GLRunnable)}.</li>
+ * </ul></p>
+ * <p>
+ * Called automatically by the
+ * window system toolkit upon receiving a repaint() request,
+ * except a running animator thread is registered with {@link #setAnimator(Thread)}.</p> <br>
+ * <p>
+ * Maybe called periodically by a running animator thread,<br>
+ * which must register itself with {@link #setAnimator(Thread)}.</p> <br>
+ * <p>
+ * This routine may be called manually for better control over the
+ * rendering process. It is legal to call another GLAutoDrawable's
+ * display method from within the {@link GLEventListener#display
+ * display(..)} callback.</p>
+ * <p>
+ * In case of a new generated OpenGL context,
+ * the implementation shall call {@link GLEventListener#init init(..)} for all
+ * registered {@link GLEventListener}s <i>before</i> making the
+ * actual {@link GLEventListener#display display(..)} calls,
+ * in case this has not been done yet.</p>
+ *
+ * @see #setAnimator(Thread)
+ */
public void display();
/** Enables or disables automatic buffer swapping for this drawable.
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
index 2dafd691a..f150b2507 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java
@@ -378,7 +378,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
return;
}
- display();
+ if( null == getAnimator() ) {
+ display();
+ }
}
/** Overridden to track when this component is added to a container.
@@ -492,8 +494,16 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
drawableHelper.removeGLEventListener(listener);
}
+ public void setAnimator(Thread animator) {
+ drawableHelper.setAnimator(animator);
+ }
+
+ public Thread getAnimator() {
+ return drawableHelper.getAnimator();
+ }
+
public void invoke(boolean wait, GLRunnable glRunnable) {
- drawableHelper.invoke(wait, glRunnable);
+ drawableHelper.invoke(this, wait, glRunnable);
}
public void setContext(GLContext ctx) {
@@ -640,10 +650,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
if (sendReshape) {
// Note: we ignore the given x and y within the parent component
// since we are drawing directly into this heavyweight component.
- int width = getWidth();
- int height = getHeight();
- getGL().glViewport(0, 0, width, height);
- drawableHelper.reshape(GLCanvas.this, 0, 0, width, height);
+ drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight());
sendReshape = false;
}
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index 73962e979..d0d97fe31 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -380,8 +380,16 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
drawableHelper.removeGLEventListener(listener);
}
+ public void setAnimator(Thread animator) {
+ drawableHelper.setAnimator(animator);
+ }
+
+ public Thread getAnimator() {
+ return drawableHelper.getAnimator();
+ }
+
public void invoke(boolean wait, GLRunnable glRunnable) {
- drawableHelper.invoke(wait, glRunnable);
+ drawableHelper.invoke(this, wait, glRunnable);
}
public GLContext createContext(GLContext shareWith) {
@@ -585,9 +593,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
}
if (sendReshape) {
if (DEBUG||VERBOSE) {
- System.err.println("display: glViewport(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")");
+ System.err.println("display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")");
}
- getGL().getGL2().glViewport(viewportX, viewportY, panelWidth, panelHeight);
drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight);
sendReshape = false;
}