diff options
author | Kenneth Russel <[email protected]> | 2005-07-10 23:17:43 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2005-07-10 23:17:43 +0000 |
commit | 8a4e964a88703bcab4a8888b25ea9e997953180a (patch) | |
tree | 073e1a11d44a0f4cb407419c90f89aee0979403d /src/net | |
parent | 6e8dd12319e2d6f702cf66728b177e6ea0152c2c (diff) |
Initial set of context-related changes for the JSR-231 API. GLContext
has been exposed in the public API. The GLEventListener callback
mechanism has been removed from the core GLContext implementation and
moved up to a higher level. GLAutoDrawable now contains the
GLEventListener-related methods, and the GLEventListener's methods now
receive a GLAutoDrawable as argument. All JOGL demos have been updated
for the new APIs. Many FIXMEs and much unimplemented functionality
remain. There is slightly different initialization behavior for the
demos containing pbuffers, and the deferring of reshape callbacks
needs to be rethought.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JSR-231@320 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/net')
30 files changed, 1070 insertions, 1302 deletions
diff --git a/src/net/java/games/jogl/Animator.java b/src/net/java/games/jogl/Animator.java index ebb6d9aed..06fb25cca 100644 --- a/src/net/java/games/jogl/Animator.java +++ b/src/net/java/games/jogl/Animator.java @@ -68,11 +68,6 @@ public class Animator { /** Creates a new Animator for a particular drawable. */ public Animator(GLDrawable drawable) { this.drawable = drawable; - - // Workaround for NVidia driver bug 80174 - if (drawable instanceof GLCanvas) { - ((GLCanvas) drawable).willSetRenderingThread(); - } } /** Starts this animator. */ @@ -85,23 +80,6 @@ public class Animator { public void run() { boolean noException = false; try { - // Try to get OpenGL context optimization since we know we - // will be rendering this one drawable continually from - // this thread; make the context current once instead of - // making it current and freeing it each frame. - drawable.setRenderingThread(Thread.currentThread()); - - // Since setRenderingThread is currently advisory (because - // of the poor JAWT implementation in the Motif AWT, which - // performs excessive locking) we also prevent repaint(), - // which is called from the AWT thread, from having an - // effect for better multithreading behavior. This call is - // not strictly necessary, but if end users write their - // own animation loops which update multiple drawables per - // tick then it may be necessary to enforce the order of - // updates. - drawable.setNoAutoRedrawMode(true); - while (!shouldStop) { noException = false; drawable.display(); @@ -109,25 +87,9 @@ public class Animator { } } finally { shouldStop = false; - drawable.setNoAutoRedrawMode(false); - try { - // The surface is already unlocked and rendering - // thread is already null if an exception occurred - // during display(), so don't disable the rendering - // thread again. - if (noException) { - // Destruction of the underlying GLContext may have - // disabled the setRenderingThread optimization out - // from under us - if (drawable.getRenderingThread() != null) { - drawable.setRenderingThread(null); - } - } - } finally { - synchronized (Animator.this) { - thread = null; - Animator.this.notify(); - } + synchronized (Animator.this) { + thread = null; + Animator.this.notify(); } } } diff --git a/src/net/java/games/jogl/impl/GLContextInitActionPair.java b/src/net/java/games/jogl/GLAutoDrawable.java index 379dda3ee..2b7528069 100755 --- a/src/net/java/games/jogl/impl/GLContextInitActionPair.java +++ b/src/net/java/games/jogl/GLAutoDrawable.java @@ -20,7 +20,7 @@ * 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 - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * 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 @@ -37,22 +37,18 @@ * and developed by Kenneth Bradley Russell and Christopher John Kline. */ -package net.java.games.jogl.impl; +package net.java.games.jogl; -public class GLContextInitActionPair { - private GLContext ctx; - private Runnable initAction; +public interface GLAutoDrawable extends GLDrawable, ComponentEvents { + /** Adds a {@link GLEventListener} to this drawable. If multiple + listeners are added to a given drawable, they are notified of + events in an arbitrary order. */ + public void addGLEventListener(GLEventListener listener); - public GLContextInitActionPair(GLContext ctx, Runnable initAction) { - this.ctx = ctx; - this.initAction = initAction; - } - - public GLContext getContext() { - return ctx; - } - - public Runnable getInitAction() { - return initAction; - } + /** 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. */ + public void removeGLEventListener(GLEventListener listener); } diff --git a/src/net/java/games/jogl/GLCanvas.java b/src/net/java/games/jogl/GLCanvas.java index f73a006ae..e7a15ccf9 100644 --- a/src/net/java/games/jogl/GLCanvas.java +++ b/src/net/java/games/jogl/GLCanvas.java @@ -43,6 +43,7 @@ import java.awt.Canvas; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; import net.java.games.jogl.impl.*; // FIXME: Subclasses need to call resetGLFunctionAvailability() on their @@ -57,20 +58,21 @@ import net.java.games.jogl.impl.*; instantiated directly; use {@link GLDrawableFactory} to construct them. */ -public final class GLCanvas extends Canvas implements GLDrawable { +public class GLCanvas extends Canvas implements GLAutoDrawable { protected static final boolean DEBUG = Debug.debug("GLCanvas"); private GLDrawableHelper drawableHelper = new GLDrawableHelper(); - private GLContext context; - - GLCanvas(GraphicsConfiguration config, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, - GLDrawable shareWith) { - super(config); - context = GLContextFactory.getFactory().createGLContext(this, capabilities, chooser, - GLContextHelper.getContext(shareWith)); + private GLContextImpl context; + + public GLCanvas(GLCapabilities capabilities, + GLCapabilitiesChooser chooser, + GLDrawable shareWith, + GraphicsDevice device) { + super(GLDrawableFactory.getFactory().chooseGraphicsConfiguration(capabilities, chooser, device)); + context = (GLContextImpl) GLContextFactory.getFactory().createGLContext(this, capabilities, chooser, + GLContextHelper.getContext(shareWith)); + context.setSynchronized(true); } public void display() { @@ -82,9 +84,7 @@ public final class GLCanvas extends Canvas implements GLDrawable { /** Overridden from Canvas; calls {@link #display}. Should not be invoked by applications directly. */ public void paint(Graphics g) { - if (!context.getNoAutoRedrawMode()) { - display(); - } + display(); } /** Overridden from Canvas; used to indicate when it's safe to @@ -127,7 +127,7 @@ public final class GLCanvas extends Canvas implements GLDrawable { }; final Runnable reshapeOnEDTRunnable = new Runnable() { public void run() { - context.invokeGL(reshapeRunnable, true, initAction); + drawableHelper.invokeGL(context, reshapeRunnable, true, initAction); } }; maybeDoSingleThreadedWorkaround(reshapeOnEDTRunnable, reshapeRunnable, true); @@ -163,26 +163,6 @@ public final class GLCanvas extends Canvas implements GLDrawable { context.setGLU(glu); } - void willSetRenderingThread() { - context.willSetRenderingThread(); - } - - public void setRenderingThread(Thread currentThreadOrNull) throws GLException { - context.setRenderingThread(currentThreadOrNull, initAction); - } - - public Thread getRenderingThread() { - return context.getRenderingThread(); - } - - public void setNoAutoRedrawMode(boolean noAutoRedraw) { - context.setNoAutoRedrawMode(noAutoRedraw); - } - - public boolean getNoAutoRedrawMode() { - return context.getNoAutoRedrawMode(); - } - public void setAutoSwapBufferMode(boolean onOrOff) { context.setAutoSwapBufferMode(onOrOff); } @@ -233,7 +213,7 @@ public final class GLCanvas extends Canvas implements GLDrawable { throw new GLException(e); } } else { - context.invokeGL(invokeGLAction, isReshape, initAction); + drawableHelper.invokeGL(context, invokeGLAction, isReshape, initAction); } } @@ -263,14 +243,14 @@ public final class GLCanvas extends Canvas implements GLDrawable { // being resized on the AWT event dispatch thread class DisplayOnEventDispatchThreadAction implements Runnable { public void run() { - context.invokeGL(displayAction, false, initAction); + drawableHelper.invokeGL(context, displayAction, false, initAction); } } private DisplayOnEventDispatchThreadAction displayOnEventDispatchThreadAction = new DisplayOnEventDispatchThreadAction(); class SwapBuffersOnEventDispatchThreadAction implements Runnable { public void run() { - context.invokeGL(swapBuffersAction, false, initAction); + drawableHelper.invokeGL(context, swapBuffersAction, false, initAction); } } private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction = diff --git a/src/net/java/games/jogl/GLContext.java b/src/net/java/games/jogl/GLContext.java new file mode 100755 index 000000000..3e12b542c --- /dev/null +++ b/src/net/java/games/jogl/GLContext.java @@ -0,0 +1,156 @@ +/* + * 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; + +public abstract class GLContext { + public static final int CONTEXT_NOT_CURRENT = 0; + public static final int CONTEXT_CURRENT = 1; + public static final int CONTEXT_CURRENT_NEW = 2; + + private static ThreadLocal currentContext = new ThreadLocal(); + + /** + * Returns the GLDrawable to which this context may be used to + * draw. + */ + // FIXME + // public abstract GLDrawable getGLDrawable(); + + /** + * Makes this GLContext current on the calling thread. + * + * There are two return values that indicate success and one that + * indicates failure. A return value of CONTEXT_CURRENT_NEW + * indicates that that context has been made current, and that + * this is the first time this context has been made current, or + * that the state of the underlying context or drawable may have + * changed since the last time this context was made current. In + * this case, the application may wish to initialize the state. A + * return value of CONTEXT_CURRENT indicates that the context has + * been made currrent, with its previous state restored. + * + * If the context could not be made current (for example, because + * the underlying drawable has not ben realized on the display) , + * a value of CONTEXT_NOT_CURRENT is returned. + * + * If the context is in use by another thread at the time of the + * call, then if isSynchronized() is true the call will + * block. If isSynchronized() is false, an exception will be + * thrown and the context will remain current on the other thread. + * + * @return CONTEXT_CURRENT if the context was successfully made current + * @return CONTEXT_CURRENT_NEW if the context was successfully made + * current, but need to be initialized. + * + * @return CONTEXT_NOT_CURRENT if the context could not be made current. + * + * @throws GLException if synchronization is disabled and the + * context is current on another thread, or because the context + * could not be created or made current due to non-recoverable, + * window system-specific errors. + */ + public abstract int makeCurrent() throws GLException; + + /** + * Releases control of this GLContext from the current thread. + * + * @throw GLException if the context had not previously been made + * current on the current thread + */ + public abstract void release() throws GLException; + + /** + * Returns the context which is current on the current thread. If no + * context is current, returns null. + * + * @return the context current on this thread, or null if no context + * is current. + */ + public static GLContext getCurrent() { + return (GLContext) currentContext.get(); + } + + /** + * Sets the current context object on the current thread. This + * method is called by GLContext implementations during {@link + * #makeCurrent} and does not need to be called by end users. + * + */ + public static void setCurrent(GLContext cur) { + currentContext.set(cur); + } + + /** + * For onscreen GLDrawables, indicates to the GLContext + * implementation that the underlying window has been created and + * can be drawn into. + */ + public abstract void setRealized(); + + /** + * Destroys this OpenGL context and frees its associated resources. + * <P> + * For onscreen GLDrawables, should be used to indicate to the + * GLContext implementation that the underlying window has been + * destroyed. + */ + public abstract void destroy(); + + /** + * Returns true if 'makeCurrent' will exhibit synchronized behavior. + */ + public abstract boolean isSynchronized(); + + /** + * Determines whether 'makeCurrent' will exhibit synchronized behavior. + */ + public abstract void setSynchronized(boolean isSynchronized); + + // 'GL' and 'GLU' pipelines allow instrumenting the actual + // pipeline for debugging, tracing, etc. + + public abstract GL getGL(); + + public abstract GLU getGLU(); + + public abstract void setGL(GL gl); + + public abstract void setGLU(GLU glu); +} diff --git a/src/net/java/games/jogl/GLDrawable.java b/src/net/java/games/jogl/GLDrawable.java index 9ca86ca79..93fa6c580 100644 --- a/src/net/java/games/jogl/GLDrawable.java +++ b/src/net/java/games/jogl/GLDrawable.java @@ -39,8 +39,6 @@ package net.java.games.jogl; -import java.awt.Dimension; - // FIXME: We need some way to tell when the device upon which the canvas is // being displayed has changed (e.g., the user drags the canvas's parent // window from one screen on multi-screen environment to another, when the @@ -67,32 +65,16 @@ import java.awt.Dimension; GLCanvas} and {@link GLJPanel}. */ public interface GLDrawable extends ComponentEvents { - /** Adds a {@link GLEventListener} to this drawable. If multiple - listeners are added to a given drawable, they are notified of - events in an arbitrary order. */ - public void addGLEventListener(GLEventListener listener); - - /** 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. */ - public void removeGLEventListener(GLEventListener listener); - - /** Sets the size of this GLDrawable. */ + /** Requests a new width and height for this GLDrawable. Not all + drawables are able to respond to this request and may silently + ignore it. */ public void setSize(int width, int height); - /** Sets the size of this GLDrawable. */ - public void setSize(Dimension d); - - /** Returns the size of this GLDrawable as a newly-created Dimension - object. */ - public Dimension getSize(); + /** Returns the current width of this GLDrawable. */ + public int getWidth(); - /** Stores the size of this GLDrawable into the user-provided - Dimension object, returning that object. If the provided - Dimension is null a new one will be allocated and returned. */ - public Dimension getSize(Dimension d); + /** Returns the current height of this GLDrawable. */ + public int getHeight(); /** Returns the {@link GL} pipeline object this GLDrawable uses. If this method is called outside of the {@link GLEventListener}'s @@ -130,58 +112,6 @@ public interface GLDrawable extends ComponentEvents { {@link GLEventListener#display}. */ public void display(); - /** <P> Changes this GLDrawable to allow OpenGL rendering only from - the supplied thread, which must either be the current thread or - null. Attempts by other threads to perform OpenGL operations - like rendering or resizing the window will be ignored as long as - the thread is set. Setting up the rendering thread is not - required but enables the system to perform additional - optimizations, in particular when the application requires - control over the rendering loop. Before exiting, - <code>setRenderingThread(null)</code> must be called or other - threads will be unable to perform OpenGL rendering to this - 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. 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 - disabled and setting the rendering thread has no effect. - Applications should not rely on setRenderingThread to prevent - rendering from other threads. <P> - - @throws GLException if the rendering thread for this drawable has - been set by another thread or if the passed thread is not equal - to the current thread or null - */ - public void setRenderingThread(Thread currentThreadOrNull) throws GLException; - - /** Returns the rendering thread for this drawable, or null if none - has been set. */ - public Thread getRenderingThread(); - - /** Disables automatic redraws of this drawable if possible. This is - provided as an overriding mechanism for applications which - perform animation on the drawable and for which the (currently - advisory) {@link #setRenderingThread} does not provide strict - enough guarantees. Its sole purpose is to avoid deadlocks that - are unfortunately all too easy to run into when both animating a - drawable from a given thread as well as having updates performed - by the AWT event thread (repaints, etc.). When it is enabled, - repaint requests driven by the AWT will not result in the OpenGL - event listeners' display methods being called from the AWT - thread, unless (as with GLJPanel) this is the only mechanism by - which repaints are done. The necessity of this API may be - rethought in a future release. Defaults to false. */ - public void setNoAutoRedrawMode(boolean noAutoRedraws); - - /** Returns whether automatic redraws are disabled for this - drawable. Defaults to false. */ - public boolean getNoAutoRedrawMode(); - /** Enables or disables automatic buffer swapping for this drawable. By default this property is set to true; when true, after all GLEventListeners have been called for a display() event, the diff --git a/src/net/java/games/jogl/GLDrawableFactory.java b/src/net/java/games/jogl/GLDrawableFactory.java index 8204fde7d..c16be50ba 100644 --- a/src/net/java/games/jogl/GLDrawableFactory.java +++ b/src/net/java/games/jogl/GLDrawableFactory.java @@ -39,6 +39,7 @@ package net.java.games.jogl; +import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import net.java.games.jogl.impl.*; @@ -78,44 +79,57 @@ public class GLDrawableFactory { return factory; } - /** Creates a {@link GLCanvas} on the default graphics device with - the specified capabilities using the default capabilities - selection algorithm. */ - public GLCanvas createGLCanvas(GLCapabilities capabilities) { - return createGLCanvas(capabilities, null, null); + /** + * Selects an AWT GraphicsConfiguration on the specified + * GraphicsDevice compatible with the supplied GLCapabilities. This + * method is intended to be used by applications which do not use + * the supplied GLCanvas class but instead wrap their own Canvas + * with a GLDrawable. Some platforms (specifically X11) require the + * GraphicsConfiguration to be specified when the platform-specific + * window system object, such as a Canvas, is created. This method + * returns null on platforms on which the OpenGL pixel format + * selection process is performed later. + * + * @see java.awt.Canvas(java.awt.GraphicsConfiguration) + */ + public GraphicsConfiguration + chooseGraphicsConfiguration(GLCapabilities capabilities, + GLCapabilitiesChooser chooser, + GraphicsDevice device) { + return GLContextFactory.getFactory().chooseGraphicsConfiguration(capabilities, chooser, device); } - /** Creates a {@link GLCanvas} on the default graphics device with - the specified capabilities using the default capabilities - selection algorithm. The canvas will share textures and display - lists with the specified {@link GLDrawable}; the drawable must - either be null or have been fabricated from this factory or by - classes in this package. A null drawable indicates no - sharing. */ - public GLCanvas createGLCanvas(GLCapabilities capabilities, GLDrawable shareWith) { - return createGLCanvas(capabilities, null, shareWith); + /** + * Returns a GLDrawable that wraps a platform-specific window system + * object, such as an AWT or LCDUI Canvas. On platforms which + * support it, selects a pixel format compatible with the supplied + * GLCapabilities, or if the passed GLCapabilities object is null, + * uses a default set of capabilities. On these platforms, uses + * either the supplied GLCapabilitiesChooser object, or if the + * passed GLCapabilitiesChooser object is null, uses a + * DefaultGLCapabilitiesChooser instance. + * + * @throw IllegalArgumentException if the passed target is either + * null or its data type is not supported by this GLDrawableFactory. + * @throw GLException if any window system-specific errors caused + * the creation of the GLDrawable to fail. + */ + public GLDrawable getGLDrawable(Object target, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser) + throws IllegalArgumentException, GLException { + // FIXME + throw new GLException("Not yet implemented"); } + + //---------------------------------------------------------------------- + // Methods to create high-level objects /** Creates a {@link GLCanvas} on the default graphics device with - the specified capabilities using the supplied capabilities - selection algorithm. A null chooser is equivalent to using the - {@link DefaultGLCapabilitiesChooser}. */ - public GLCanvas createGLCanvas(GLCapabilities capabilities, GLCapabilitiesChooser chooser) { - return createGLCanvas(capabilities, chooser, null); - } - - /** Creates a {@link GLCanvas} on the default graphics device with - the specified capabilities using the supplied capabilities - selection algorithm. A null chooser is equivalent to using the - {@link DefaultGLCapabilitiesChooser}. The canvas will share - textures and display lists with the specified {@link - GLDrawable}; the drawable must either be null or have been - fabricated from this factory or by classes in this package. A - null drawable indicates no sharing. */ - public GLCanvas createGLCanvas(GLCapabilities capabilities, - GLCapabilitiesChooser chooser, - GLDrawable shareWith) { - return createGLCanvas(capabilities, chooser, shareWith, null); + the specified capabilities using the default capabilities + selection algorithm. */ + public GLCanvas createGLCanvas(GLCapabilities capabilities) { + return createGLCanvas(capabilities, null, null, null); } /** Creates a {@link GLCanvas} on the specified graphics device with @@ -147,11 +161,10 @@ public class GLDrawableFactory { // least in the Sun AWT implementation) that this will result in // equivalent behavior to calling the no-arg super() constructor // for Canvas. - return new GLCanvas(GLContextFactory.getFactory(). - chooseGraphicsConfiguration(capabilities, chooser, device), - capabilities, + return new GLCanvas(capabilities, chooser, - shareWith); + shareWith, + device); } /** Creates a {@link GLJPanel} with the specified capabilities using @@ -192,4 +205,27 @@ public class GLDrawableFactory { } return new GLJPanel(capabilities, chooser, shareWith); } + + /** + * Returns true if it is possible to create a GLPbuffer with the + * given capabilites and dimensions. + */ + public boolean canCreateGLPbuffer(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { + // FIXME + throw new GLException("Not yet implemented"); + } + + + /** + * Creates a GLPbuffer with the given capabilites and dimensions. + */ + public GLPbuffer createGLPbuffer(GLCapabilities capabilities, + int initialWidth, + int initialHeight, + GLContext shareWith) { + // FIXME + throw new GLException("Not yet implemented"); + } } diff --git a/src/net/java/games/jogl/GLEventListener.java b/src/net/java/games/jogl/GLEventListener.java index 0f345e6c7..a680716a0 100644 --- a/src/net/java/games/jogl/GLEventListener.java +++ b/src/net/java/games/jogl/GLEventListener.java @@ -51,17 +51,17 @@ public interface GLEventListener extends EventListener { initialized. Can be used to perform one-time OpenGL initialization such as setup of lights and display lists. Note that this method may be called more than once if the underlying - OpenGL context for the GLDrawable is destroyed and recreated, + OpenGL context for the GLAutoDrawable is destroyed and recreated, for example if a GLCanvas is removed from the widget hierarchy and later added again. */ - public void init(GLDrawable drawable); + public void init(GLAutoDrawable drawable); /** Called by the drawable to initiate OpenGL rendering by the client. After all GLEventListeners have been notified of a display event, the drawable will swap its buffers if necessary. */ - public void display(GLDrawable drawable); + public void display(GLAutoDrawable drawable); /** Called by the drawable during the first repaint after the component has been resized. The client can update the viewport @@ -71,20 +71,20 @@ public interface GLEventListener extends EventListener { y, width, height)</code> when this method is called, so the client may not have to do anything in this method. */ - public void reshape(GLDrawable drawable, int x, int y, int width, int height); + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height); /** Called by the drawable when the display mode or the display device - associated with the GLDrawable has changed. The two boolean parameters + associated with the GLAutoDrawable has changed. The two boolean parameters indicate the types of change(s) that have occurred. (<b> !!! CURRENTLY UNIMPLEMENTED !!! </b>) <P> An example of a display <i>mode</i> change is when the bit depth changes (e.g., - from 32-bit to 16-bit color) on monitor upon which the GLDrawable is + from 32-bit to 16-bit color) on monitor upon which the GLAutoDrawable is currently being displayed. <p> An example of a display <i>device</i> change is when the user drags the - window containing the GLDrawable from one monitor to another in a + window containing the GLAutoDrawable from one monitor to another in a multiple-monitor setup. <p> The reason that this function handles both types of changes (instead of @@ -94,5 +94,5 @@ public interface GLEventListener extends EventListener { adjustments to compensate for a device change if it knows that the mode on the new device is identical the previous mode. */ - public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged); + public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged); } diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java index 87c9ee9b3..163330766 100644 --- a/src/net/java/games/jogl/GLJPanel.java +++ b/src/net/java/games/jogl/GLJPanel.java @@ -77,7 +77,7 @@ import net.java.games.jogl.impl.*; methods as side-effect-free as possible. */ -public final class GLJPanel extends JPanel implements GLDrawable { +public final class GLJPanel extends JPanel implements GLAutoDrawable { protected static final boolean DEBUG = Debug.debug("GLJPanel"); private GLDrawableHelper drawableHelper = new GLDrawableHelper(); @@ -114,7 +114,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { private Frame toplevel; // Implementation using software rendering - private GLContext offscreenContext; + private GLContextImpl offscreenContext; // For saving/restoring of OpenGL state during ReadPixels private int[] swapbytes = new int[1]; @@ -184,7 +184,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { pbuffer.display(); } } else { - offscreenContext.invokeGL(displayAction, false, initAction); + drawableHelper.invokeGL(offscreenContext, displayAction, false, initAction); } } @@ -239,6 +239,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { Runnable r = new Runnable() { public void run() { GLContext context = null; + GLDrawableHelper helper = drawableHelper; readBackWidthInPixels = 0; readBackHeightInPixels = 0; @@ -269,6 +270,11 @@ public final class GLJPanel extends JPanel implements GLDrawable { } GLPbufferImpl pbufferImpl = (GLPbufferImpl) pbuffer; context = pbufferImpl.getContext(); + // FIXME: hack workaround for fact that reshapes may be + // deferred; must rethink this and defer them manually + // until the next display() + helper = pbufferImpl.getDrawableHelper(); + // It looks like NVidia's drivers (at least the ones on my // notebook) are buggy and don't allow a rectangle of less than // the pbuffer's width to be read...this doesn't really matter @@ -293,8 +299,14 @@ public final class GLJPanel extends JPanel implements GLDrawable { panelWidth = fwidth; panelHeight = fheight; - context.invokeGL(new Runnable() { + if (DEBUG) { + System.err.println("Doing invokeGL of reshape action"); + } + helper.invokeGL(context, new Runnable() { public void run() { + if (DEBUG) { + System.err.println("glViewport(0, 0, " + panelWidth + ", " + panelHeight + ")"); + } getGL().glViewport(0, 0, panelWidth, panelHeight); drawableHelper.reshape(GLJPanel.this, 0, 0, panelWidth, panelHeight); } @@ -370,22 +382,6 @@ public final class GLJPanel extends JPanel implements GLDrawable { } } - public void setRenderingThread(Thread currentThreadOrNull) throws GLException { - // Not supported for GLJPanel because all repaint requests must be - // handled by the AWT thread - } - - public Thread getRenderingThread() { - return null; - } - - public void setNoAutoRedrawMode(boolean noAutoRedraws) { - } - - public boolean getNoAutoRedrawMode() { - return false; - } - public void setAutoSwapBufferMode(boolean onOrOff) { if (!hardwareAccelerationDisabled) { pbuffer.setAutoSwapBufferMode(onOrOff); @@ -406,7 +402,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { if (!hardwareAccelerationDisabled) { pbuffer.swapBuffers(); } else { - offscreenContext.invokeGL(swapBuffersAction, false, initAction); + drawableHelper.invokeGL(offscreenContext, swapBuffersAction, false, initAction); } } @@ -461,7 +457,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { // The pbuffer shares textures and display lists with the // heavyweight, so by transitivity the pbuffer will share with // it as well. - heavyweight = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), shareWith); + heavyweight = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), null, shareWith, null); firstTime = true; } if (heavyweight.canCreateOffscreenDrawable()) { @@ -500,13 +496,17 @@ public final class GLJPanel extends JPanel implements GLDrawable { } // Create an offscreen context instead - offscreenContext = GLContextFactory.getFactory().createGLContext(null, offscreenCaps, chooser, - GLContextHelper.getContext(shareWith)); + offscreenContext = (GLContextImpl) GLContextFactory.getFactory().createGLContext(null, offscreenCaps, chooser, + GLContextHelper.getContext(shareWith)); + offscreenContext.setSynchronized(true); offscreenContext.resizeOffscreenContext(panelWidth, panelHeight); updater = new Updater(); if (panelWidth > 0 && panelHeight > 0) { - offscreenContext.invokeGL(new Runnable() { + drawableHelper.invokeGL(offscreenContext, new Runnable() { public void run() { + if (DEBUG) { + System.err.println("glViewport(0, 0, " + panelWidth + ", " + panelHeight + ")"); + } getGL().glViewport(0, 0, panelWidth, panelHeight); drawableHelper.reshape(GLJPanel.this, 0, 0, panelWidth, panelHeight); } @@ -523,7 +523,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { this.g = g; } - public void init(GLDrawable drawable) { + public void init(GLAutoDrawable drawable) { if (!hardwareAccelerationDisabled) { if (DEBUG) { System.err.println("GLJPanel$Updater.init(): pbufferInitializationCompleted = true"); @@ -541,7 +541,7 @@ public final class GLJPanel extends JPanel implements GLDrawable { drawableHelper.init(GLJPanel.this); } - public void display(GLDrawable drawable) { + public void display(GLAutoDrawable drawable) { drawableHelper.display(GLJPanel.this); // Must now copy pixels from offscreen context into surface @@ -672,11 +672,11 @@ public final class GLJPanel extends JPanel implements GLDrawable { } } - public void reshape(GLDrawable drawable, int x, int y, int width, int height) { + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { // This is handled above and dispatched directly to the appropriate context } - public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { + public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { } } diff --git a/src/net/java/games/jogl/GLPbuffer.java b/src/net/java/games/jogl/GLPbuffer.java index b073388f5..4dd3c1e00 100644 --- a/src/net/java/games/jogl/GLPbuffer.java +++ b/src/net/java/games/jogl/GLPbuffer.java @@ -46,7 +46,7 @@ package net.java.games.jogl; buffers. These methods are currently highly experimental and may be removed in a future release. */ -public interface GLPbuffer extends GLDrawable { +public interface GLPbuffer extends GLAutoDrawable { /** Indicates the GL_APPLE_float_pixels extension is being used for this pbuffer. */ public static final int APPLE_FLOAT = 1; diff --git a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java index be5e26067..87f2b1819 100644 --- a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java +++ b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java @@ -54,7 +54,7 @@ import java.lang.reflect.*; public final class FunctionAvailabilityCache { private static final boolean DEBUG = Debug.debug("FunctionAvailabilityCache"); - FunctionAvailabilityCache(GLContext context) + FunctionAvailabilityCache(GLContextImpl context) { this.context = context; } @@ -243,7 +243,7 @@ public final class FunctionAvailabilityCache { private HashMap availabilityCache = new HashMap(50); private HashSet availableExtensionCache = new HashSet(50); - private GLContext context; + private GLContextImpl context; /** * A class for storing and comparing revision version numbers. diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java deleted file mode 100644 index 41fa98c4b..000000000 --- a/src/net/java/games/jogl/impl/GLContext.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * 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 - * MICROSYSTEMS, 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.awt.Component; -import net.java.games.jogl.*; -import net.java.games.gluegen.runtime.*; - -public abstract class GLContext { - protected static final boolean DEBUG = Debug.debug("GLContext"); - protected static final boolean VERBOSE = Debug.verbose(); - protected static final boolean NO_FREE = Debug.isPropertyDefined("jogl.GLContext.nofree"); - - static { - NativeLibLoader.load(); - } - - protected Component component; - - // Indicates whether the component (if an onscreen context) has been - // realized. Plausibly, before the component is realized the JAWT - // should return an error or NULL object from some of its - // operations; this appears to be the case on Win32 but is not true - // at least with Sun's current X11 implementation (1.4.x), which - // crashes with no other error reported if the DrawingSurfaceInfo is - // fetched from a locked DrawingSurface during the validation as a - // result of calling show() on the main thread. To work around this - // we prevent any JAWT or OpenGL operations from being done until - // addNotify() is called on the component. - protected boolean realized; - - protected GLCapabilities capabilities; - protected GLCapabilitiesChooser chooser; - protected GL gl; - protected static final GLUProcAddressTable gluProcAddressTable = new GLUProcAddressTable(); - protected static boolean haveResetGLUProcAddressTable; - protected GLU glu = new GLUImpl(gluProcAddressTable); - protected Thread renderingThread; - protected Runnable deferredReshapeAction; - // Support for OpenGL context destruction and recreation in the face - // of the setRenderingThread optimization, which makes the context - // permanently current on the animation thread. FIXME: should make - // this more uniform and general, possibly by implementing in terms - // of Runnables; however, necessary sequence of operations in - // invokeGL makes this tricky. - protected boolean deferredDestroy; - protected boolean deferredSetRealized; - - // 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 - // GLDrawable, the expectation is that the Animator will be started - // shortly and that the user doesn't want rendering to occur from - // the AWT thread. However, there is a small window between when the - // Animator is created and attached to the GLDrawable and when it's - // started (and sets the rendering thread) when repaint events can - // be issued by the AWT thread if the component is realized. To work - // around this problem, we currently specify in the Animator's API - // that between the time it's created and started no redraws will - // occur. - protected volatile boolean willSetRenderingThread; - - // Flag for disabling all repaint and resize processing on the AWT - // thread to avoid application-level deadlocks; only really used for - // GLCanvas - protected boolean noAutoRedraw; - - // Flag for enabling / disabling automatic swapping of the front and - // back buffers - protected boolean autoSwapBuffers = true; - - // Offscreen context handling. Offscreen contexts should handle - // these resize requests in makeCurrent and clear the - // pendingOffscreenResize flag. - protected boolean pendingOffscreenResize; - protected int pendingOffscreenWidth; - protected int pendingOffscreenHeight; - - // 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(); - } - }; - // This thread-local variable helps implement setRenderingThread()'s - // optimized context handling. When the bottommost invokeGL() on the - // execution stack finishes for the rendering thread for that - // context, we pop the context off the context stack but do not free - // it, instead storing it in this thread-local variable. This gives - // us enough information to recover the context stack state in - // subsequent invokeGL() calls. - protected static final ThreadLocal perThreadSavedCurrentContext = new ThreadLocal() { - protected synchronized Object initialValue() { - return new GLContextInitActionPair(null, null); - } - }; - - public GLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, - GLContext shareWith) { - this.component = component; - this.capabilities = (GLCapabilities) capabilities.clone(); - this.chooser = chooser; - setGL(createGL()); - functionAvailability = new FunctionAvailabilityCache(this); - if (shareWith != null) { - GLContextShareSet.registerSharing(this, shareWith); - } - } - - /** Runs the given runnable with this OpenGL context valid. */ - public synchronized void invokeGL(Runnable runnable, boolean isReshape, Runnable initAction) throws GLException { - // 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 - if (!isRealized() || - willSetRenderingThread || - (renderingThread != null && - renderingThread != currentThread)) { - // Support for removeNotify()/addNotify() when the - // setRenderingThread optimization is in effect and before the - // animation thread gets a chance to handle either request - if (!isRealized() && deferredSetRealized) { - setRealized(); - deferredSetRealized = false; - } else { - if (isReshape) { - deferredReshapeAction = runnable; - } - return; - } - } - - if (isReshape && noAutoRedraw && !SingleThreadedWorkaround.doWorkaround()) { - // Don't process reshape requests on the AWT thread - deferredReshapeAction = runnable; - return; - } - - if (deferredDestroy) { - deferredDestroy = false; - if (renderingThread != null) { - // Need to disable the setRenderingThread optimization to free - // up the context - setRenderingThread(null, initAction); - } - destroy(); - return; - } - - // The goal of this code is to optimize OpenGL context handling as - // much as possible. In particular: - // - // - setRenderingThread() works by making the "bottommost" OpenGL - // context current once and not freeing it until the rendering - // thread has been unset. Note that subsequent pushes of other - // contexts will still necessarily cause them to be made current - // and freed. - // - // - If the same context is pushed on the per-thread context stack - // more than once back-to-back, the subsequent pushes will not - // actually cause a makeCurrent/free to occur. - // - // Complexities occur because setRenderingThread() can be called - // at any time. Currently we implement the rendering thread - // optimization by popping it off the OpenGL context stack and - // storing it in a thread-local variable. - - GLContextStack ctxStack = getPerThreadContextStack(); - GLContext savedPerThreadContext = getPerThreadSavedCurrentContext(); - Runnable savedPerThreadInitAction = getPerThreadSavedInitAction(); - setPerThreadSavedCurrentContext(null, null); - if (ctxStack.size() == 0 && - savedPerThreadContext != null) { - // The setRenderingThread optimization moved the current context - // into thread-local storage. Put it back on the context stack, - // because we might need to free it later. - ctxStack.push(savedPerThreadContext, savedPerThreadInitAction); - } - - GLContext curContext = ctxStack.peekContext(); - Runnable curInitAction = ctxStack.peekInitAction(); - boolean mustDoMakeCurrent = true; - - if (curContext == this) { - mustDoMakeCurrent = false; - } - - if (mustDoMakeCurrent) { - if (curContext != null) { - if (DEBUG && VERBOSE) { - System.err.println(getThreadName() + ": 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. - // We'll defer any actions until invokeGL() is called again at a time - // when the component has been visualized. - if (isReshape) { - deferredReshapeAction = runnable; - } - - // Clean up after ourselves on the way out. - // NOTE that this is an abbreviated version of the code below - // and should probably be refactored/cleaned up -- this bug - // fix was done without a lot of intense thought about the - // situation - if (curContext != null) { - curContext.makeCurrent(curInitAction); - } - return; - } - if (DEBUG && VERBOSE) { - System.err.println(getThreadName() + ": 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); - } - - RuntimeException userException = null; - GLException internalException = null; - - try { - if (deferredReshapeAction != null) { - deferredReshapeAction.run(); - deferredReshapeAction = null; - } - runnable.run(); - if (autoSwapBuffers && !isReshape) { - swapBuffers(); - } - } catch (RuntimeException e) { - userException = e; - throw(userException); - } finally { - if (userException != null) { - // Disallow setRenderingThread if display action is throwing exceptions - renderingThread = null; - } - - boolean mustSkipFreeForRenderingThread = false; - if (currentThread == renderingThread && curContext == null) { - mustSkipFreeForRenderingThread = true; - setPerThreadSavedCurrentContext(this, initAction); - } - - // Always pop myself off the per-thread context stack - ctxStack.pop(); - - // Free the context unless the setRenderingThread optimization - // kicks in. - if (mustDoMakeCurrent && !mustSkipFreeForRenderingThread) { - if (DEBUG && VERBOSE) { - System.err.println(getThreadName() + ": Freeing context " + this); - } - - try { - free(); - } catch (GLException e) { - internalException = e; - } - - if (curContext != null) { - if (DEBUG && VERBOSE) { - System.err.println(getThreadName() + ": Making context " + curContext + " current again"); - } - try { - curContext.makeCurrent(curInitAction); - } catch (GLException e) { - internalException = e; - } - } - } - - // Check to see whether we pushed any remaining entry on the - // per-thread context stack. If so, put it back in thread-local - // storage unless the rendering thread optimization was recently - // disabled. - if (savedPerThreadContext != null) { - assert(savedPerThreadContext == curContext); - ctxStack.pop(); - if (savedPerThreadContext.getRenderingThread() == null) { - try { - savedPerThreadContext.free(); - } catch (GLException e) { - internalException = e; - } - } else { - setPerThreadSavedCurrentContext(savedPerThreadContext, savedPerThreadInitAction); - } - } - - // Make sure the end user's exception shows up in any stack - // traces; the rethrow of the userException above should take - // precedence if the internalException will otherwise squelch it - if (internalException != null) { - if (userException != null && - internalException.getCause() == null) { - internalException.initCause(userException); - throw(internalException); - } else if (userException == null) { - throw(internalException); - } - } - } - } - - public GL getGL() { - return gl; - } - - public void setGL(GL gl) { - this.gl = gl; - // Also reset the GL object for the pure-Java GLU implementation - ((GLUImpl) glu).setGL(gl); - } - - public GLU getGLU() { - return glu; - } - - public void setGLU(GLU glu) { - this.glu = glu; - } - - /** Gives a hint to the context that setRenderingThread will be - called in the near future; causes redraws to be halted. This is - a workaround for bugs in NVidia's drivers and is used only by - the Animator class. */ - public synchronized void willSetRenderingThread() { - this.willSetRenderingThread = true; - } - - public synchronized void setRenderingThread(Thread currentThreadOrNull, Runnable initAction) { - if (SingleThreadedWorkaround.doWorkaround()) { - willSetRenderingThread = false; - return; - } - - Thread currentThread = Thread.currentThread(); - if (currentThreadOrNull != null && currentThreadOrNull != currentThread) { - throw new GLException("Argument must be either the current thread or null"); - } - if (renderingThread != null && currentThreadOrNull != null) { - throw new GLException("Attempt to re-set or change rendering thread"); - } - 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; - 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; - perThreadRenderingContext.set(this); - } - } - - public Thread getRenderingThread() { - return renderingThread; - } - - public void setNoAutoRedrawMode(boolean noAutoRedraw) { - this.noAutoRedraw = noAutoRedraw; - } - - public boolean getNoAutoRedrawMode() { - return noAutoRedraw; - } - - public void setAutoSwapBufferMode(boolean autoSwapBuffers) { - this.autoSwapBuffers = autoSwapBuffers; - } - - public boolean getAutoSwapBufferMode() { - return autoSwapBuffers; - } - - /** Swaps the buffers of the OpenGL context if necessary. All error - conditions cause a GLException to be thrown. */ - public abstract void swapBuffers() throws GLException; - - /** Routine needed only for offscreen contexts in order to resize - the underlying bitmap. Called by GLJPanel. */ - public void resizeOffscreenContext(int newWidth, int newHeight) { - if (!isOffscreen()) { - throw new GLException("Should only call for offscreen OpenGL contexts"); - } - pendingOffscreenResize = true; - pendingOffscreenWidth = newWidth; - pendingOffscreenHeight = newHeight; - } - - /** Indicates which floating-point pbuffer implementation is in - use. Returns one of GLPbuffer.APPLE_FLOAT, GLPbuffer.ATI_FLOAT, - or GLPbuffer.NV_FLOAT. */ - public int getFloatingPointMode() throws GLException { - throw new GLException("Not supported on non-pbuffer contexts"); - } - - /** Returns a non-null (but possibly empty) string containing the - space-separated list of available platform-dependent (e.g., WGL, - GLX) extensions. Can only be called while this context is - current. */ - public abstract String getPlatformExtensionsString(); - - /** - * Resets the cache of which GL functions are available for calling through this - * context. See {@link #isFunctionAvailable(String)} for more information on - * the definition of "available". - */ - protected void resetGLFunctionAvailability() { - // In order to be able to allow the user to uniformly install the - // debug and trace pipelines in their GLEventListener.init() - // method (for both GLCanvas and GLJPanel), we need to reset the - // actual GL object in the GLDrawable as well - setGL(createGL()); - - functionAvailability.flush(); - if (!haveResetGLUProcAddressTable) { - if (DEBUG) { - System.err.println(getThreadName() + ": !!! Initializing GLU extension address table"); - } - resetProcAddressTable(gluProcAddressTable); - haveResetGLUProcAddressTable = true; // Only need to do this once globally - } - recomputeSingleThreadedWorkaround(); - } - - /** - * Returns true if the specified OpenGL core- or extension-function can be - * successfully called using this GL context given the current host (OpenGL - * <i>client</i>) and display (OpenGL <i>server</i>) configuration. - * - * See {@link GL#isFunctionAvailable(String)} for more details. - * - * @param glFunctionName the name of the OpenGL function (e.g., use - * "glPolygonOffsetEXT" to check if the {@link - * net.java.games.jogl.GL#glPolygonOffsetEXT(float,float)} is available). - */ - protected boolean isFunctionAvailable(String glFunctionName) { - return functionAvailability.isFunctionAvailable(mapToRealGLFunctionName(glFunctionName)); - } - - /** - * Returns true if the specified OpenGL extension can be - * successfully called using this GL context given the current host (OpenGL - * <i>client</i>) and display (OpenGL <i>server</i>) configuration. - * - * See {@link GL#isExtensionAvailable(String)} for more details. - * - * @param glExtensionName the name of the OpenGL extension (e.g., - * "GL_VERTEX_PROGRAM_ARB"). - */ - public boolean isExtensionAvailable(String glExtensionName) { - return functionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); - } - - /** - * Pbuffer support; indicates whether this context is capable of - * creating a subordinate pbuffer context (distinct from an - * "offscreen context", which is typically software-rendered on all - * platforms). - */ - public abstract boolean canCreatePbufferContext(); - - /** - * Pbuffer support; creates a subordinate GLContext for a pbuffer - * associated with this context. - */ - public abstract GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight); - - /** - * Pbuffer support; given that this is a GLContext associated with a - * pbuffer, binds this pbuffer to its texture target. - */ - public abstract void bindPbufferToTexture(); - - /** - * Pbuffer support; given that this is a GLContext associated with a - * pbuffer, releases this pbuffer from its texture target. - */ - public abstract void releasePbufferFromTexture(); - - /* - * Sets the swap interval for onscreen OpenGL contexts. Has no - * effect for offscreen contexts. - */ - public void setSwapInterval(final int interval) { - } - - /** Maps the given "platform-independent" function name to a real function - name. Currently this is only used to map "glAllocateMemoryNV" and - associated routines to wglAllocateMemoryNV / glXAllocateMemoryNV. */ - protected abstract String mapToRealGLFunctionName(String glFunctionName); - - /** Maps the given "platform-independent" extension name to a real - function name. Currently this is only used to map - "GL_ARB_pbuffer" and "GL_ARB_pixel_format" to "WGL_ARB_pbuffer" - and "WGL_ARB_pixel_format" (not yet mapped to X11). */ - protected abstract String mapToRealGLExtensionName(String glExtensionName); - - /** Create the GL for this context. */ - protected abstract GL createGL(); - - /** Hook indicating whether the concrete GLContext implementation is - offscreen and therefore whether we need to process resize - requests. */ - protected abstract boolean isOffscreen(); - - /** Only called for offscreen contexts; returns the buffer from - which to read pixels (GL.GL_FRONT or GL.GL_BACK). */ - public abstract int getOffscreenContextReadBuffer(); - - /** Only called for offscreen contexts; needed by glReadPixels */ - public abstract int getOffscreenContextWidth(); - - /** Only called for offscreen contexts; needed by glReadPixels */ - public abstract int getOffscreenContextHeight(); - - /** Only called for offscreen contexts; needed by glReadPixels */ - public abstract int getOffscreenContextPixelDataType(); - - /** On some platforms the mismatch between OpenGL's coordinate - system (origin at bottom left) and the window system's - coordinate system (origin at top left) necessitates a vertical - flip of pixels read from offscreen contexts. */ - public abstract boolean offscreenImageNeedsVerticalFlip(); - - /** Attempts to make the GL context current. If necessary, creates a - context and calls the initAction once the context is current. - Most error conditions cause an exception to be thrown, except - for the case where the context can not be created because the - component has not yet been visualized. In this case makeCurrent - returns false and the caller should abort any OpenGL event - processing and instead return immediately. */ - protected abstract boolean makeCurrent(Runnable initAction) throws GLException; - - /** Frees the OpenGL context. All error conditions cause a - GLException to be thrown. */ - protected abstract void free() throws GLException; - - /** Inform the system that the associated heavyweight widget has - been realized and that it is safe to create an associated OpenGL - context. If the widget is later destroyed then destroy() should - be called, which will cause the underlying OpenGL context to be - destroyed as well as the realized bit to be set to false. */ - public void setRealized() { - if (getRenderingThread() != null && - Thread.currentThread() != getRenderingThread()) { - deferredSetRealized = true; - return; - } - setRealized(true); - } - - /** Sets only the "realized" bit. Should be called by subclasses - from within the destroy() implementation. */ - protected synchronized void setRealized(boolean realized) { - this.realized = realized; - if (DEBUG) { - System.err.println(getThreadName() + ": GLContext.setRealized(" + realized + ") for context " + this); - } - } - - /** Indicates whether the component associated with this context has - been realized. */ - public synchronized boolean getRealized() { - return realized; - } - - /** Destroys the underlying OpenGL context and changes the realized - state to false. This should be called when the widget is being - destroyed. */ - public synchronized void destroy() throws GLException { - if (getRenderingThread() != null && - Thread.currentThread() != getRenderingThread()) { - if (DEBUG) { - System.err.println(getThreadName() + ": Deferred destroy for context " + this); - } - deferredDestroy = true; - return; - } - setRealized(false); - GLContextShareSet.contextDestroyed(this); - destroyImpl(); - } - - /** Destroys the underlying OpenGL context. */ - protected abstract void destroyImpl() throws GLException; - - public synchronized boolean isRealized() { - return (component == null || getRealized()); - } - - /** Helper routine which resets a ProcAddressTable generated by the - GLEmitter by looking up anew all of its function pointers. */ - protected void resetProcAddressTable(Object table) { - Class tableClass = table.getClass(); - java.lang.reflect.Field[] fields = tableClass.getDeclaredFields(); - - for (int i = 0; i < fields.length; ++i) { - String addressFieldName = fields[i].getName(); - if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) { - // not a proc address variable - continue; - } - int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length(); - String glFuncName = addressFieldName.substring(startOfMethodName); - try { - java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); - assert(addressField.getType() == Long.TYPE); - long newProcAddress = dynamicLookupFunction(glFuncName); - // 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)); - } - } catch (Exception e) { - throw new GLException("Cannot get GL proc address for method \"" + - glFuncName + "\": Couldn't set value of field \"" + addressFieldName + - "\" in class " + tableClass.getName(), e); - } - } - } - - /** Dynamically looks up the given function. */ - protected abstract long dynamicLookupFunction(String glFuncName); - - /** Indicates whether the underlying OpenGL context has been - created. This is used to manage sharing of display lists and - 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(); - } - - /** Support for setRenderingThread()'s optimized context handling */ - protected static GLContext getPerThreadSavedCurrentContext() { - return ((GLContextInitActionPair) perThreadSavedCurrentContext.get()).getContext(); - } - - /** Support for setRenderingThread()'s optimized context handling */ - protected static Runnable getPerThreadSavedInitAction() { - return ((GLContextInitActionPair) perThreadSavedCurrentContext.get()).getInitAction(); - } - - /** Support for setRenderingThread()'s optimized context handling */ - protected static void setPerThreadSavedCurrentContext(GLContext context, Runnable initAction) { - perThreadSavedCurrentContext.set(new GLContextInitActionPair(context, initAction)); - } - - /** Support for automatic detection of whether we need to enable the - single-threaded workaround for ATI and other vendors' cards. - Should be called by subclasses for onscreen rendering inside - their makeCurrent() implementation once the context is - current. */ - private void recomputeSingleThreadedWorkaround() { - GL gl = getGL(); - String str = gl.glGetString(GL.GL_VENDOR); - if (str != null && str.indexOf("ATI") >= 0) { - // Doing this instead of calling setRenderingThread(null) should - // be OK since we are doing this very early in the maintenance - // of the per-thread context stack, before we are actually - // pushing any GLContext objects on it - SingleThreadedWorkaround.shouldDoWorkaround(); - if( SingleThreadedWorkaround.doWorkaround() ) { - renderingThread = null; - } - } - } - - protected static String getThreadName() { - return Thread.currentThread().getName(); - } -} diff --git a/src/net/java/games/jogl/impl/GLContextImpl.java b/src/net/java/games/jogl/impl/GLContextImpl.java new file mode 100755 index 000000000..26547c8c3 --- /dev/null +++ b/src/net/java/games/jogl/impl/GLContextImpl.java @@ -0,0 +1,364 @@ +/* + * 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.awt.Component; + +import net.java.games.jogl.*; +import net.java.games.gluegen.runtime.*; + +public abstract class GLContextImpl extends GLContext { + protected GLContextLock lock = new GLContextLock(); + protected static final boolean DEBUG = Debug.debug("GLContextImpl"); + protected static final boolean VERBOSE = Debug.verbose(); + protected static final boolean NO_FREE = Debug.isPropertyDefined("jogl.GLContext.nofree"); + + static { + NativeLibLoader.load(); + } + + protected GLCapabilities capabilities; + protected GLCapabilitiesChooser chooser; + protected Component component; + + // Cache of the functions that are available to be called at the current + // moment in time + protected FunctionAvailabilityCache functionAvailability; + + protected GL gl; + protected GLU glu = new GLUImpl(gluProcAddressTable); + protected static final GLUProcAddressTable gluProcAddressTable = new GLUProcAddressTable(); + protected static boolean haveResetGLUProcAddressTable; + + public GLContextImpl(Component component, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser, + GLContext shareWith) { + this.component = component; + this.capabilities = (GLCapabilities) capabilities.clone(); + this.chooser = chooser; + setGL(createGL()); + functionAvailability = new FunctionAvailabilityCache(this); + if (shareWith != null) { + GLContextShareSet.registerSharing(this, shareWith); + } + } + + public int makeCurrent() throws GLException { + lock.lock(); + int res = 0; + try { + res = makeCurrentImpl(); + } catch (GLException e) { + lock.unlock(); + throw(e); + } + if (res == CONTEXT_NOT_CURRENT) { + lock.unlock(); + } else { + setCurrent(this); + } + return res; + } + + protected abstract int makeCurrentImpl() throws GLException; + + public void release() throws GLException { + if (!lock.isHeld()) { + throw new GLException("Context not current on current thread"); + } + setCurrent(null); + try { + releaseImpl(); + } finally { + lock.unlock(); + } + } + + protected abstract void releaseImpl() throws GLException; + + public void destroy() { + // Should we check the lock state? It should not be current on any + // thread. + destroyImpl(); + } + + protected abstract void destroyImpl() throws GLException; + + public boolean isSynchronized() { + return !lock.getFailFastMode(); + } + + public void setSynchronized(boolean isSynchronized) { + lock.setFailFastMode(!isSynchronized); + } + + public GL getGL() { + return gl; + } + + public void setGL(GL gl) { + this.gl = gl; + // Also reset the GL object for the pure-Java GLU implementation + ((GLUImpl) glu).setGL(gl); + } + + public GLU getGLU() { + return glu; + } + + public void setGLU(GLU glu) { + this.glu = glu; + } + + // Subclasses for onscreen GLContexts should override this to + // receive a notification from the GLCanvas or other implementation + // upon addNotify + public void setRealized() { + } + + //---------------------------------------------------------------------- + // Helpers for various context implementations + // + + // Flag for enabling / disabling automatic swapping of the front and + // back buffers + protected boolean autoSwapBuffers = true; + + // Offscreen context handling. Offscreen contexts should handle + // these resize requests in makeCurrent and clear the + // pendingOffscreenResize flag. + protected boolean pendingOffscreenResize; + protected int pendingOffscreenWidth; + protected int pendingOffscreenHeight; + + /** Create the GL for this context. */ + protected abstract GL createGL(); + + /** + * Pbuffer support; indicates whether this context is capable of + * creating a subordinate pbuffer context (distinct from an + * "offscreen context", which is typically software-rendered on all + * platforms). + */ + public abstract boolean canCreatePbufferContext(); + + /** + * Pbuffer support; creates a subordinate GLContext for a pbuffer + * associated with this context. + */ + public abstract GLContext createPbufferContext(GLCapabilities capabilities, + int initialWidth, + int initialHeight); + + /** + * Pbuffer support; given that this is a GLContext associated with a + * pbuffer, binds this pbuffer to its texture target. + */ + public abstract void bindPbufferToTexture(); + + /** + * Pbuffer support; given that this is a GLContext associated with a + * pbuffer, releases this pbuffer from its texture target. + */ + public abstract void releasePbufferFromTexture(); + + /* + * Sets the swap interval for onscreen OpenGL contexts. Has no + * effect for offscreen contexts. + */ + public void setSwapInterval(final int interval) { + } + + /** Maps the given "platform-independent" function name to a real function + name. Currently this is only used to map "glAllocateMemoryNV" and + associated routines to wglAllocateMemoryNV / glXAllocateMemoryNV. */ + protected abstract String mapToRealGLFunctionName(String glFunctionName); + + /** Maps the given "platform-independent" extension name to a real + function name. Currently this is only used to map + "GL_ARB_pbuffer" and "GL_ARB_pixel_format" to "WGL_ARB_pbuffer" + and "WGL_ARB_pixel_format" (not yet mapped to X11). */ + protected abstract String mapToRealGLExtensionName(String glExtensionName); + + public void setAutoSwapBufferMode(boolean autoSwapBuffers) { + this.autoSwapBuffers = autoSwapBuffers; + } + + public boolean getAutoSwapBufferMode() { + return autoSwapBuffers; + } + + /** Swaps the buffers of the OpenGL context if necessary. All error + conditions cause a GLException to be thrown. */ + public abstract void swapBuffers() throws GLException; + + /** Returns a non-null (but possibly empty) string containing the + space-separated list of available platform-dependent (e.g., WGL, + GLX) extensions. Can only be called while this context is + current. */ + public abstract String getPlatformExtensionsString(); + + /** Helper routine which resets a ProcAddressTable generated by the + GLEmitter by looking up anew all of its function pointers. */ + protected void resetProcAddressTable(Object table) { + Class tableClass = table.getClass(); + java.lang.reflect.Field[] fields = tableClass.getDeclaredFields(); + + for (int i = 0; i < fields.length; ++i) { + String addressFieldName = fields[i].getName(); + if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) { + // not a proc address variable + continue; + } + int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length(); + String glFuncName = addressFieldName.substring(startOfMethodName); + try { + java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); + assert(addressField.getType() == Long.TYPE); + long newProcAddress = dynamicLookupFunction(glFuncName); + // 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)); + } + } catch (Exception e) { + throw new GLException("Cannot get GL proc address for method \"" + + glFuncName + "\": Couldn't set value of field \"" + addressFieldName + + "\" in class " + tableClass.getName(), e); + } + } + } + + /** Dynamically looks up the given function. */ + protected abstract long dynamicLookupFunction(String glFuncName); + + /** Indicates whether the underlying OpenGL context has been + created. This is used to manage sharing of display lists and + textures between contexts. */ + public abstract boolean isCreated(); + + /** + * Resets the cache of which GL functions are available for calling through this + * context. See {@link #isFunctionAvailable(String)} for more information on + * the definition of "available". + */ + protected void resetGLFunctionAvailability() { + // In order to be able to allow the user to uniformly install the + // debug and trace pipelines in their GLEventListener.init() + // method (for both GLCanvas and GLJPanel), we need to reset the + // actual GL object in the GLDrawable as well + setGL(createGL()); + + functionAvailability.flush(); + if (!haveResetGLUProcAddressTable) { + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Initializing GLU extension address table"); + } + resetProcAddressTable(gluProcAddressTable); + haveResetGLUProcAddressTable = true; // Only need to do this once globally + } + } + + /** + * Returns true if the specified OpenGL core- or extension-function can be + * successfully called using this GL context given the current host (OpenGL + * <i>client</i>) and display (OpenGL <i>server</i>) configuration. + * + * See {@link GL#isFunctionAvailable(String)} for more details. + * + * @param glFunctionName the name of the OpenGL function (e.g., use + * "glPolygonOffsetEXT" to check if the {@link + * net.java.games.jogl.GL#glPolygonOffsetEXT(float,float)} is available). + */ + protected boolean isFunctionAvailable(String glFunctionName) { + return functionAvailability.isFunctionAvailable(mapToRealGLFunctionName(glFunctionName)); + } + + /** + * Returns true if the specified OpenGL extension can be + * successfully called using this GL context given the current host (OpenGL + * <i>client</i>) and display (OpenGL <i>server</i>) configuration. + * + * See {@link GL#isExtensionAvailable(String)} for more details. + * + * @param glExtensionName the name of the OpenGL extension (e.g., + * "GL_VERTEX_PROGRAM_ARB"). + */ + public boolean isExtensionAvailable(String glExtensionName) { + return functionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); + } + + /** Indicates which floating-point pbuffer implementation is in + use. Returns one of GLPbuffer.APPLE_FLOAT, GLPbuffer.ATI_FLOAT, + or GLPbuffer.NV_FLOAT. */ + public int getFloatingPointMode() throws GLException { + throw new GLException("Not supported on non-pbuffer contexts"); + } + + /** Hook indicating whether the concrete GLContext implementation is + offscreen and therefore whether we need to process resize + requests. */ + protected abstract boolean isOffscreen(); + + /** On some platforms the mismatch between OpenGL's coordinate + system (origin at bottom left) and the window system's + coordinate system (origin at top left) necessitates a vertical + flip of pixels read from offscreen contexts. */ + public abstract boolean offscreenImageNeedsVerticalFlip(); + + /** Only called for offscreen contexts; needed by glReadPixels */ + public abstract int getOffscreenContextPixelDataType(); + + /** Routine needed only for offscreen contexts in order to resize + the underlying bitmap. Called by GLJPanel. */ + public void resizeOffscreenContext(int newWidth, int newHeight) { + if (!isOffscreen()) { + throw new GLException("Should only call for offscreen OpenGL contexts"); + } + pendingOffscreenResize = true; + pendingOffscreenWidth = newWidth; + pendingOffscreenHeight = newHeight; + } + + protected static String getThreadName() { + return Thread.currentThread().getName(); + } +} diff --git a/src/net/java/games/jogl/impl/GLContextLock.java b/src/net/java/games/jogl/impl/GLContextLock.java new file mode 100755 index 000000000..7e40cbe46 --- /dev/null +++ b/src/net/java/games/jogl/impl/GLContextLock.java @@ -0,0 +1,118 @@ +/* + * 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 net.java.games.jogl.*; + +/** Implements the makeCurrent / release locking behavior of the + GLContext class. When "fail fast mode" is enabled, attempts to + lock the same GLContextLock on more than one thread cause + GLException to be raised. This lock is not recursive. Attempts to + lock it more than once on a given thread will cause GLException to + be raised. */ + +public class GLContextLock { + private Object lock = new Object(); + private Thread owner; + private boolean failFastMode = true; + + /** Locks this GLContextLock on the current thread. If fail fast + mode is enabled and the GLContextLock is already owned by + another thread, throws GLException. */ + public void lock() throws GLException { + synchronized(lock) { + Thread current = Thread.currentThread(); + if (owner == null) { + owner = current; + } else if (owner != current) { + while (owner != null) { + if (failFastMode) { + throw new GLException("Attempt to make context current on thread " + current + + " which is already current on thread " + owner); + } else { + try { + lock.wait(); + } catch (InterruptedException e) { + throw new GLException(e); + } + } + } + owner = current; + } else { + throw new GLException("Attempt to make the same context current twice on thread " + current); + } + } + } + + /** Unlocks this GLContextLock. */ + public void unlock() throws GLException { + synchronized (lock) { + Thread current = Thread.currentThread(); + if (owner == current) { + owner = null; + lock.notifyAll(); + } else { + if (owner != null) { + throw new GLException("Attempt by thread " + current + + " to release context owned by thread " + owner); + } else { + throw new GLException("Attempt by thread " + current + + " to release unowned context"); + } + } + } + } + + /** Indicates whether this lock is held by the current thread. */ + public boolean isHeld() { + synchronized(lock) { + Thread current = Thread.currentThread(); + return (owner == current); + } + } + + public void setFailFastMode(boolean onOrOff) { + failFastMode = onOrOff; + } + + public boolean getFailFastMode() { + return failFastMode; + } +} diff --git a/src/net/java/games/jogl/impl/GLContextShareSet.java b/src/net/java/games/jogl/impl/GLContextShareSet.java index 60c6b7d59..f2e1c595a 100644 --- a/src/net/java/games/jogl/impl/GLContextShareSet.java +++ b/src/net/java/games/jogl/impl/GLContextShareSet.java @@ -41,6 +41,7 @@ package net.java.games.jogl.impl; import java.lang.ref.*; import java.util.*; +import net.java.games.jogl.*; /** Provides a mechanism by which OpenGL contexts can share textures and display lists in the face of multithreading and asynchronous @@ -61,7 +62,8 @@ public class GLContextShareSet { public void add(GLContext ctx) { if (allShares.put(ctx, dummyValue) == null) { - if (ctx.isCreated()) { + // FIXME: downcast to GLContextImpl undesirable + if (((GLContextImpl) ctx).isCreated()) { createdShares.put(ctx, dummyValue); } else { destroyedShares.put(ctx, dummyValue); diff --git a/src/net/java/games/jogl/impl/GLContextStack.java b/src/net/java/games/jogl/impl/GLContextStack.java deleted file mode 100755 index 089d53525..000000000 --- a/src/net/java/games/jogl/impl/GLContextStack.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 - * MICROSYSTEMS, 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(); - } -} diff --git a/src/net/java/games/jogl/impl/GLDrawableHelper.java b/src/net/java/games/jogl/impl/GLDrawableHelper.java index dd5d7c17f..da164088f 100644 --- a/src/net/java/games/jogl/impl/GLDrawableHelper.java +++ b/src/net/java/games/jogl/impl/GLDrawableHelper.java @@ -42,11 +42,13 @@ package net.java.games.jogl.impl; import java.util.*; import net.java.games.jogl.*; -/** Encapsulates the implementation of most of the GLDrawable's +/** Encapsulates the implementation of most of the GLAutoDrawable's 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(); public GLDrawableHelper() { } @@ -63,22 +65,92 @@ public class GLDrawableHelper { listeners = newListeners; } - public void init(GLDrawable drawable) { + public void init(GLAutoDrawable drawable) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((GLEventListener) iter.next()).init(drawable); } } - public void display(GLDrawable drawable) { + public void display(GLAutoDrawable drawable) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((GLEventListener) iter.next()).display(drawable); } } - public void reshape(GLDrawable 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 static final ThreadLocal perThreadInitAction = new ThreadLocal(); + private Runnable deferredReshapeAction; + /** Principal helper method which runs a Runnable with the context + made current. This could have been made part of GLContext, but a + desired goal is to be able to implement the GLCanvas in terms of + the GLContext's public APIs, and putting it into a separate + class helps ensure that we don't inadvertently use private + methods of the GLContext or its implementing classes. */ + public void invokeGL(GLContext context, + Runnable runnable, + boolean isReshape, + Runnable initAction) { + // Support for recursive makeCurrent() calls as well as calling + // other drawables' display() methods from within another one's + GLContext lastContext = GLContext.getCurrent(); + Runnable lastInitAction = (Runnable) perThreadInitAction.get(); + if (lastContext != null) { + lastContext.release(); + } + + int res = 0; + try { + res = context.makeCurrent(); + if (res == GLContext.CONTEXT_NOT_CURRENT) { + if (isReshape) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Deferring reshape action"); + } + deferredReshapeAction = runnable; + } + } else { + if (res == GLContext.CONTEXT_CURRENT_NEW) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); + } + initAction.run(); + } + if (deferredReshapeAction != null) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running deferred reshape action"); + } + Runnable act = deferredReshapeAction; + deferredReshapeAction = null; + act.run(); + } + if (DEBUG && VERBOSE) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running runnable"); + } + runnable.run(); + // FIXME: must phrase this in terms of new GLDrawable swap buffer functionality + if (((GLContextImpl) context).getAutoSwapBufferMode()) { + ((GLContextImpl) context).swapBuffers(); + } + } + } finally { + try { + if (res != GLContext.CONTEXT_NOT_CURRENT) { + context.release(); + } + } catch (Exception e) { + } + if (lastContext != null) { + int res2 = lastContext.makeCurrent(); + if (res2 == GLContext.CONTEXT_CURRENT_NEW) { + lastInitAction.run(); + } + } + } + } } diff --git a/src/net/java/games/jogl/impl/GLPbufferImpl.java b/src/net/java/games/jogl/impl/GLPbufferImpl.java index 7b17c3010..4e8bd7c63 100644 --- a/src/net/java/games/jogl/impl/GLPbufferImpl.java +++ b/src/net/java/games/jogl/impl/GLPbufferImpl.java @@ -53,13 +53,13 @@ import net.java.games.jogl.*; public class GLPbufferImpl implements GLPbuffer { // GLPbufferContext - private GLContext context; + private GLContextImpl context; private GLDrawableHelper drawableHelper = new GLDrawableHelper(); private boolean isInitialized=false; private int floatMode; public GLPbufferImpl(GLContext context) { - this.context = context; + this.context = (GLContextImpl) context; } public void display() { @@ -73,15 +73,12 @@ public class GLPbufferImpl implements GLPbuffer { throw new GLException("Not yet implemented"); } - public void setSize(Dimension d) { - setSize(d.width, d.height); - } - - public Dimension getSize() { - return getSize(null); + public int getWidth() { + // FIXME + throw new GLException("Not yet implemented"); } - public Dimension getSize(Dimension d) { + public int getHeight() { // FIXME throw new GLException("Not yet implemented"); } @@ -110,26 +107,6 @@ public class GLPbufferImpl implements GLPbuffer { context.setGLU(glu); } - void willSetRenderingThread() { - // Not supported for pbuffers - } - - public void setRenderingThread(Thread currentThreadOrNull) throws GLException { - // Not supported for pbuffers - } - - public Thread getRenderingThread() { - // Not supported for pbuffers - return null; - } - - public void setNoAutoRedrawMode(boolean noAutoRedraws) { - } - - public boolean getNoAutoRedrawMode() { - return false; - } - public void setAutoSwapBufferMode(boolean onOrOff) { context.setAutoSwapBufferMode(onOrOff); } @@ -168,6 +145,11 @@ public class GLPbufferImpl implements GLPbuffer { return context; } + // FIXME: workaround for problems with deferring reshape actions + public GLDrawableHelper getDrawableHelper() { + return drawableHelper; + } + //---------------------------------------------------------------------- // No-ops for ComponentEvents // @@ -239,7 +221,7 @@ public class GLPbufferImpl implements GLPbuffer { throw new GLException(e); } } else { - context.invokeGL(invokeGLAction, isReshape, initAction); + drawableHelper.invokeGL(context, invokeGLAction, isReshape, initAction); } } @@ -271,14 +253,14 @@ public class GLPbufferImpl implements GLPbuffer { // being resized on the AWT event dispatch thread class DisplayOnEventDispatchThreadAction implements Runnable { public void run() { - context.invokeGL(displayAction, false, initAction); + drawableHelper.invokeGL(context, displayAction, false, initAction); } } private DisplayOnEventDispatchThreadAction displayOnEventDispatchThreadAction = new DisplayOnEventDispatchThreadAction(); class SwapBuffersOnEventDispatchThreadAction implements Runnable { public void run() { - context.invokeGL(swapBuffersAction, false, initAction); + drawableHelper.invokeGL(context, swapBuffersAction, false, initAction); } } private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction = diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java index 8cc33f8ff..b921116db 100644 --- a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java +++ b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java @@ -45,7 +45,7 @@ import net.java.games.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX import net.java.games.jogl.*; import net.java.games.jogl.impl.*; -public abstract class MacOSXGLContext extends GLContext +public abstract class MacOSXGLContext extends GLContextImpl { private static JAWT jawt; protected long nsContext; // NSOpenGLContext @@ -119,7 +119,7 @@ public abstract class MacOSXGLContext extends GLContext /** * Creates and initializes an appropriate OpenGl nsContext. Should only be - * called by {@link makeCurrent(Runnable)}. + * called by {@link makeCurrentImpl()}. */ protected boolean create(boolean pbuffer, boolean floatingPoint) { MacOSXGLContext other = (MacOSXGLContext) GLContextShareSet.getShareContext(this); @@ -165,7 +165,7 @@ public abstract class MacOSXGLContext extends GLContext return true; } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { boolean created = false; if (nsContext == 0) { if (!create()) { @@ -183,14 +183,12 @@ public abstract class MacOSXGLContext extends GLContext if (created) { resetGLFunctionAvailability(); - if (initAction != null) { - initAction.run(); - } + return CONTEXT_CURRENT_NEW; } - return true; + return CONTEXT_CURRENT; } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { if (!CGL.clearCurrentContext(nsContext, nsView)) { throw new GLException("Error freeing OpenGL nsContext"); } diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXOffscreenGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXOffscreenGLContext.java index 37b2302c0..39aab5652 100644 --- a/src/net/java/games/jogl/impl/macosx/MacOSXOffscreenGLContext.java +++ b/src/net/java/games/jogl/impl/macosx/MacOSXOffscreenGLContext.java @@ -83,7 +83,7 @@ public class MacOSXOffscreenGLContext extends MacOSXPbufferGLContext throw new GLException("Should not call this"); } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { if (pendingOffscreenResize && (nsContext != 0)) { if (pendingOffscreenWidth != width || pendingOffscreenHeight != height) { destroyPBuffer(); @@ -93,9 +93,9 @@ public class MacOSXOffscreenGLContext extends MacOSXPbufferGLContext pendingOffscreenResize = false; } } - return super.makeCurrent(initAction); + return super.makeCurrentImpl(); } - public synchronized void swapBuffers() throws GLException { + public void swapBuffers() throws GLException { } } diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXOnscreenGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXOnscreenGLContext.java index ba4eee0ef..f2398aab8 100644 --- a/src/net/java/games/jogl/impl/macosx/MacOSXOnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/macosx/MacOSXOnscreenGLContext.java @@ -53,6 +53,18 @@ public class MacOSXOnscreenGLContext extends MacOSXGLContext { private JAWT_DrawingSurfaceInfo dsi; private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; + // Indicates whether the component (if an onscreen context) has been + // realized. Plausibly, before the component is realized the JAWT + // should return an error or NULL object from some of its + // operations; this appears to be the case on Win32 but is not true + // at least with Sun's current X11 implementation (1.4.x), which + // crashes with no other error reported if the DrawingSurfaceInfo is + // fetched from a locked DrawingSurface during the validation as a + // result of calling show() on the main thread. To work around this + // we prevent any JAWT or OpenGL operations from being done until + // addNotify() is called on the component. + protected boolean realized; + // Variables for pbuffer support List pbuffersToInstantiate = new ArrayList(); @@ -82,8 +94,9 @@ public class MacOSXOnscreenGLContext extends MacOSXGLContext { return true; } - public synchronized GLContext createPbufferContext(GLCapabilities capabilities, int initialWidth, int initialHeight) { + public GLContext createPbufferContext(GLCapabilities capabilities, int initialWidth, int initialHeight) { MacOSXPbufferGLContext ctx = new MacOSXPbufferGLContext(capabilities, initialWidth, initialHeight); + ctx.setSynchronized(true); GLContextShareSet.registerSharing(this, ctx); pbuffersToInstantiate.add(ctx); return ctx; @@ -97,22 +110,17 @@ public class MacOSXOnscreenGLContext extends MacOSXGLContext { throw new GLException("Should not call this"); } - public synchronized void setRenderingThread(Thread currentThreadOrNull, Runnable initAction) { - this.willSetRenderingThread = false; - // FIXME: the JAWT in the Panther developer release - // requires all JAWT operations to be done on the AWT - // thread. This means that setRenderingThread won't work - // yet on this platform. This method can be deleted once - // the update for that release ships. - } - - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { try { + if (!realized) { + return CONTEXT_NOT_CURRENT; + } if (!lockSurface()) { - return false; + return CONTEXT_NOT_CURRENT; } - boolean ret = super.makeCurrent(initAction); - if (ret) { + int ret = super.makeCurrentImpl(); + if ((ret == CONTEXT_CURRENT) || + (ret == CONTEXT_CURRENT_NEW)) { // Assume the canvas might have been resized or moved and tell the OpenGL // context to update itself. This used to be done only upon receiving a // reshape event but that doesn't appear to be sufficient. An experiment @@ -142,15 +150,20 @@ public class MacOSXOnscreenGLContext extends MacOSXGLContext { } } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { try { - super.free(); + super.releaseImpl(); } finally { unlockSurface(); } } - public synchronized void swapBuffers() throws GLException { + protected void destroyImpl() throws GLException { + realized = false; + super.destroyImpl(); + } + + public void swapBuffers() throws GLException { if (!CGL.flushBuffer(nsContext, nsView)) { throw new GLException("Error swapping buffers"); } diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java index 6c8004bee..b163bb9ce 100644 --- a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java +++ b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java @@ -104,7 +104,7 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext { } } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { created = false; if (pBuffer == 0) { @@ -112,10 +112,10 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext { System.err.println("Pbuffer not instantiated yet for " + this); } // pbuffer not instantiated yet - return false; + return CONTEXT_NOT_CURRENT; } - boolean res = super.makeCurrent(initAction); + int res = super.makeCurrentImpl(); if (created) { // Initialize render-to-texture support if requested boolean rect = capabilities.getOffscreenRenderToTextureRectangle(); diff --git a/src/net/java/games/jogl/impl/mipmap/BuildMipmap.java b/src/net/java/games/jogl/impl/mipmap/BuildMipmap.java index 9c9c3122b..06a6a02bc 100644 --- a/src/net/java/games/jogl/impl/mipmap/BuildMipmap.java +++ b/src/net/java/games/jogl/impl/mipmap/BuildMipmap.java @@ -46,7 +46,8 @@ import java.io.*; */ public class BuildMipmap { - private static boolean DEBUG = Debug.debug("BuildMipmap"); + private static final boolean DEBUG = Debug.debug("BuildMipmap"); + private static final boolean VERBOSE = Debug.verbose(); /** Creates a new instance of BuildMipmap */ public BuildMipmap() { @@ -663,16 +664,18 @@ public class BuildMipmap { gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, srcImage ); if (DEBUG) { System.err.println("GL Error(" + level + "): " + gl.glGetError() ); - try { - File file = new File( "glu2DMipmapJ" + level + ".bin" ); - FileOutputStream fos = new FileOutputStream( file ); - srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); - fos.getChannel().write( srcImage ); - srcImage.clear(); - fos.close(); - } catch( IOException e ) { - System.err.println("IOException"); - System.err.println(e.getMessage()); + if (VERBOSE) { + try { + File file = new File( "glu2DMipmapJ" + level + ".bin" ); + FileOutputStream fos = new FileOutputStream( file ); + srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); + fos.getChannel().write( srcImage ); + srcImage.clear(); + fos.close(); + } catch( IOException e ) { + System.err.println("IOException"); + System.err.println(e.getMessage()); + } } } } @@ -769,15 +772,17 @@ public class BuildMipmap { gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, srcImage ); if (DEBUG) { System.err.println("GL Error(" + level + "): " + gl.glGetError() ); - try { - File file = new File( "glu2DMipmapJ" + level + ".bin" ); - FileOutputStream fos = new FileOutputStream( file ); - srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); - fos.getChannel().write( srcImage ); - srcImage.clear(); - } catch( IOException e ) { - System.err.println("IOException"); - System.err.println(e.getMessage()); + if (VERBOSE) { + try { + File file = new File( "glu2DMipmapJ" + level + ".bin" ); + FileOutputStream fos = new FileOutputStream( file ); + srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); + fos.getChannel().write( srcImage ); + srcImage.clear(); + } catch( IOException e ) { + System.err.println("IOException"); + System.err.println(e.getMessage()); + } } } } @@ -817,15 +822,17 @@ public class BuildMipmap { gl.glTexImage2D( target, level, internalFormat, newwidth, newheight, 0, format, type, newMipmapImage ); if (DEBUG) { System.err.println("GL Error: " + gl.glGetError() ); - try { - File file = new File( "glu2DMipmapJ" + level + ".bin" ); - FileOutputStream fos = new FileOutputStream( file ); - srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); - fos.getChannel().write( newMipmapImage ); - srcImage.clear(); - } catch( IOException e ) { - System.err.println("IOException"); - System.err.println(e.getMessage()); + if (VERBOSE) { + try { + File file = new File( "glu2DMipmapJ" + level + ".bin" ); + FileOutputStream fos = new FileOutputStream( file ); + srcImage.limit( Mipmap.image_size( newwidth, newheight, format, type ) ); + fos.getChannel().write( newMipmapImage ); + srcImage.clear(); + } catch( IOException e ) { + System.err.println("IOException"); + System.err.println(e.getMessage()); + } } } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java index e938c8023..338b11e6a 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java @@ -48,7 +48,7 @@ import net.java.games.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX import net.java.games.jogl.*; import net.java.games.jogl.impl.*; -public abstract class WindowsGLContext extends GLContext { +public abstract class WindowsGLContext extends GLContextImpl { private static JAWT jawt; protected long hglrc; protected long hdc; @@ -124,11 +124,11 @@ public abstract class WindowsGLContext extends GLContext { /** * Creates and initializes an appropriate OpenGL context. Should only be - * called by {@link #makeCurrent(Runnable)}. + * called by {@link #makeCurrentImpl()}. */ protected abstract void create(); - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { boolean created = false; if (hglrc == 0) { create(); @@ -177,13 +177,12 @@ public abstract class WindowsGLContext extends GLContext { } } GLContextShareSet.contextCreated(this); - - initAction.run(); + return CONTEXT_CURRENT_NEW; } - return true; + return CONTEXT_CURRENT; } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { if (!NO_FREE) { if (!WGL.wglMakeCurrent(0, 0)) { throw new GLException("Error freeing OpenGL context: " + WGL.GetLastError()); diff --git a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java index c70607da7..d944a8684 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java @@ -92,9 +92,9 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { return false; } - public synchronized GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLContext createPbufferContext(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { throw new GLException("Not supported"); } @@ -106,7 +106,7 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { throw new GLException("Should not call this"); } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { if (pendingOffscreenResize) { if (pendingOffscreenWidth != width || pendingOffscreenHeight != height) { if (hglrc != 0) { @@ -117,7 +117,7 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { pendingOffscreenResize = false; } } - return super.makeCurrent(initAction); + return super.makeCurrentImpl(); } protected void destroyImpl() { @@ -133,7 +133,7 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { } } - public synchronized void swapBuffers() throws GLException { + public void swapBuffers() throws GLException { } protected void create() { diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java index 0dc1818fb..d4af4b3b7 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java @@ -51,6 +51,18 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { JAWT_DrawingSurfaceInfo dsi; JAWT_Win32DrawingSurfaceInfo win32dsi; + // Indicates whether the component (if an onscreen context) has been + // realized. Plausibly, before the component is realized the JAWT + // should return an error or NULL object from some of its + // operations; this appears to be the case on Win32 but is not true + // at least with Sun's current X11 implementation (1.4.x), which + // crashes with no other error reported if the DrawingSurfaceInfo is + // fetched from a locked DrawingSurface during the validation as a + // result of calling show() on the main thread. To work around this + // we prevent any JAWT or OpenGL operations from being done until + // addNotify() is called on the component. + protected boolean realized; + // Variables for pbuffer support List pbuffersToInstantiate = new ArrayList(); @@ -61,6 +73,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { super(component, capabilities, chooser, shareWith); } + /* public void invokeGL(Runnable runnable, boolean isReshape, Runnable initAction) throws GLException { // Unfortunately, invokeGL can be called with the AWT tree lock // held, and the Windows onscreen implementation of @@ -79,6 +92,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { super.invokeGL(runnable, isReshape, initAction); } } + */ protected GL createGL() { @@ -101,10 +115,11 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { return haveWGLARBPbuffer(); } - public synchronized GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLContext createPbufferContext(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { WindowsPbufferGLContext ctx = new WindowsPbufferGLContext(capabilities, initialWidth, initialHeight); + ctx.setSynchronized(true); pbuffersToInstantiate.add(ctx); return ctx; } @@ -117,13 +132,21 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { throw new GLException("Should not call this"); } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + public void setRealized() { + realized = true; + } + + protected int makeCurrentImpl() throws GLException { try { + if (!realized) { + return CONTEXT_NOT_CURRENT; + } if (!lockSurface()) { - return false; + return CONTEXT_NOT_CURRENT; } - boolean ret = super.makeCurrent(initAction); - if (ret) { + int ret = super.makeCurrentImpl(); + if ((ret == CONTEXT_CURRENT) || + (ret == CONTEXT_CURRENT_NEW)) { // Instantiate any pending pbuffers while (!pbuffersToInstantiate.isEmpty()) { WindowsPbufferGLContext ctx = @@ -142,15 +165,20 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { } } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { try { - super.free(); + super.releaseImpl(); } finally { unlockSurface(); } } - public synchronized void swapBuffers() throws GLException { + protected void destroyImpl() throws GLException { + realized = false; + super.destroyImpl(); + } + + public void swapBuffers() throws GLException { if (!WGL.SwapBuffers(hdc) && (WGL.GetLastError() != 0)) { throw new GLException("Error swapping buffers"); } diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java index 26108a5cd..d58d15d02 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java @@ -382,7 +382,7 @@ public class WindowsPbufferGLContext extends WindowsGLContext { } } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { created = false; if (buffer == 0) { @@ -390,10 +390,10 @@ public class WindowsPbufferGLContext extends WindowsGLContext { if (DEBUG) { System.err.println("pbuffer not instantiated yet"); } - return false; + return CONTEXT_NOT_CURRENT; } - boolean res = super.makeCurrent(initAction); + int res = super.makeCurrentImpl(); if (DEBUG) { System.err.println("super.makeCurrent() = " + res + ", created = " + created); } diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java index 837b7b791..7077c855e 100644 --- a/src/net/java/games/jogl/impl/x11/X11GLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java @@ -46,7 +46,7 @@ import net.java.games.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX import net.java.games.jogl.*; import net.java.games.jogl.impl.*; -public abstract class X11GLContext extends GLContext { +public abstract class X11GLContext extends GLContextImpl { protected long display; protected long drawable; protected long visualID; @@ -126,19 +126,9 @@ public abstract class X11GLContext extends GLContext { public abstract boolean offscreenImageNeedsVerticalFlip(); - public synchronized void setRenderingThread(Thread currentThreadOrNull, Runnable initAction) { - this.willSetRenderingThread = false; - // FIXME: the JAWT on X11 grabs the AWT lock while the - // DrawingSurface is locked, which means that no other events can - // be processed. Currently we handle this by preventing the - // effects of setRenderingThread. We should figure out a better - // solution that is reasonably robust. Must file a bug to be fixed - // in the 1.5 JAWT. - } - /** * Creates and initializes an appropriate OpenGl context. Should only be - * called by {@link makeCurrent(Runnable)}. + * called by {@link makeCurrentImpl()}. */ protected abstract void create(); @@ -150,7 +140,7 @@ public abstract class X11GLContext extends GLContext { return super.isExtensionAvailable(glExtensionName); } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { boolean created = false; if (context == 0) { create(); @@ -172,12 +162,12 @@ public abstract class X11GLContext extends GLContext { if (created) { resetGLFunctionAvailability(); - initAction.run(); + return CONTEXT_CURRENT_NEW; } - return true; + return CONTEXT_CURRENT; } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { if (!GLX.glXMakeCurrent(display, 0, 0)) { throw new GLException("Error freeing OpenGL context"); } diff --git a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java index 2e30e2b18..c493d3380 100644 --- a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java @@ -95,9 +95,9 @@ public class X11OffscreenGLContext extends X11GLContext { return false; } - public synchronized GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLContext createPbufferContext(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { throw new GLException("Not supported"); } @@ -109,7 +109,7 @@ public class X11OffscreenGLContext extends X11GLContext { throw new GLException("Should not call this"); } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { display = X11GLContextFactory.getDisplayConnection(); if (pendingOffscreenResize) { if (pendingOffscreenWidth != width || pendingOffscreenHeight != height) { @@ -122,15 +122,15 @@ public class X11OffscreenGLContext extends X11GLContext { } } mostRecentDisplay = display; - return super.makeCurrent(initAction); + return super.makeCurrentImpl(); } - public synchronized void swapBuffers() throws GLException { + public void swapBuffers() throws GLException { } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { try { - super.free(); + super.releaseImpl(); } finally { display = 0; } diff --git a/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java b/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java index 2fd340d79..5a6fe23bb 100644 --- a/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java @@ -51,6 +51,18 @@ public class X11OnscreenGLContext extends X11GLContext { private JAWT_DrawingSurfaceInfo dsi; private JAWT_X11DrawingSurfaceInfo x11dsi; + // Indicates whether the component (if an onscreen context) has been + // realized. Plausibly, before the component is realized the JAWT + // should return an error or NULL object from some of its + // operations; this appears to be the case on Win32 but is not true + // at least with Sun's current X11 implementation (1.4.x), which + // crashes with no other error reported if the DrawingSurfaceInfo is + // fetched from a locked DrawingSurface during the validation as a + // result of calling show() on the main thread. To work around this + // we prevent any JAWT or OpenGL operations from being done until + // addNotify() is called on the component. + protected boolean realized; + // Variables for pbuffer support List pbuffersToInstantiate = new ArrayList(); @@ -83,10 +95,11 @@ public class X11OnscreenGLContext extends X11GLContext { return true; } - public synchronized GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLContext createPbufferContext(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { X11PbufferGLContext ctx = new X11PbufferGLContext(capabilities, initialWidth, initialHeight); + ctx.setSynchronized(true); pbuffersToInstantiate.add(ctx); return ctx; } @@ -106,13 +119,21 @@ public class X11OnscreenGLContext extends X11GLContext { } } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + public void setRealized() { + realized = true; + } + + protected int makeCurrentImpl() throws GLException { try { + if (!realized) { + return CONTEXT_NOT_CURRENT; + } if (!lockSurface()) { - return false; + return CONTEXT_NOT_CURRENT; } - boolean ret = super.makeCurrent(initAction); - if (ret) { + int ret = super.makeCurrentImpl(); + if ((ret == CONTEXT_CURRENT) || + (ret == CONTEXT_CURRENT_NEW)) { // Instantiate any pending pbuffers while (!pbuffersToInstantiate.isEmpty()) { X11PbufferGLContext ctx = @@ -131,15 +152,20 @@ public class X11OnscreenGLContext extends X11GLContext { } } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { try { - super.free(); + super.releaseImpl(); } finally { unlockSurface(); } } - public synchronized void swapBuffers() throws GLException { + protected void destroyImpl() throws GLException { + realized = false; + super.destroyImpl(); + } + + public void swapBuffers() throws GLException { // FIXME: this cast to int would be wrong on 64-bit platforms // where the argument type to glXMakeCurrent would change (should // probably make GLXDrawable, and maybe XID, Opaque as long) diff --git a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java index 7733472fb..30a60ba61 100644 --- a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java @@ -234,10 +234,10 @@ public class X11PbufferGLContext extends X11GLContext { } } - protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + protected int makeCurrentImpl() throws GLException { if (buffer == 0) { // pbuffer not instantiated yet - return false; + return CONTEXT_NOT_CURRENT; } lockAWT(); @@ -257,15 +257,15 @@ public class X11PbufferGLContext extends X11GLContext { if (created) { resetGLFunctionAvailability(); - initAction.run(); + return CONTEXT_CURRENT_NEW; } - return true; + return CONTEXT_CURRENT; } finally { unlockAWT(); } } - protected synchronized void free() throws GLException { + protected void releaseImpl() throws GLException { lockAWT(); try { if (!GLX.glXMakeContextCurrent(display, 0, 0, 0)) { |