summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/net/java/games/jogl/GLDrawable.java12
-rw-r--r--src/net/java/games/jogl/impl/GLContext.java122
-rwxr-xr-xsrc/net/java/games/jogl/impl/GLContextInitActionPair.java58
-rwxr-xr-xsrc/net/java/games/jogl/impl/GLContextStack.java127
4 files changed, 297 insertions, 22 deletions
diff --git a/src/net/java/games/jogl/GLDrawable.java b/src/net/java/games/jogl/GLDrawable.java
index 6197688b1..26b7b0a06 100644
--- a/src/net/java/games/jogl/GLDrawable.java
+++ b/src/net/java/games/jogl/GLDrawable.java
@@ -111,9 +111,11 @@ public interface GLDrawable extends ComponentEvents {
{@link GLEventListener}s. Called automatically by the window
system toolkit upon receiving a repaint() request. When used in
conjunction with {@link
- net.java.games.jogl.GLDrawable#setRenderingThread}, this routine may be
- called manually by the application's main loop for higher
- performance and better control over the rendering process. */
+ net.java.games.jogl.GLDrawable#setRenderingThread}, this routine
+ may be called manually by the application's main loop for higher
+ performance and better control over the rendering process. It is
+ legal to call another GLDrawable's display method from within
+ {@link GLEventListener#display}. */
public void display();
/** <P> Changes this GLDrawable to allow OpenGL rendering only from
@@ -129,7 +131,9 @@ public interface GLDrawable extends ComponentEvents {
drawable. Throws {@link GLException} if the rendering thread for
this drawable has been set and attempts are made to set or clear
the rendering thread from another thread, or if the passed
- thread is not equal to the current thread or null. </P>
+ thread is not equal to the current thread or null. Also throws
+ {@link GLException} if the current thread attempts to call
+ <code>setRenderingThread</code> on more than one drawable. </P>
<P> <B>NOTE:</B> Currently this routine is only advisory, which
means that on some platforms the underlying optimizations are
diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java
index 3923ed307..e0def092a 100644
--- a/src/net/java/games/jogl/impl/GLContext.java
+++ b/src/net/java/games/jogl/impl/GLContext.java
@@ -65,11 +65,6 @@ public abstract class GLContext {
// the first event is received from the AWT event dispatch thread.
private boolean realized;
- // This avoids (as much as possible) losing the effects of
- // setRenderingThread, which may need to be deferred if the
- // component is not realized
- private boolean deferredSetRenderingThread;
-
protected GLCapabilities capabilities;
protected GLCapabilitiesChooser chooser;
protected GL gl;
@@ -83,6 +78,11 @@ public abstract class GLContext {
protected Thread renderingThread;
protected Runnable deferredReshapeAction;
+ // Error checking for setRenderingThread to ensure that one thread
+ // doesn't attempt to call setRenderingThread on more than one
+ // drawable
+ protected static final ThreadLocal perThreadRenderingContext = new ThreadLocal();
+
// This is a workaround for a bug in NVidia's drivers where
// vertex_array_range is only safe for single-threaded use; a bug
// has been filed, ID 80174. When an Animator is created for a
@@ -112,6 +112,14 @@ public abstract class GLContext {
// Cache of the functions that are available to be called at the current
// moment in time
protected FunctionAvailabilityCache functionAvailability;
+
+ // Support for recursive makeCurrent() calls as well as calling
+ // other drawables' display() methods from within another one's
+ protected static final ThreadLocal perThreadContextStack = new ThreadLocal() {
+ protected synchronized Object initialValue() {
+ return new GLContextStack();
+ }
+ };
public GLContext(Component component,
GLCapabilities capabilities,
@@ -133,7 +141,9 @@ public abstract class GLContext {
/** Runs the given runnable with this OpenGL context valid. */
public synchronized void invokeGL(Runnable runnable, boolean isReshape, Runnable initAction) throws GLException {
- Thread currentThread = null;
+ // Could be more clever about not calling this every time, but
+ // Thread.currentThread() is very fast and this makes the logic simpler
+ Thread currentThread = Thread.currentThread();
// Defer JAWT and OpenGL operations until onscreen components are
// realized
@@ -144,7 +154,7 @@ public abstract class GLContext {
if (!realized() ||
willSetRenderingThread ||
(renderingThread != null &&
- renderingThread != (currentThread = Thread.currentThread()))) {
+ renderingThread != currentThread)) {
if (isReshape) {
deferredReshapeAction = runnable;
}
@@ -157,8 +167,35 @@ public abstract class GLContext {
return;
}
- if (renderingThread == null || deferredSetRenderingThread) {
- deferredSetRenderingThread = false;
+ GLContextStack ctxStack = getPerThreadContextStack();
+ GLContext curContext = ctxStack.peekContext();
+ Runnable curInitAction = ctxStack.peekInitAction();
+ boolean mustDoMakeCurrent = true;
+ boolean mustSkipFreeForRenderingThread = false;
+ boolean mustFreeBecauseOfNoRenderingThread = false;
+
+ if (curContext == this) {
+ mustDoMakeCurrent = false;
+ }
+
+ if (currentThread == renderingThread && curContext == null) {
+ mustSkipFreeForRenderingThread = true;
+ }
+
+ if (!mustDoMakeCurrent &&
+ renderingThread == null &&
+ ctxStack.size() == 1) {
+ mustFreeBecauseOfNoRenderingThread = true;
+ }
+
+ if (mustDoMakeCurrent) {
+ if (curContext != null) {
+ if (DEBUG) {
+ System.err.println("Freeing context " + curContext + " due to recursive makeCurrent");
+ }
+ curContext.free();
+ }
+
if (!makeCurrent(initAction)) {
// Couldn't make the thread current because the component has not yet
// been visualized, and therefore the context cannot be created.
@@ -169,17 +206,23 @@ public abstract class GLContext {
}
return;
}
+ if (DEBUG) {
+ System.err.println("Making context " + this + " current");
+ }
}
+ ctxStack.push(this, initAction);
// At this point the OpenGL context is current. Offscreen contexts
// handle resizing the backing bitmap in makeCurrent. Therefore we
// may need to free and make the context current again if we
// didn't actually make it current above.
if (pendingOffscreenResize && renderingThread != null) {
+ ctxStack.pop();
free();
if (!makeCurrent(initAction)) {
throw new GLException("Error while resizing offscreen context");
}
+ ctxStack.push(this, initAction);
}
boolean caughtException = false;
@@ -199,8 +242,34 @@ public abstract class GLContext {
// Disallow setRenderingThread if display action is throwing exceptions
renderingThread = null;
}
- if (renderingThread == null) {
+
+ if (!mustFreeBecauseOfNoRenderingThread && !mustSkipFreeForRenderingThread) {
+ ctxStack.pop();
+ }
+
+ // Free the context if another one was current, but not if the
+ // setRenderingThread optimization kicks in. However, if the
+ // setRenderingThread optimization has recently been disabled,
+ // must force a free.
+ if ((mustDoMakeCurrent && !mustSkipFreeForRenderingThread) ||
+ mustFreeBecauseOfNoRenderingThread) {
+ if (mustFreeBecauseOfNoRenderingThread) {
+ // Must match previous push()
+ ctxStack.pop();
+ }
+
+ if (DEBUG) {
+ System.err.println("Freeing context " + this);
+ }
+
free();
+
+ if (curContext != null && !mustFreeBecauseOfNoRenderingThread) {
+ if (DEBUG) {
+ System.err.println("Making context " + curContext + " current again");
+ }
+ curContext.makeCurrent(curInitAction);
+ }
}
}
}
@@ -240,18 +309,29 @@ public abstract class GLContext {
if (renderingThread == null && currentThreadOrNull == null) {
throw new GLException("Attempt to clear rendering thread when already cleared");
}
+
+ Object currentThreadRenderingContext = perThreadRenderingContext.get();
+ if (currentThreadOrNull != null &&
+ currentThreadRenderingContext != null &&
+ currentThreadRenderingContext != this) {
+ throw new GLException("Attempt to call setRenderingThread on more than one drawable in this thread");
+ }
+
this.willSetRenderingThread = false;
if (currentThreadOrNull == null) {
renderingThread = null;
- if (realized()) {
- // We are guaranteed to own the context
- free();
- }
+ perThreadRenderingContext.set(null);
+ // Just in case the end user wasn't planning on drawing the
+ // drawable even once more (which would give us a chance to free
+ // the context), try to free the context now by performing an
+ // invokeGL with a do-nothing action
+ invokeGL(new Runnable() {
+ public void run() {
+ }
+ }, false, initAction);
} else {
renderingThread = currentThreadOrNull;
- if (realized()) {
- makeCurrent(initAction);
- }
+ perThreadRenderingContext.set(this);
}
}
@@ -428,7 +508,7 @@ public abstract class GLContext {
// set the current value of the proc address variable in the table object
addressField.setLong(table, newProcAddress);
if (DEBUG) {
- System.err.println(glFuncName + " = 0x" + Long.toHexString(newProcAddress));
+ // System.err.println(glFuncName + " = 0x" + Long.toHexString(newProcAddress));
}
} catch (Exception e) {
throw new GLException("Cannot get GL proc address for method \"" +
@@ -446,6 +526,12 @@ public abstract class GLContext {
textures between contexts. */
public abstract boolean isCreated();
+ /** Support for recursive makeCurrent() calls as well as calling
+ other drawables' display() methods from within another one's */
+ protected static GLContextStack getPerThreadContextStack() {
+ return (GLContextStack) perThreadContextStack.get();
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
diff --git a/src/net/java/games/jogl/impl/GLContextInitActionPair.java b/src/net/java/games/jogl/impl/GLContextInitActionPair.java
new file mode 100755
index 000000000..ed2e78ac8
--- /dev/null
+++ b/src/net/java/games/jogl/impl/GLContextInitActionPair.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package net.java.games.jogl.impl;
+
+public class GLContextInitActionPair {
+ private GLContext ctx;
+ private Runnable initAction;
+
+ public GLContextInitActionPair(GLContext ctx, Runnable initAction) {
+ this.ctx = ctx;
+ this.initAction = initAction;
+ }
+
+ public GLContext getContext() {
+ return ctx;
+ }
+
+ public Runnable getInitAction() {
+ return initAction;
+ }
+}
diff --git a/src/net/java/games/jogl/impl/GLContextStack.java b/src/net/java/games/jogl/impl/GLContextStack.java
new file mode 100755
index 000000000..dd80b0804
--- /dev/null
+++ b/src/net/java/games/jogl/impl/GLContextStack.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package net.java.games.jogl.impl;
+
+import java.util.*;
+
+/** Implements a stack of GLContext objects along with the initActions
+ that need to be run if their creation is necessary. This is used
+ to detect redundant makeCurrent() calls and to allow one drawable
+ to call display() of another from within the first drawable's
+ display() method. */
+
+public class GLContextStack {
+ private ArrayList data = new ArrayList();
+
+ /** Pushes this GLContext on the stack. The passed context must be non-null. */
+ public void push(GLContext ctx, Runnable initAction) {
+ if (ctx == null) {
+ throw new IllegalArgumentException("Null contexts are not allowed here");
+ }
+
+ data.add(new GLContextInitActionPair(ctx, initAction));
+ }
+
+ /** Removes and returns the top GLContext and associated
+ initialization action, or null if there is none. */
+ public GLContextInitActionPair pop() {
+ if (data.size() == 0) {
+ return null;
+ }
+
+ return (GLContextInitActionPair) data.remove(data.size() - 1);
+ }
+
+ /** Returns the top GLContext and associated initialization action
+ without removing it, or null if there is none. */
+ public GLContextInitActionPair peek() {
+ return peek(0);
+ }
+
+ /** Returns the <i>i</i>th GLContext and associated initialization
+ action from the top without removing it, or null if there is
+ none. */
+ public GLContextInitActionPair peek(int i) {
+ if (data.size() - i <= 0) {
+ return null;
+ }
+
+ return (GLContextInitActionPair) data.get(data.size() - i - 1);
+ }
+
+ /** Returns the top GLContext without removing it, or null if there
+ is none. */
+ public GLContext peekContext() {
+ return peekContext(0);
+ }
+
+ /** Returns the <i>i</i>th GLContext from the top without removing
+ it, or null if there is none. */
+ public GLContext peekContext(int i) {
+ GLContextInitActionPair pair = peek(i);
+ if (pair == null) {
+ return null;
+ }
+
+ return pair.getContext();
+ }
+
+ /** Returns the top initialization action without removing it, or
+ null if there is none. */
+ public Runnable peekInitAction() {
+ return peekInitAction(0);
+ }
+
+ /** Returns the <i>i</i>th initialization action from the top
+ without removing it, or null if there is none. */
+ public Runnable peekInitAction(int i) {
+ GLContextInitActionPair pair = peek(i);
+ if (pair == null) {
+ return null;
+ }
+
+ return pair.getInitAction();
+ }
+
+ /** Returns the number of entries on the GLContext stack. */
+ public int size() {
+ return data.size();
+ }
+}