diff options
author | Kenneth Russel <[email protected]> | 2006-02-11 01:11:57 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2006-02-11 01:11:57 +0000 |
commit | 8ebdef6860e34bf16b9b13c657f651bf9ce32ab3 (patch) | |
tree | e1b51b0c8cacf3987f219b2e992af089aea5d1b4 | |
parent | b75d4a3718b1a5744218e19c4f5c1a9ff0311f34 (diff) |
Further work on FBO support in Java2D/JOGL bridge. Upgraded JOGL's
Java2D class to latest proposed set of APIs in OGLUtilities and
changed usage of these APIs to be approximately correct. Left in
fallback path for working with non-FBO case in current Mustang builds.
Not working yet, and don't yet understand why; checking in at this
intermediate point to be able to more easily test on more machines.
Added error checking to creation of external GLContexts and
GLDrawables on Windows and X11 platforms.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@597 232f8b59-042b-4e1e-8c03-345bb8c30851
8 files changed, 208 insertions, 72 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLContextImpl.java b/src/classes/com/sun/opengl/impl/GLContextImpl.java index d79de9f5a..0910fe250 100644 --- a/src/classes/com/sun/opengl/impl/GLContextImpl.java +++ b/src/classes/com/sun/opengl/impl/GLContextImpl.java @@ -123,15 +123,22 @@ public abstract class GLContextImpl extends GLContext { // If we are tracking creation and destruction of server-side // OpenGL objects, we must decrement the reference count of the // GLObjectTracker upon context destruction. - int res = makeCurrent(); - if (res != CONTEXT_CURRENT) { - // FIXME: we really need to behave better than this - throw new GLException("Unable to make context current to destroy tracked server-side OpenGL objects"); - } try { - tracker.unref(getGL()); - } finally { - release(); + int res = makeCurrent(); + if (res != CONTEXT_CURRENT) { + // FIXME: we really need to behave better than this + throw new GLException("Unable to make context current to destroy tracked server-side OpenGL objects"); + } + try { + tracker.unref(getGL()); + } finally { + release(); + } + } catch (GLException e) { + // FIXME: should probably do something more intelligent here + if (DEBUG) { + e.printStackTrace(); + } } } } diff --git a/src/classes/com/sun/opengl/impl/GLContextShareSet.java b/src/classes/com/sun/opengl/impl/GLContextShareSet.java index 283a56f85..20a9364fb 100644 --- a/src/classes/com/sun/opengl/impl/GLContextShareSet.java +++ b/src/classes/com/sun/opengl/impl/GLContextShareSet.java @@ -39,6 +39,9 @@ package com.sun.opengl.impl; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.lang.ref.*; import java.util.*; import javax.media.opengl.*; @@ -168,10 +171,20 @@ public class GLContextShareSet { 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 (Java2D.isOGLPipelineActive()) { + // FIXME: probably need to do something different here + // Need to be able to figure out the GraphicsDevice for the + // older context if it's on-screen + GraphicsConfiguration gc = GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice(). + getDefaultConfiguration(); + GLContext j2dShareContext = Java2D.getShareContext(gc); + if (impl1 != null && impl1 == j2dShareContext) { + impl1 = null; + } } + if (impl1 != null) { tracker = impl1.getObjectTracker(); assert (tracker != null) diff --git a/src/classes/com/sun/opengl/impl/Java2D.java b/src/classes/com/sun/opengl/impl/Java2D.java index cf9e8ff1e..bf3219b77 100755 --- a/src/classes/com/sun/opengl/impl/Java2D.java +++ b/src/classes/com/sun/opengl/impl/Java2D.java @@ -53,13 +53,27 @@ public class Java2D { private static boolean DEBUG = Debug.debug("Java2D"); private static boolean VERBOSE = Debug.verbose(); private static boolean isOGLPipelineActive; - private static boolean isFBOEnabled; private static Method invokeWithOGLContextCurrentMethod; private static Method isQueueFlusherThreadMethod; private static Method getOGLViewportMethod; private static Method getOGLScissorBoxMethod; private static Method getOGLSurfaceIdentifierMethod; + // The following methods and fields are needed for proper support of + // Frame Buffer Objects in the Java2D/OpenGL pipeline + // (-Dsun.java2d.opengl.fbobject=true) + private static boolean fbObjectSupportInitialized; + private static Method invokeWithOGLSharedContextCurrentMethod; + private static Method getOGLSurfaceTypeMethod; + + // Publicly-visible constants for OpenGL surface types + public static final int UNDEFINED = getOGLUtilitiesIntField("UNDEFINED"); + public static final int WINDOW = getOGLUtilitiesIntField("WINDOW"); + public static final int PBUFFER = getOGLUtilitiesIntField("PBUFFER"); + public static final int TEXTURE = getOGLUtilitiesIntField("TEXTURE"); + public static final int FLIP_BACKBUFFER = getOGLUtilitiesIntField("FLIP_BACKBUFFER"); + public static final int FBOBJECT = getOGLUtilitiesIntField("FBOBJECT"); + // 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 @@ -69,7 +83,7 @@ public class Java2D { // (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 boolean initializedJ2DFBOShareContext; private static GLContext j2dFBOShareContext; static { @@ -125,11 +139,32 @@ public class Java2D { }); getOGLSurfaceIdentifierMethod.setAccessible(true); - String fbo = System.getProperty("sun.java2d.opengl.fbobject"); - isFBOEnabled = (fbo != null) && "true".equals(fbo); + // Try to get additional methods required for proper FBO support + fbObjectSupportInitialized = true; + try { + invokeWithOGLSharedContextCurrentMethod = utils.getDeclaredMethod("invokeWithOGLSharedContextCurrent", + new Class[] { + GraphicsConfiguration.class, + Runnable.class + }); + invokeWithOGLSharedContextCurrentMethod.setAccessible(true); + + getOGLSurfaceTypeMethod = utils.getDeclaredMethod("getOGLSurfaceType", + new Class[] { + Graphics.class + }); + getOGLSurfaceTypeMethod.setAccessible(true); + } catch (Exception e) { + fbObjectSupportInitialized = false; + if (DEBUG && VERBOSE) { + e.printStackTrace(); + System.err.println("Disabling Java2D/JOGL FBO support"); + } + } } catch (Exception e) { if (DEBUG && VERBOSE) { e.printStackTrace(); + System.err.println("Disabling Java2D/JOGL integration"); } isOGLPipelineActive = false; } @@ -148,13 +183,11 @@ public class Java2D { } public static boolean isFBOEnabled() { - return isFBOEnabled; + return fbObjectSupportInitialized; } public static boolean isQueueFlusherThread() { - if (!isOGLPipelineActive()) { - throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); - } + checkActive(); try { return ((Boolean) isQueueFlusherThreadMethod.invoke(null, new Object[] {})).booleanValue(); @@ -169,9 +202,7 @@ public class Java2D { Graphics object and runs the given Runnable on the Queue Flushing Thread in one atomic action. */ public static void invokeWithOGLContextCurrent(Graphics g, Runnable r) throws GLException { - if (!isOGLPipelineActive()) { - throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); - } + checkActive(); try { GLDrawableFactoryImpl.getFactoryImpl().lockAWTForJava2D(); @@ -187,6 +218,31 @@ public class Java2D { } } + /** Makes current the "shared" OpenGL context associated with the + given GraphicsConfiguration object, allowing JOGL to share + server-side OpenGL objects like textures and display lists with + this context when necessary. This is needed when Java2D's FBO + support is enabled, because in order to render into that FBO, + JOGL must share textures and display lists with it. Returns + false if the passed GraphicsConfiguration was not an OpenGL + GraphicsConfiguration. */ + public static boolean invokeWithOGLSharedContextCurrent(GraphicsConfiguration g, Runnable r) throws GLException { + checkActive(); + + try { + GLDrawableFactoryImpl.getFactoryImpl().lockAWTForJava2D(); + try { + return ((Boolean) invokeWithOGLSharedContextCurrentMethod.invoke(null, new Object[] {g, r})).booleanValue(); + } finally { + GLDrawableFactoryImpl.getFactoryImpl().unlockAWTForJava2D(); + } + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (Exception e) { + throw (InternalError) new InternalError().initCause(e); + } + } + /** 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 @@ -196,9 +252,7 @@ public class Java2D { public static Rectangle getOGLViewport(Graphics g, int componentWidth, int componentHeight) { - if (!isOGLPipelineActive()) { - throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); - } + checkActive(); try { return (Rectangle) getOGLViewportMethod.invoke(null, new Object[] {g, @@ -218,9 +272,7 @@ public class Java2D { 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)"); - } + checkActive(); try { return (Rectangle) getOGLScissorBoxMethod.invoke(null, new Object[] {g}); @@ -238,9 +290,7 @@ public class Java2D { 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)"); - } + checkActive(); try { return getOGLSurfaceIdentifierMethod.invoke(null, new Object[] {g}); @@ -251,6 +301,27 @@ public class Java2D { } } + /** Returns the underlying surface type for the given Graphics + object. This indicates, in particular, whether Java2D is + currently rendering into a pbuffer or FBO. */ + public static int getOGLSurfaceType(Graphics g) { + checkActive(); + + try { + // FIXME: fallback path for pre-b73 (?) Mustang builds -- remove + // once fbobject support is in OGLUtilities + if (!fbObjectSupportInitialized) { + return 0; + } + + return ((Integer) getOGLSurfaceTypeMethod.invoke(null, new Object[] { g })).intValue(); + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (Exception e) { + 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 @@ -258,7 +329,11 @@ public class Java2D { future to indicate which GraphicsDevice the source context is associated with. */ public static GLContext filterShareContext(GLContext shareContext) { - initFBOShareContext(); + // FIXME: this may need adjustment + initFBOShareContext(GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice(). + getDefaultConfiguration()); if (j2dFBOShareContext != null) { return j2dFBOShareContext; } @@ -269,8 +344,10 @@ public class Java2D { 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(); + public static GLContext getShareContext(GraphicsConfiguration gc) { + initFBOShareContext(gc); + // FIXME: for full generality probably need to have multiple of + // these, one per GraphicsConfiguration seen? return j2dFBOShareContext; } @@ -278,44 +355,54 @@ public class Java2D { // Internals only below this point // - private static void initFBOShareContext() { + private static void checkActive() { + if (!isOGLPipelineActive()) { + throw new GLException("Java2D OpenGL pipeline not active (or necessary support not present)"); + } + } + + private static int getOGLUtilitiesIntField(final String name) { + Integer i = (Integer) AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + Class utils = Class.forName("sun.java2d.opengl.OGLUtilities"); + Field f = utils.getField(name); + f.setAccessible(true); + return f.get(null); + } catch (Exception e) { + if (DEBUG && VERBOSE) { + e.printStackTrace(); + } + return null; + } + } + }); + if (i == null) + return 0; + if (DEBUG && VERBOSE) { + System.err.println("OGLUtilities." + name + " = " + i.intValue()); + } + return i.intValue(); + } + + private static void initFBOShareContext(final GraphicsConfiguration gc) { // 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() { + !initializedJ2DFBOShareContext) { + + // FIXME: this technique is probably not adequate in multi-head + // situations. Ideally we would keep track of a given share + // context on a per-GraphicsConfiguration basis or something + // similar rather than keeping one share context in a global + // variable. + initializedJ2DFBOShareContext = true; + invokeWithOGLSharedContextCurrent(gc, 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 a12f156f5..c56614599 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 (hglrc == 0) { + throw new GLException("Error: attempted to make an external GLContext without a drawable/context current"); + } if (DEBUG) { System.err.println(getThreadName() + ": !!! Created external OpenGL context " + toHexString(hglrc) + " for " + this); } diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLDrawable.java b/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLDrawable.java index 68ab83161..23ec0a1fc 100755 --- a/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsExternalGLDrawable.java @@ -46,6 +46,9 @@ public class WindowsExternalGLDrawable extends WindowsGLDrawable { public WindowsExternalGLDrawable() { super(new GLCapabilities(), null); hdc = WGL.wglGetCurrentDC(); + if (hdc == 0) { + throw new GLException("Error: attempted to make an external GLDrawable without a drawable/context current"); + } } public GLContext createContext(GLContext shareWith) { diff --git a/src/classes/com/sun/opengl/impl/x11/X11ExternalGLContext.java b/src/classes/com/sun/opengl/impl/x11/X11ExternalGLContext.java index ae61c0063..e0446f4d6 100755 --- a/src/classes/com/sun/opengl/impl/x11/X11ExternalGLContext.java +++ b/src/classes/com/sun/opengl/impl/x11/X11ExternalGLContext.java @@ -51,6 +51,9 @@ public class X11ExternalGLContext extends X11GLContext { lockToolkit(); try { context = GLX.glXGetCurrentContext(); + if (context == 0) { + throw new GLException("Error: attempted to make an external GLContext without a drawable/context current"); + } drawable = new Drawable(GLX.glXGetCurrentDisplay()); } finally { unlockToolkit(); diff --git a/src/classes/com/sun/opengl/impl/x11/X11ExternalGLDrawable.java b/src/classes/com/sun/opengl/impl/x11/X11ExternalGLDrawable.java index e8fc069ba..10e58d3a0 100755 --- a/src/classes/com/sun/opengl/impl/x11/X11ExternalGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/x11/X11ExternalGLDrawable.java @@ -55,6 +55,9 @@ public class X11ExternalGLDrawable extends X11GLDrawable { display = GLX.glXGetCurrentDisplay(); drawable = GLX.glXGetCurrentDrawable(); readDrawable = GLX.glXGetCurrentReadDrawable(); + if (drawable == 0) { + throw new GLException("Error: attempted to make an external GLDrawable without a drawable/context current"); + } // Need GLXFBConfig ID in order to properly create new contexts // on this drawable diff --git a/src/classes/javax/media/opengl/GLJPanel.java b/src/classes/javax/media/opengl/GLJPanel.java index 6f8340aff..929975f13 100644 --- a/src/classes/javax/media/opengl/GLJPanel.java +++ b/src/classes/javax/media/opengl/GLJPanel.java @@ -178,7 +178,10 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { // 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(); + Java2D.getShareContext(GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice(). + getDefaultConfiguration()); } } @@ -235,11 +238,19 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { } } - private void captureJ2DState(GL gl) { + private void captureJ2DState(GL gl, Graphics g) { gl.glGetIntegerv(GL.GL_DRAW_BUFFER, drawBuffer, 0); gl.glGetIntegerv(GL.GL_READ_BUFFER, readBuffer, 0); - if (Java2D.isFBOEnabled()) { + if (Java2D.isFBOEnabled() && + Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) { + if (DEBUG && VERBOSE) { + System.err.println("-- Fetching GL_FRAMEBUFFER_BINDING_EXT"); + } gl.glGetIntegerv(GL.GL_FRAMEBUFFER_BINDING_EXT, frameBuffer, 0); + + // Unbind the framebuffer from this context before attempting to + // bind it to ours (may not be necessary) + // gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0); } } @@ -268,14 +279,12 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { viewportX = oglViewport.x; viewportY = oglViewport.y; - 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 (Java2D.isFBOEnabled() && + Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) { if (DEBUG && VERBOSE) { System.err.println("Binding to framebuffer object " + frameBuffer[0]); } @@ -284,6 +293,14 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBuffer[0]); // FIXME: do we need to do anything else? Bind Texture2D state // or something else? + } else { + if (DEBUG && VERBOSE) { + System.err.println("Setting up drawBuffer " + drawBuffer[0] + + " and readBuffer " + readBuffer[0]); + } + + gl.glDrawBuffer(drawBuffer[0]); + gl.glReadBuffer(readBuffer[0]); } return true; @@ -363,7 +380,7 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { j2dContext.makeCurrent(); try { - captureJ2DState(j2dContext.getGL()); + captureJ2DState(j2dContext.getGL(), g); Object curSurface = Java2D.getOGLSurfaceIdentifier(g); if (curSurface != null) { if (j2dSurface != curSurface) { |