diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/net/java/games/jogl/GLDrawable.java | 12 | ||||
-rw-r--r-- | src/net/java/games/jogl/impl/GLContext.java | 122 | ||||
-rwxr-xr-x | src/net/java/games/jogl/impl/GLContextInitActionPair.java | 58 | ||||
-rwxr-xr-x | src/net/java/games/jogl/impl/GLContextStack.java | 127 |
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(); + } +} |