diff options
10 files changed, 211 insertions, 178 deletions
diff --git a/src/net/java/games/jogl/GLDrawableFactory.java b/src/net/java/games/jogl/GLDrawableFactory.java index 38a2b904f..bf2a8535d 100644 --- a/src/net/java/games/jogl/GLDrawableFactory.java +++ b/src/net/java/games/jogl/GLDrawableFactory.java @@ -211,8 +211,9 @@ public class GLDrawableFactory { public boolean canCreateGLPbuffer(GLCapabilities capabilities, int initialWidth, int initialHeight) { - // FIXME - throw new GLException("Not yet implemented"); + return GLContextFactory.getFactory().canCreateGLPbuffer(capabilities, + initialWidth, + initialHeight); } @@ -223,7 +224,9 @@ public class GLDrawableFactory { int initialWidth, int initialHeight, GLContext shareWith) { - // FIXME - throw new GLException("Not yet implemented"); + return GLContextFactory.getFactory().createGLPbuffer(capabilities, + initialWidth, + initialHeight, + shareWith); } } diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java index be8cc22e6..e55507a67 100644 --- a/src/net/java/games/jogl/GLJPanel.java +++ b/src/net/java/games/jogl/GLJPanel.java @@ -83,6 +83,7 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { private GLDrawableHelper drawableHelper = new GLDrawableHelper(); private volatile boolean isInitialized; + private volatile boolean shouldInitialize = false; // Data used for either pbuffers or pixmap-based offscreen surfaces private GLCapabilities offscreenCaps; @@ -109,12 +110,9 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { // Implementation using pbuffers private static boolean hardwareAccelerationDisabled = Debug.isPropertyDefined("jogl.gljpanel.nohw"); - private boolean pbufferInitializationCompleted; private GLPbuffer pbuffer; private int pbufferWidth = 256; private int pbufferHeight = 256; - private GLCanvas heavyweight; - private Frame toplevel; // Implementation using software rendering private GLDrawableImpl offscreenDrawable; @@ -139,10 +137,6 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { } public void display() { - if (!isInitialized) { - return; - } - if (EventQueue.isDispatchThread()) { // Want display() to be synchronous, so call paintImmediately() paintImmediately(0, 0, getWidth(), getHeight()); @@ -161,32 +155,17 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { GLEventListener#display}. Should not be invoked by applications directly. */ public void paintComponent(Graphics g) { + if (shouldInitialize) { + initialize(); + } + if (!isInitialized) { return; } updater.setGraphics(g); if (!hardwareAccelerationDisabled) { - if (!pbufferInitializationCompleted) { - try { - heavyweight.display(); - pbuffer.display(); - } catch (GLException e) { - if (DEBUG) { - e.printStackTrace(); - } - // We consider any exception thrown during updating of the - // heavyweight or pbuffer during the initialization phases - // to be an indication that there was a problem - // instantiating the pbuffer, regardless of whether the - // exception originated in the user's GLEventListener. In - // these cases we immediately back off and use software - // rendering. - disableHardwareRendering(); - } - } else { - pbuffer.display(); - } + pbuffer.display(); } else { drawableHelper.invokeGL(offscreenDrawable, offscreenContext, displayAction, initAction); } @@ -194,7 +173,7 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { public void addNotify() { super.addNotify(); - initialize(); + shouldInitialize = true; if (DEBUG) { System.err.println("GLJPanel.addNotify()"); } @@ -211,11 +190,6 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { pbuffer.destroy(); pbuffer = null; } - if (toplevel != null) { - toplevel.dispose(); - toplevel = null; - heavyweight = null; - } } else { if (offscreenContext != null) { offscreenContext.destroy(); @@ -237,10 +211,6 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { public void reshape(int x, int y, int width, int height) { super.reshape(x, y, width, height); - if (!isInitialized) { - return; - } - // Move all reshape requests onto AWT EventQueue thread final int fx = x; final int fy = y; @@ -252,6 +222,19 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { readBackWidthInPixels = 0; readBackHeightInPixels = 0; + panelWidth = fwidth; + panelHeight = fheight; + + sendReshape = true; + + if (shouldInitialize) { + initialize(); + } + + if (!isInitialized) { + return; + } + if (!hardwareAccelerationDisabled) { // Use factor larger than 2 during shrinks for some hysteresis float shrinkFactor = 2.5f; @@ -287,19 +270,14 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { } else { offscreenContext.destroy(); offscreenDrawable.setSize(Math.max(1, fwidth), Math.max(1, fheight)); - readBackWidthInPixels = fwidth; - readBackHeightInPixels = fheight; + readBackWidthInPixels = Math.max(1, fwidth); + readBackHeightInPixels = Math.max(1, fheight); } if (offscreenImage != null) { offscreenImage.flush(); offscreenImage = null; } - - panelWidth = fwidth; - panelHeight = fheight; - - sendReshape = true; } }; if (EventQueue.isDispatchThread()) { @@ -430,68 +408,35 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { // Internals only below this point // - private void disableHardwareRendering() { - if (VERBOSE) { - System.err.println("GLJPanel: Falling back on software rendering due to pbuffer problems"); + private void initialize() { + if (panelWidth == 0 || + panelHeight == 0) { + // Not sized to non-zero size yet + return; } - hardwareAccelerationDisabled = true; - pbufferInitializationCompleted = false; - EventQueue.invokeLater(new Runnable() { - public void run() { - if (toplevel != null) { - toplevel.setVisible(false); - toplevel.dispose(); - toplevel = null; - heavyweight = null; - } - } - }); - initialize(); - } - private void initialize() { // Initialize either the hardware-accelerated rendering path or // the lightweight rendering path if (!hardwareAccelerationDisabled) { - boolean firstTime = false; - if (heavyweight == null) { - // Make the heavyweight share with the "shareWith" parameter. - // 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(), null, shareWith, null); - firstTime = true; - } - // FIXME: or'ing in true is a hack for lazy determination of - // canCreateOffscreenDrawable() on X11 - // This will go away once pbuffer creation is more eager - if (heavyweight.canCreateOffscreenDrawable() || true) { - if (firstTime) { - toplevel = new Frame(); - toplevel.setUndecorated(true); + if (GLDrawableFactory.getFactory().canCreateGLPbuffer(offscreenCaps, + pbufferWidth, + pbufferHeight)) { + if (pbuffer != null) { + throw new InternalError("Creating pbuffer twice without destroying it (memory leak / correctness bug)"); } - pbuffer = heavyweight.createOffscreenDrawable(offscreenCaps, pbufferWidth, pbufferHeight); - updater = new Updater(); - pbuffer.addGLEventListener(updater); - pbufferInitializationCompleted = false; - if (firstTime) { - toplevel.add(heavyweight); - toplevel.setSize(1, 1); + try { + pbuffer = GLDrawableFactory.getFactory().createGLPbuffer(offscreenCaps, + pbufferWidth, + pbufferHeight, + shareWith); + updater = new Updater(); + pbuffer.addGLEventListener(updater); + shouldInitialize = false; + isInitialized = true; + return; + } catch (GLException e) { + hardwareAccelerationDisabled = true; } - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - toplevel.setVisible(true); - } catch (GLException e) { - if (DEBUG) { - e.printStackTrace(); - } - disableHardwareRendering(); - } - } - }); - isInitialized = true; - return; } else { if (VERBOSE) { System.err.println("GLJPanel: Falling back on software rendering because no pbuffer support"); @@ -504,13 +449,14 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { } } - // Create an offscreen context instead + // Fall-through path: create an offscreen context instead offscreenDrawable = GLContextFactory.getFactory().createOffscreenDrawable(offscreenCaps, chooser); offscreenDrawable.setSize(Math.max(1, panelWidth), Math.max(1, panelHeight)); offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith); offscreenContext.setSynchronized(true); updater = new Updater(); + shouldInitialize = false; isInitialized = true; } @@ -525,20 +471,6 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { } public void init(GLAutoDrawable drawable) { - if (!hardwareAccelerationDisabled) { - if (DEBUG) { - System.err.println("GLJPanel$Updater.init(): pbufferInitializationCompleted = true"); - } - pbufferInitializationCompleted = true; - EventQueue.invokeLater(new Runnable() { - public void run() { - // Race conditions might dispose of this before now - if (toplevel != null) { - toplevel.setVisible(false); - } - } - }); - } drawableHelper.init(GLJPanel.this); } @@ -628,6 +560,9 @@ public final class GLJPanel extends JPanel implements GLAutoDrawable { if (readBackBytes != null) { gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackBytes, 0); } else if (readBackInts != null) { + if (DEBUG && VERBOSE) { + System.err.println("GLJPanel$Updater.display(): readBackInts.length == " + readBackInts.length); + } gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackInts, 0); } diff --git a/src/net/java/games/jogl/impl/GLContextFactory.java b/src/net/java/games/jogl/impl/GLContextFactory.java index bd5497619..bbdb73853 100644 --- a/src/net/java/games/jogl/impl/GLContextFactory.java +++ b/src/net/java/games/jogl/impl/GLContextFactory.java @@ -106,4 +106,13 @@ public abstract class GLContextFactory { // GLJPanel support public abstract GLDrawableImpl createOffscreenDrawable(GLCapabilities capabilities, GLCapabilitiesChooser chooser); + + public abstract boolean canCreateGLPbuffer(GLCapabilities capabilities, + int initialWidth, + int initialHeight); + + public abstract GLPbuffer createGLPbuffer(GLCapabilities capabilities, + int initialWidth, + int initialHeight, + GLContext shareWith); } diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java index d0ea429a4..cde1d54b1 100644 --- a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java +++ b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java @@ -161,11 +161,11 @@ public abstract class MacOSXGLContext extends GLContextImpl if (!CGL.deleteContext(nsContext, 0)) { throw new GLException("Unable to delete OpenGL context"); } - nsContext = 0; - GLContextShareSet.contextDestroyed(this); if (DEBUG) { System.err.println("!!! Destroyed OpenGL context " + nsContext); } + nsContext = 0; + GLContextShareSet.contextDestroyed(this); } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java index fccd0bf70..64cb74868 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java @@ -179,11 +179,11 @@ public class WindowsGLContext extends GLContextImpl { if (!WGL.wglDeleteContext(hglrc)) { throw new GLException("Unable to delete OpenGL context"); } - hglrc = 0; - GLContextShareSet.contextDestroyed(this); if (DEBUG) { System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + toHexString(hglrc)); } + hglrc = 0; + GLContextShareSet.contextDestroyed(this); } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java index fb03b8702..1ea4c8b95 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java @@ -40,18 +40,16 @@ package net.java.games.jogl.impl.windows; import java.awt.Component; +import java.awt.EventQueue; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Rectangle; import java.io.File; +import java.lang.reflect.InvocationTargetException; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Collection; -import java.util.Iterator; +import java.util.ArrayList; +import java.util.List; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; @@ -63,21 +61,6 @@ public class WindowsGLContextFactory extends GLContextFactory { NativeLibLoader.load(); } - // On Windows we want to be able to use some extension routines like - // wglChoosePixelFormatARB during the creation of the user's first - // GLContext. However, this and other routines' function pointers - // aren't loaded by the driver until the first OpenGL context is - // created. The standard way of working around this chicken-and-egg - // problem is to create a dummy window, show it, send it a paint - // message, create an OpenGL context, fetch the needed function - // pointers, and then destroy the dummy window and context. It turns - // out that ATI cards need the dummy context to be current while - // wglChoosePixelFormatARB is called, so we cache the extension - // strings the dummy context reports as being available. - private static Map/*<GraphicsDevice, GL>*/ dummyContextMap = new HashMap(); - private static Map/*<GraphicsDevice, String>*/ dummyExtensionsMap = new HashMap(); - private static Set/*<GraphicsDevice >*/ pendingContextSet = new HashSet(); - public WindowsGLContextFactory() { AccessController.doPrivileged( new PrivilegedAction() { public Object run() { @@ -159,6 +142,79 @@ public class WindowsGLContextFactory extends GLContextFactory { return new WindowsOffscreenGLDrawable(capabilities, chooser); } + private boolean pbufferSupportInitialized = false; + private boolean canCreateGLPbuffer = false; + public boolean canCreateGLPbuffer(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { + if (!pbufferSupportInitialized) { + Runnable r = new Runnable() { + public void run() { + WindowsDummyGLDrawable dummyDrawable = new WindowsDummyGLDrawable(); + GLContext dummyContext = dummyDrawable.createContext(null); + if (dummyContext != null) { + GLContext lastContext = GLContext.getCurrent(); + if (lastContext != null) { + lastContext.release(); + } + dummyContext.makeCurrent(); + GL dummyGL = dummyContext.getGL(); + canCreateGLPbuffer = dummyGL.isExtensionAvailable("GL_ARB_pbuffer"); + pbufferSupportInitialized = true; + dummyContext.release(); + dummyContext.destroy(); + dummyDrawable.destroy(); + if (lastContext != null) { + lastContext.makeCurrent(); + } + } + } + }; + maybeDoSingleThreadedWorkaround(r); + } + return canCreateGLPbuffer; + } + + public GLPbuffer createGLPbuffer(final GLCapabilities capabilities, + final int initialWidth, + final int initialHeight, + final GLContext shareWith) { + if (!canCreateGLPbuffer) { + throw new GLException("Pbuffer support not available with current graphics card"); + } + final List returnList = new ArrayList(); + Runnable r = new Runnable() { + public void run() { + WindowsDummyGLDrawable dummyDrawable = new WindowsDummyGLDrawable(); + GLContext dummyContext = dummyDrawable.createContext(null); + GLContext lastContext = GLContext.getCurrent(); + if (lastContext != null) { + lastContext.release(); + } + dummyContext.makeCurrent(); + GL dummyGL = dummyContext.getGL(); + try { + WindowsPbufferGLDrawable pbufferDrawable = new WindowsPbufferGLDrawable(capabilities, + initialWidth, + initialHeight, + dummyDrawable, + dummyGL); + GLPbufferImpl pbuffer = new GLPbufferImpl(pbufferDrawable, shareWith); + returnList.add(pbuffer); + dummyContext.release(); + dummyContext.destroy(); + dummyDrawable.destroy(); + } finally { + if (lastContext != null) { + lastContext.makeCurrent(); + } + } + } + }; + maybeDoSingleThreadedWorkaround(r); + return (GLPbuffer) returnList.get(0); + } + static String wglGetLastError() { int err = WGL.GetLastError(); String detail = null; @@ -172,4 +228,18 @@ public class WindowsGLContextFactory extends GLContextFactory { } return detail; } + + private void maybeDoSingleThreadedWorkaround(Runnable action) { + if (SingleThreadedWorkaround.doWorkaround() && !EventQueue.isDispatchThread()) { + try { + EventQueue.invokeAndWait(action); + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (InterruptedException e) { + throw new GLException(e); + } + } else { + action.run(); + } + } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java index 15de59df8..b3ed2a03c 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java @@ -56,15 +56,21 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { } public boolean canCreatePbufferContext() { + return false; + /* return haveWGLARBPbuffer(); + */ } public GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, int initialWidth, int initialHeight) { + throw new GLException("No longer supported"); + /* WindowsPbufferGLDrawable buf = new WindowsPbufferGLDrawable(capabilities, initialWidth, initialHeight); pbuffersToInstantiate.add(buf); return buf; + */ } protected int makeCurrentImpl() throws GLException { @@ -86,6 +92,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { } } int ret = super.makeCurrentImpl(); + /* if ((ret == CONTEXT_CURRENT) || (ret == CONTEXT_CURRENT_NEW)) { // Instantiate any pending pbuffers @@ -104,6 +111,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { } } } + */ return ret; } catch (RuntimeException e) { try { diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java index 98956f259..80d6d2a02 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java @@ -43,6 +43,8 @@ import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class WindowsPbufferGLContext extends WindowsGLContext { + private static final boolean DEBUG = Debug.debug("WindowsPbufferGLContext"); + // State for render-to-texture and render-to-texture-rectangle support private WindowsPbufferGLDrawable drawable; private boolean rtt; // render-to-texture? @@ -98,7 +100,7 @@ public class WindowsPbufferGLContext extends WindowsGLContext { int res = super.makeCurrentImpl(); if (DEBUG && VERBOSE) { - System.err.println("super.makeCurrent() = " + res); + System.err.println("WindowsPbufferGLContext: super.makeCurrentImpl() = " + res); } if (res == CONTEXT_CURRENT_NEW) { GLCapabilities capabilities = drawable.getCapabilities(); diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java index 6917b281d..d91feb27c 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java +++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java @@ -54,7 +54,11 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { private int floatMode; - public WindowsPbufferGLDrawable(GLCapabilities capabilities, int initialWidth, int initialHeight) { + public WindowsPbufferGLDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight, + WindowsGLDrawable dummyDrawable, + GL gl) { super(null, capabilities, null); this.initWidth = initialWidth; this.initHeight = initialHeight; @@ -69,6 +73,8 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { (capabilities.getOffscreenRenderToTextureRectangle() ? " [rect]" : "") + (capabilities.getOffscreenFloatingPointBuffers() ? " [float]" : "")); } + + createPbuffer(dummyDrawable.getHDC(), gl); } public GLContext createContext(GLContext shareWith) { @@ -106,7 +112,36 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { return height; } - public void createPbuffer(GL gl, long parentHdc) { + public GLCapabilities getCapabilities() { + return capabilities; + } + + public long getPbuffer() { + return buffer; + } + + public int getFloatingPointMode() { + return floatMode; + } + + public void swapBuffers() throws GLException { + // FIXME: this doesn't make sense any more because we don't have + // access to our OpenGL context here + /* + // FIXME: do we need to do anything if the pbuffer is double-buffered? + // For now, just grab the pixels for the render-to-texture support. + if (rtt && !hasRTT) { + if (DEBUG) { + System.err.println("Copying pbuffer data to GL_TEXTURE_2D state"); + } + + GL gl = getGL(); + gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, width, height); + } + */ + } + + private void createPbuffer(long parentHdc, GL gl) { int[] iattributes = new int [2*MAX_ATTRIBS]; float[] fattributes = new float[2*MAX_ATTRIBS]; int nfattribs = 0; @@ -358,35 +393,6 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { } } - public GLCapabilities getCapabilities() { - return capabilities; - } - - public long getPbuffer() { - return buffer; - } - - public int getFloatingPointMode() { - return floatMode; - } - - public void swapBuffers() throws GLException { - // FIXME: this doesn't make sense any more because we don't have - // access to our OpenGL context here - /* - // FIXME: do we need to do anything if the pbuffer is double-buffered? - // For now, just grab the pixels for the render-to-texture support. - if (rtt && !hasRTT) { - if (DEBUG) { - System.err.println("Copying pbuffer data to GL_TEXTURE_2D state"); - } - - GL gl = getGL(); - gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, width, height); - } - */ - } - private static String wglGetLastError() { return WindowsGLContextFactory.wglGetLastError(); } diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java index f00e75ce2..66520ada3 100644 --- a/src/net/java/games/jogl/impl/x11/X11GLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java @@ -171,12 +171,12 @@ public abstract class X11GLContext extends GLContextImpl { lockAWT(); if (context != 0) { GLX.glXDestroyContext(mostRecentDisplay, context); - context = 0; - mostRecentDisplay = 0; - GLContextShareSet.contextDestroyed(this); if (DEBUG) { System.err.println("!!! Destroyed OpenGL context " + context); } + context = 0; + mostRecentDisplay = 0; + GLContextShareSet.contextDestroyed(this); } unlockAWT(); } |