diff options
5 files changed, 227 insertions, 53 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLContextImpl.java b/src/classes/com/sun/opengl/impl/GLContextImpl.java index 5dbf08df6..d79de9f5a 100644 --- a/src/classes/com/sun/opengl/impl/GLContextImpl.java +++ b/src/classes/com/sun/opengl/impl/GLContextImpl.java @@ -66,9 +66,11 @@ public abstract class GLContextImpl extends GLContext { public GLContextImpl(GLContext shareWith) { setGL(createGL()); functionAvailability = new FunctionAvailabilityCache(this); - if (shareWith != null || GLContextShareSet.isObjectTrackingDebuggingEnabled()) { - GLContextShareSet.registerSharing(this, shareWith); + GLContext shareContext = Java2D.filterShareContext(shareWith); + if (shareContext != null) { + GLContextShareSet.registerSharing(this, shareContext); } + GLContextShareSet.registerForObjectTracking(shareWith, this); } public int makeCurrent() throws GLException { diff --git a/src/classes/com/sun/opengl/impl/GLContextShareSet.java b/src/classes/com/sun/opengl/impl/GLContextShareSet.java index b0d1b1da4..283a56f85 100644 --- a/src/classes/com/sun/opengl/impl/GLContextShareSet.java +++ b/src/classes/com/sun/opengl/impl/GLContextShareSet.java @@ -62,17 +62,6 @@ public class GLContextShareSet { private Map createdShares = new WeakHashMap(); private Map destroyedShares = new WeakHashMap(); - // When the Java2D/OpenGL pipeline is active and using FBOs to - // render, we need to track the creation and destruction of - // server-side OpenGL objects among contexts sharing these objects - private GLObjectTracker tracker; - - public ShareSet() { - if (isObjectTrackingEnabled()) { - tracker = new GLObjectTracker(); - } - } - public void add(GLContext ctx) { if (allShares.put(ctx, dummyValue) == null) { // FIXME: downcast to GLContextImpl undesirable @@ -111,57 +100,26 @@ public class GLContextShareSet { assert res == null : "State of ShareSet corrupted; thought context " + ctx + " shouldn't have been in destroyed set but was"; } - - public GLObjectTracker getObjectTracker() { - return tracker; - } - } - - private static boolean isObjectTrackingEnabled() { - return (Java2D.isOGLPipelineActive() && Java2D.isFBOEnabled()); - } - - /** Indicates to callers whether sharing must be registered even for - contexts which don't share textures and display lists with any - others. */ - public static boolean isObjectTrackingDebuggingEnabled() { - return forceTracking; } /** Indicate that contexts <code>share1</code> and - <code>share2</code> will share textures and display lists. */ + <code>share2</code> will share textures and display lists. Both + must be non-null. */ public static synchronized void registerSharing(GLContext share1, GLContext share2) { + if (share1 == null || share2 == null) { + throw new IllegalArgumentException("Both share1 and share2 must be non-null"); + } ShareSet share = entryFor(share1); - if (share == null && (share2 != null)) { + if (share == null) { share = entryFor(share2); } if (share == null) { share = new ShareSet(); } share.add(share1); - if (share2 != null) { - share.add(share2); - } + share.add(share2); addEntry(share1, share); - if (share2 != null) { - addEntry(share2, share); - } - GLObjectTracker tracker = share.getObjectTracker(); - if (tracker != null) { - // FIXME: downcast to GLContextImpl undesirable - GLContextImpl impl1 = (GLContextImpl) share1; - GLContextImpl impl2 = (GLContextImpl) share2; - if (impl1.getObjectTracker() == null) { - impl1.setObjectTracker(tracker); - } - if ((impl2 != null) && (impl2.getObjectTracker() == null)) { - impl2.setObjectTracker(tracker); - } - assert impl1.getObjectTracker() == tracker : "State of ShareSet corrupted; " + - "got different-than-expected GLObjectTracker for context 1"; - assert (impl2 == null) || (impl2.getObjectTracker() == tracker) : "State of ShareSet corrupted; " + - "got different-than-expected GLObjectTracker for context 2"; - } + addEntry(share2, share); } public static synchronized GLContext getShareContext(GLContext contextToCreate) { @@ -186,6 +144,49 @@ public class GLContextShareSet { } } + /** Indicates that the two supplied contexts (which must be able to + share textures and display lists) should be in the same + namespace for tracking of server-side object creation and + deletion. Because the sharing necessary behind the scenes is + different than that requested at the user level, the two notions + are different. This must be called immediately after the + creation of the new context (which is the second argument) + before any server-side OpenGL objects have been created in that + context. */ + public static synchronized void registerForObjectTracking(GLContext olderContextOrNull, + GLContext newContext) { + if (isObjectTrackingEnabled() || isObjectTrackingDebuggingEnabled()) { + if (olderContextOrNull != null && + newContext != null) { + if (entryFor(olderContextOrNull) != entryFor(newContext)) { + throw new IllegalArgumentException("old and new contexts must be able to share textures and display lists"); + } + } + + // FIXME: downcast to GLContextImpl undesirable + GLContextImpl impl1 = (GLContextImpl) olderContextOrNull; + GLContextImpl impl2 = (GLContextImpl) newContext; + GLObjectTracker tracker = null; + // Don't share object trackers with the primordial share context from Java2D + GLContext j2dShareContext = Java2D.getShareContext(); + if (impl1 != null && impl1 == j2dShareContext) { + impl1 = null; + } + if (impl1 != null) { + tracker = impl1.getObjectTracker(); + assert (tracker != null) + : "registerForObjectTracking was not called properly for the older context"; + } + if (tracker == null) { + tracker = new GLObjectTracker(); + } + // Note that we don't assert that the tracker is non-null for + // impl2 because the way we use this functionality we actually + // overwrite the initially-set object tracker in the new context + impl2.setObjectTracker(tracker); + } + } + //---------------------------------------------------------------------- // Internals only below this point // @@ -199,4 +200,13 @@ public class GLContextShareSet { shareMap.put(context, share); } } + + private static boolean isObjectTrackingEnabled() { + return ((Java2D.isOGLPipelineActive() && Java2D.isFBOEnabled()) || + isObjectTrackingDebuggingEnabled()); + } + + private static boolean isObjectTrackingDebuggingEnabled() { + return forceTracking; + } } diff --git a/src/classes/com/sun/opengl/impl/Java2D.java b/src/classes/com/sun/opengl/impl/Java2D.java index c3eaa3b7c..cf9e8ff1e 100755 --- a/src/classes/com/sun/opengl/impl/Java2D.java +++ b/src/classes/com/sun/opengl/impl/Java2D.java @@ -40,6 +40,7 @@ package com.sun.opengl.impl; import java.awt.*; +import java.awt.image.*; import java.lang.reflect.*; import java.security.*; @@ -59,6 +60,18 @@ public class Java2D { private static Method getOGLScissorBoxMethod; private static Method getOGLSurfaceIdentifierMethod; + // If FBOs are enabled in the Java2D/OpenGL pipeline, all contexts + // created by JOGL must share textures and display lists with the + // Java2D contexts in order to access the frame buffer object for + // potential rendering, and to simultaneously support sharing of + // textures and display lists with one another. Java2D has the + // notion of a single shared context with which all other contexts + // (on the same display device?) share textures and display lists; + // this is an approximation to that notion which will be refined + // later. + private static VolatileImage j2dFBOVolatileImage; // just a dummy image + private static GLContext j2dFBOShareContext; + static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { @@ -174,6 +187,12 @@ public class Java2D { } } + /** Returns the OpenGL viewport associated with the given Graphics + object, assuming that the Graphics object is associated with a + component of the specified width and height. The user should + call glViewport() with the returned rectangle's bounds in order + to get correct rendering results. Should only be called from the + Queue Flusher Thread. */ public static Rectangle getOGLViewport(Graphics g, int componentWidth, int componentHeight) { @@ -192,6 +211,12 @@ public class Java2D { } } + /** Returns the OpenGL scissor region associated with the given + Graphics object, taking into account all clipping regions, etc. + To avoid destroying Java2D's previous rendering results, this + method should be called and the resulting rectangle's bounds + passed to a call to glScissor(). Should only be called from the + Queue Flusher Thread. */ public static Rectangle getOGLScissorBox(Graphics g) { if (!isOGLPipelineActive()) { throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); @@ -206,7 +231,12 @@ public class Java2D { } } - + /** Returns an opaque "surface identifier" associated with the given + Graphics object. If this changes from invocation to invocation, + the underlying OpenGL drawable for the Graphics object has + changed and a new external GLDrawable and GLContext should be + created (and the old ones destroyed). Should only be called from + the Queue Flusher Thread.*/ public static Object getOGLSurfaceIdentifier(Graphics g) { if (!isOGLPipelineActive()) { throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); @@ -220,4 +250,76 @@ public class Java2D { throw (InternalError) new InternalError().initCause(e); } } + + /** Returns either the given GLContext or a substitute one with + which clients should share textures and display lists. Needed + when the Java2D/OpenGL pipeline is active and FBOs are being + used for rendering. FIXME: may need to alter the API in the + future to indicate which GraphicsDevice the source context is + associated with. */ + public static GLContext filterShareContext(GLContext shareContext) { + initFBOShareContext(); + if (j2dFBOShareContext != null) { + return j2dFBOShareContext; + } + return shareContext; + } + + /** Returns the GLContext associated with the Java2D "share + context", with which all contexts created by JOGL must share + textures and display lists when the FBO option is enabled for + the Java2D/OpenGL pipeline. */ + public static GLContext getShareContext() { + initFBOShareContext(); + return j2dFBOShareContext; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private static void initFBOShareContext() { + // Note 1: this must not be done in the static initalizer due to + // deadlock problems. + + // Note 2: the first execution of this method must not be from the + // Java2D Queue Flusher Thread. + + // Note that at this point it's basically impossible that we're + // executing on the Queue Flusher Thread since all calls (even + // from end users) should be going through this interface and + // we're still in the static initializer + if (isOGLPipelineActive() && + isFBOEnabled() && + j2dFBOVolatileImage == null) { + // Create a compatible VolatileImage (FIXME: may need one per + // display device, and may need to create them lazily, which may + // cause problems) and create a JOGL GLContext to wrap its + // GLContext. + // + // FIXME: this technique is not really adequate. The + // VolatileImage may be punted at any time, meaning that its + // OpenGL context will be destroyed and any shares of + // server-side objects with it will be gone. This context is + // currently the "pinch point" through which all of the shares + // with the set of contexts created by JOGL go through. Java2D + // has the notion of its own share context with which all of the + // contexts it creates internally share server-side objects; + // what is really needed is another API in OGLUtilities to + // invoke a Runnable with that share context current rather than + // the context associated with a particular Graphics object, so + // that JOGL can grab a handle to that persistent context. + j2dFBOVolatileImage = + GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice(). + getDefaultConfiguration(). + createCompatibleVolatileImage(2, 2); + invokeWithOGLContextCurrent(j2dFBOVolatileImage.getGraphics(), new Runnable() { + public void run() { + j2dFBOShareContext = GLDrawableFactory.getFactory().createExternalGLContext(); + } + }); + } + } } diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLContext.java b/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLContext.java index 694aa6b0d..a12f156f5 100755 --- a/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLContext.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLContext.java @@ -51,6 +51,9 @@ public class WindowsExternalGLContext extends WindowsGLContext { public WindowsExternalGLContext() { super(null, null); hglrc = WGL.wglGetCurrentContext(); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Created external OpenGL context " + toHexString(hglrc) + " for " + this); + } GLContextShareSet.contextCreated(this); resetGLFunctionAvailability(); } diff --git a/src/classes/javax/media/opengl/GLJPanel.java b/src/classes/javax/media/opengl/GLJPanel.java index ad5a7f769..1dd204239 100644 --- a/src/classes/javax/media/opengl/GLJPanel.java +++ b/src/classes/javax/media/opengl/GLJPanel.java @@ -80,6 +80,10 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { private static final boolean DEBUG = Debug.debug("GLJPanel"); private static final boolean VERBOSE = Debug.verbose(); + // FIXME: remove these once debugging is done + private static final boolean HACK1 = Debug.debug("GLJPanel.hack1"); + private static final boolean HACK2 = Debug.debug("GLJPanel.hack2"); + private GLDrawableHelper drawableHelper = new GLDrawableHelper(); private volatile boolean isInitialized; private volatile boolean shouldInitialize = false; @@ -159,11 +163,23 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { // properly render into Java2D back buffer private int[] drawBuffer = new int[1]; private int[] readBuffer = new int[1]; + // This is required when the FBO option of the Java2D / OpenGL + // pipeline is active + private int[] frameBuffer = new int[1]; // These are always set to (0, 0) except when the Java2D / OpenGL // pipeline is active private int viewportX; private int viewportY; + static { + // Force eager initialization of part of the Java2D class since + // otherwise it's likely it will try to be initialized while on + // the Queue Flusher Thread, which is not allowed + if (Java2D.isOGLPipelineActive() && Java2D.isFBOEnabled()) { + Java2D.getShareContext(); + } + } + /** Creates a new GLJPanel component with a default set of OpenGL capabilities and using the default OpenGL capabilities selection mechanism. */ @@ -220,6 +236,9 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { private void captureJ2DState(GL gl) { gl.glGetIntegerv(GL.GL_DRAW_BUFFER, drawBuffer, 0); gl.glGetIntegerv(GL.GL_READ_BUFFER, readBuffer, 0); + if (Java2D.isFBOEnabled()) { + gl.glGetIntegerv(GL.GL_FRAMEBUFFER_BINDING_EXT, frameBuffer, 0); + } } private boolean preGL(Graphics g) { @@ -249,6 +268,22 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { gl.glDrawBuffer(drawBuffer[0]); gl.glReadBuffer(readBuffer[0]); + + // If the FBO option is active, bind to the FBO from the Java2D + // context. + // Note that all of the plumbing in the context sharing stuff will + // allow us to bind to this object since it's in our namespace. + if (Java2D.isFBOEnabled()) { + if (DEBUG && VERBOSE) { + System.err.println("Binding to framebuffer object " + frameBuffer[0]); + } + + gl.glBindTexture(GL.GL_TEXTURE_2D, 0); + gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBuffer[0]); + // FIXME: do we need to do anything else? Bind Texture2D state + // or something else? + } + return true; } @@ -346,6 +381,28 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { joglDrawable = GLDrawableFactory.getFactory().createExternalGLDrawable(); joglContext = joglDrawable.createContext(shareWith); } + + // FIXME: remove these once debugging is done + if (HACK1) { + // Skip all GLContext manipulation This fixes the + // display of the icons and text (done with Java2D) + // in the JGears demo when FBO is active + return; + } + if (HACK2) { + // Do a little GLContext manipulation but skip all + // FBO-related manipulation and other stuff (as well + // as the user rendering). + + // Note that the icons and text in the JGears demo + // disappear when this flag is used, so clearly any + // OpenGL context manipulation is messing up the + // Java2D context state when FBO is active. + joglContext.makeCurrent(); + joglContext.release(); + return; + } + drawableHelper.invokeGL(joglDrawable, joglContext, displayAction, initAction); } } finally { |