diff options
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) { |