diff options
Diffstat (limited to 'src/net/java/games')
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)) { |