diff options
Diffstat (limited to 'src/net/java/games/jogl/impl/x11')
9 files changed, 898 insertions, 588 deletions
diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java index 7077c855e..a43def0b8 100644 --- a/src/net/java/games/jogl/impl/x11/X11GLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java @@ -47,9 +47,7 @@ import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public abstract class X11GLContext extends GLContextImpl { - protected long display; - protected long drawable; - protected long visualID; + protected X11GLDrawable drawable; protected long context; private boolean glXQueryExtensionsStringInitialized; private boolean glXQueryExtensionsStringAvailable; @@ -84,11 +82,10 @@ public abstract class X11GLContext extends GLContextImpl { }); } - public X11GLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public X11GLContext(X11GLDrawable drawable, GLContext shareWith) { - super(component, capabilities, chooser, shareWith); + super(shareWith); + this.drawable = drawable; } protected GL createGL() @@ -108,16 +105,6 @@ public abstract class X11GLContext extends GLContextImpl { return glExtensionName; } - protected abstract boolean isOffscreen(); - - public int getOffscreenContextWidth() { - throw new GLException("Should not call this"); - } - - public int getOffscreenContextHeight() { - throw new GLException("Should not call this"); - } - public int getOffscreenContextPixelDataType() { throw new GLException("Should not call this"); } @@ -126,18 +113,32 @@ public abstract class X11GLContext extends GLContextImpl { public abstract boolean offscreenImageNeedsVerticalFlip(); - /** - * Creates and initializes an appropriate OpenGl context. Should only be - * called by {@link makeCurrentImpl()}. + /** Helper routine which usually just turns around and calls + * createContext (except for pbuffers, which use a different context + * creation mechanism). Should only be called by {@link + * makeCurrentImpl()}. */ protected abstract void create(); - - public boolean isExtensionAvailable(String glExtensionName) { - if (glExtensionName.equals("GL_ARB_pbuffer") || - glExtensionName.equals("GL_ARB_pixel_format")) { - return isGLX13; + + /** + * Creates and initializes an appropriate OpenGL context. Should only be + * called by {@link create()}. + */ + protected void createContext(boolean onscreen) { + XVisualInfo vis = drawable.chooseVisual(onscreen); + X11GLContext other = (X11GLContext) GLContextShareSet.getShareContext(this); + long share = 0; + if (other != null) { + share = other.getContext(); + if (share == 0) { + throw new GLException("GLContextShareSet returned an invalid OpenGL context"); + } } - return super.isExtensionAvailable(glExtensionName); + context = GLX.glXCreateContext(drawable.getDisplay(), vis, share, onscreen); + if (context == 0) { + throw new GLException("Unable to create OpenGL context"); + } + GLContextShareSet.contextCreated(this); } protected int makeCurrentImpl() throws GLException { @@ -145,19 +146,20 @@ public abstract class X11GLContext extends GLContextImpl { if (context == 0) { create(); if (DEBUG) { - System.err.println("!!! Created GL context for " + getClass().getName()); + System.err.println(getThreadName() + ": !!! Created GL context for " + getClass().getName()); } created = true; } - if (drawable == 0) { - throw new GLException("Unable to make context current; drawable was null"); - } - // 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) - if (!GLX.glXMakeCurrent(display, (int) drawable, context)) { + if (!GLX.glXMakeCurrent(drawable.getDisplay(), drawable.getDrawable(), context)) { throw new GLException("Error making context current"); + } else { + mostRecentDisplay = drawable.getDisplay(); + if (DEBUG && VERBOSE) { + System.err.println(getThreadName() + ": glXMakeCurrent(display " + toHexString(drawable.getDisplay()) + + ", drawable " + toHexString(drawable.getDrawable()) + + ", context " + toHexString(context) + ") succeeded"); + } } if (created) { @@ -168,7 +170,7 @@ public abstract class X11GLContext extends GLContextImpl { } protected void releaseImpl() throws GLException { - if (!GLX.glXMakeCurrent(display, 0, 0)) { + if (!GLX.glXMakeCurrent(drawable.getDisplay(), 0, 0)) { throw new GLException("Error freeing OpenGL context"); } } @@ -177,16 +179,16 @@ 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; } unlockAWT(); } - public abstract void swapBuffers() throws GLException; - protected long dynamicLookupFunction(String glFuncName) { long res = 0; if (!isLinuxAMD64) { @@ -216,12 +218,12 @@ public abstract class X11GLContext extends GLContextImpl { // Figure out whether we are running GLX version 1.3 or above and // therefore have pbuffer support - if (display == 0) { + if (drawable.getDisplay() == 0) { throw new GLException("Expected non-null DISPLAY for querying GLX version"); } int[] major = new int[1]; int[] minor = new int[1]; - if (!GLX.glXQueryVersion(display, major, 0, minor, 0)) { + if (!GLX.glXQueryVersion(drawable.getDisplay(), major, 0, minor, 0)) { throw new GLException("glXQueryVersion failed"); } if (DEBUG) { @@ -253,7 +255,7 @@ public abstract class X11GLContext extends GLContextImpl { } public synchronized String getPlatformExtensionsString() { - if (display == 0) { + if (drawable.getDisplay() == 0) { throw new GLException("Context not current"); } if (!glXQueryExtensionsStringInitialized) { @@ -263,7 +265,7 @@ public abstract class X11GLContext extends GLContextImpl { if (glXQueryExtensionsStringAvailable) { lockAWT(); try { - String ret = GLX.glXQueryExtensionsString(display, GLX.DefaultScreen(display)); + String ret = GLX.glXQueryExtensionsString(drawable.getDisplay(), GLX.DefaultScreen(drawable.getDisplay())); if (DEBUG) { System.err.println("!!! GLX extensions: " + ret); } @@ -292,97 +294,17 @@ public abstract class X11GLContext extends GLContextImpl { return available; } - //---------------------------------------------------------------------- - // Internals only below this point - // - - protected JAWT getJAWT() { - return X11GLContextFactory.getJAWT(); - } - - protected XVisualInfo chooseVisual() { - if (!isOffscreen()) { - // The visual has already been chosen by the time we get here; - // it's specified by the GraphicsConfiguration of the - // GLCanvas. Fortunately, the JAWT supplies the visual ID for - // the component in a portable fashion, so all we have to do is - // use XGetVisualInfo with a VisualIDMask to get the - // corresponding XVisualInfo to pass into glXChooseVisual. - int[] count = new int[1]; - XVisualInfo template = new XVisualInfo(); - // FIXME: probably not 64-bit clean - template.visualid((int) visualID); - XVisualInfo[] infos = GLX.XGetVisualInfo(display, GLX.VisualIDMask, template, count, 0); - if (infos == null || infos.length == 0) { - throw new GLException("Error while getting XVisualInfo for visual ID " + visualID); - } - // FIXME: the storage for the infos array is leaked (should - // clean it up somehow when we're done with the visual we're - // returning) - return infos[0]; - } else { - // It isn't clear to me whether we need this much code to handle - // the offscreen case, where we're creating a pixmap into which - // to render...this is what we (incorrectly) used to do for the - // onscreen case - - int screen = 0; // FIXME: provide way to specify this? - XVisualInfo vis = null; - int[] count = new int[1]; - XVisualInfo template = new XVisualInfo(); - template.screen(screen); - XVisualInfo[] infos = GLX.XGetVisualInfo(display, GLX.VisualScreenMask, template, count, 0); - if (infos == null) { - throw new GLException("Error while enumerating available XVisualInfos"); - } - GLCapabilities[] caps = new GLCapabilities[infos.length]; - for (int i = 0; i < infos.length; i++) { - caps[i] = X11GLContextFactory.xvi2GLCapabilities(display, infos[i]); - } - int chosen = chooser.chooseCapabilities(capabilities, caps, -1); - if (chosen < 0 || chosen >= caps.length) { - throw new GLException("GLCapabilitiesChooser specified invalid index (expected 0.." + (caps.length - 1) + ")"); - } - if (DEBUG) { - System.err.println("Chosen visual (" + chosen + "):"); - System.err.println(caps[chosen]); - } - vis = infos[chosen]; - if (vis == null) { - throw new GLException("GLCapabilitiesChooser chose an invalid visual"); - } - // FIXME: the storage for the infos array is leaked (should - // clean it up somehow when we're done with the visual we're - // returning) - - return vis; - } - } - - protected long createContext(XVisualInfo vis, boolean onscreen) { - X11GLContext other = (X11GLContext) GLContextShareSet.getShareContext(this); - long share = 0; - if (other != null) { - share = other.getContext(); - if (share == 0) { - throw new GLException("GLContextShareSet returned an invalid OpenGL context"); - } - } - long res = GLX.glXCreateContext(display, vis, share, onscreen); - if (res != 0) { - GLContextShareSet.contextCreated(this); + public boolean isExtensionAvailable(String glExtensionName) { + if (glExtensionName.equals("GL_ARB_pbuffer") || + glExtensionName.equals("GL_ARB_pixel_format")) { + return isGLX13; } - return res; + return super.isExtensionAvailable(glExtensionName); } - // Helper routine for the overridden create() to call - protected void chooseVisualAndCreateContext(boolean onscreen) { - XVisualInfo vis = chooseVisual(); - context = createContext(vis, onscreen); - if (context == 0) { - throw new GLException("Unable to create OpenGL context"); - } - } + //---------------------------------------------------------------------- + // Internals only below this point + // protected long getContext() { return context; diff --git a/src/net/java/games/jogl/impl/x11/X11GLContextFactory.java b/src/net/java/games/jogl/impl/x11/X11GLContextFactory.java index 3be11c002..78d03a28a 100644 --- a/src/net/java/games/jogl/impl/x11/X11GLContextFactory.java +++ b/src/net/java/games/jogl/impl/x11/X11GLContextFactory.java @@ -119,15 +119,22 @@ public class X11GLContextFactory extends GLContextFactory { return null; } - public GLContext createGLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, - GLContext shareWith) { - if (component != null) { - return new X11OnscreenGLContext(component, capabilities, chooser, shareWith); - } else { - return new X11OffscreenGLContext(capabilities, chooser, shareWith); + public GLDrawable getGLDrawable(Object target, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + if (target == null) { + throw new IllegalArgumentException("Null target"); } + if (!(target instanceof Component)) { + throw new IllegalArgumentException("GLDrawables not supported for objects of type " + + target.getClass().getName() + " (only Components are supported in this implementation)"); + } + return new X11OnscreenGLDrawable((Component) target); + } + + public GLDrawableImpl createOffscreenDrawable(GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + return new X11OffscreenGLDrawable(capabilities, chooser); } public static GLCapabilities xvi2GLCapabilities(long display, XVisualInfo info) { diff --git a/src/net/java/games/jogl/impl/x11/X11GLDrawable.java b/src/net/java/games/jogl/impl/x11/X11GLDrawable.java new file mode 100644 index 000000000..32098ab43 --- /dev/null +++ b/src/net/java/games/jogl/impl/x11/X11GLDrawable.java @@ -0,0 +1,172 @@ +/* + * 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.x11; + +import java.awt.Component; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public abstract class X11GLDrawable extends GLDrawableImpl { + protected static final boolean DEBUG = Debug.debug("X11GLDrawable"); + + protected long display; + protected long drawable; + protected long visualID; + protected Component component; + protected GLCapabilities capabilities; + protected GLCapabilitiesChooser chooser; + + public X11GLDrawable(Component component, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + this.component = component; + this.capabilities = (capabilities == null) ? null : + ((GLCapabilities) capabilities.clone()); + this.chooser = chooser; + } + + public void setRealized(boolean val) { + throw new GLException("Should not call this (should only be called for onscreen GLDrawables)"); + } + + public void destroy() { + throw new GLException("Should not call this (should only be called for offscreen GLDrawables)"); + } + + public void swapBuffers() throws GLException { + } + + public long getDisplay() { + return display; + } + + public long getDrawable() { + return drawable; + } + + //--------------------------------------------------------------------------- + // Internals only below this point + // + + protected XVisualInfo chooseVisual(boolean onscreen) { + if (display == 0) { + throw new GLException("null display"); + } + + // FIXME + if (onscreen) { + // The visual has already been chosen by the time we get here; + // it's specified by the GraphicsConfiguration of the + // GLCanvas. Fortunately, the JAWT supplies the visual ID for + // the component in a portable fashion, so all we have to do is + // use XGetVisualInfo with a VisualIDMask to get the + // corresponding XVisualInfo to pass into glXChooseVisual. + int[] count = new int[1]; + XVisualInfo template = new XVisualInfo(); + // FIXME: probably not 64-bit clean + template.visualid((int) visualID); + lockAWT(); + XVisualInfo[] infos = GLX.XGetVisualInfo(display, GLX.VisualIDMask, template, count, 0); + unlockAWT(); + if (infos == null || infos.length == 0) { + throw new GLException("Error while getting XVisualInfo for visual ID " + visualID); + } + // FIXME: the storage for the infos array is leaked (should + // clean it up somehow when we're done with the visual we're + // returning) + return infos[0]; + } else { + // It isn't clear to me whether we need this much code to handle + // the offscreen case, where we're creating a pixmap into which + // to render...this is what we (incorrectly) used to do for the + // onscreen case + + int screen = 0; // FIXME: provide way to specify this? + XVisualInfo vis = null; + int[] count = new int[1]; + XVisualInfo template = new XVisualInfo(); + template.screen(screen); + XVisualInfo[] infos = null; + GLCapabilities[] caps = null; + lockAWT(); + try { + infos = GLX.XGetVisualInfo(display, GLX.VisualScreenMask, template, count, 0); + if (infos == null) { + throw new GLException("Error while enumerating available XVisualInfos"); + } + caps = new GLCapabilities[infos.length]; + for (int i = 0; i < infos.length; i++) { + caps[i] = X11GLContextFactory.xvi2GLCapabilities(display, infos[i]); + } + } finally { + unlockAWT(); + } + int chosen = chooser.chooseCapabilities(capabilities, caps, -1); + if (chosen < 0 || chosen >= caps.length) { + throw new GLException("GLCapabilitiesChooser specified invalid index (expected 0.." + (caps.length - 1) + ")"); + } + if (DEBUG) { + System.err.println("Chosen visual (" + chosen + "):"); + System.err.println(caps[chosen]); + } + vis = infos[chosen]; + if (vis == null) { + throw new GLException("GLCapabilitiesChooser chose an invalid visual"); + } + // FIXME: the storage for the infos array is leaked (should + // clean it up somehow when we're done with the visual we're + // returning) + + return vis; + } + } + + + // These synchronization primitives prevent the AWT from making + // requests from the X server asynchronously to this code. + protected void lockAWT() { + X11GLContextFactory.lockAWT(); + } + + protected void unlockAWT() { + X11GLContextFactory.unlockAWT(); + } +} diff --git a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java index c493d3380..4397c72d8 100644 --- a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java @@ -39,46 +39,24 @@ package net.java.games.jogl.impl.x11; -import java.awt.image.BufferedImage; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class X11OffscreenGLContext extends X11GLContext { - private long pixmap; - private boolean isDoubleBuffered; - // Width and height of the underlying bitmap - private int width; - private int height; + private X11OffscreenGLDrawable drawable; - public X11OffscreenGLContext(GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public X11OffscreenGLContext(X11OffscreenGLDrawable drawable, GLContext shareWith) { - super(null, capabilities, chooser, shareWith); - } - - protected GL createGL() - { - return new X11GLImpl(this); - } - - protected boolean isOffscreen() { - return true; - } - - public int getOffscreenContextWidth() { - return width; - } - - public int getOffscreenContextHeight() { - return height; + super(drawable, shareWith); + this.drawable = drawable; } public int getOffscreenContextPixelDataType() { - return GL.GL_UNSIGNED_BYTE; + return GL.GL_UNSIGNED_BYTE; } public int getOffscreenContextReadBuffer() { - if (isDoubleBuffered) { + if (drawable.isDoubleBuffered()) { return GL.GL_BACK; } return GL.GL_FRONT; @@ -95,9 +73,9 @@ public class X11OffscreenGLContext extends X11GLContext { return false; } - public GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { throw new GLException("Not supported"); } @@ -109,67 +87,7 @@ public class X11OffscreenGLContext extends X11GLContext { throw new GLException("Should not call this"); } - protected int makeCurrentImpl() throws GLException { - display = X11GLContextFactory.getDisplayConnection(); - if (pendingOffscreenResize) { - if (pendingOffscreenWidth != width || pendingOffscreenHeight != height) { - if (context != 0) { - destroy(); - } - width = pendingOffscreenWidth; - height = pendingOffscreenHeight; - pendingOffscreenResize = false; - } - } - mostRecentDisplay = display; - return super.makeCurrentImpl(); - } - - public void swapBuffers() throws GLException { - } - - protected void releaseImpl() throws GLException { - try { - super.releaseImpl(); - } finally { - display = 0; - } - } - protected void create() { - XVisualInfo vis = chooseVisual(); - int bitsPerPixel = vis.depth(); - - if (display == 0) { - throw new GLException("No active display"); - } - int screen = GLX.DefaultScreen(display); - pixmap = GLX.XCreatePixmap(display, (int) GLX.RootWindow(display, screen), width, height, bitsPerPixel); - if (pixmap == 0) { - throw new GLException("XCreatePixmap failed"); - } - drawable = GLX.glXCreateGLXPixmap(display, vis, pixmap); - if (drawable == 0) { - throw new GLException("glXCreateGLXPixmap failed"); - } - context = createContext(vis, false); - if (context == 0) { - throw new GLException("Unable to create OpenGL context"); - } - isDoubleBuffered = (X11GLContextFactory.glXGetConfig(display, vis, GLX.GLX_DOUBLEBUFFER, new int[1], 0) != 0); - } - - protected void destroyImpl() { - if (context != 0) { - super.destroyImpl(); - // Must destroy OpenGL context, pixmap and GLXPixmap - GLX.glXDestroyContext(display, context); - GLX.glXDestroyGLXPixmap(display, (int) drawable); - GLX.XFreePixmap(display, pixmap); - context = 0; - drawable = 0; - pixmap = 0; - GLContextShareSet.contextDestroyed(this); - } + createContext(false); } } diff --git a/src/net/java/games/jogl/impl/x11/X11OffscreenGLDrawable.java b/src/net/java/games/jogl/impl/x11/X11OffscreenGLDrawable.java new file mode 100644 index 000000000..7b60612df --- /dev/null +++ b/src/net/java/games/jogl/impl/x11/X11OffscreenGLDrawable.java @@ -0,0 +1,143 @@ +/* + * 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.x11; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class X11OffscreenGLDrawable extends X11GLDrawable { + private long pixmap; + private boolean isDoubleBuffered; + // Width and height of the underlying bitmap + private int width; + private int height; + + public X11OffscreenGLDrawable(GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + super(null, capabilities, chooser); + } + + public GLContext createContext(GLContext shareWith) { + return new X11OffscreenGLContext(this, shareWith); + } + + public void setSize(int newWidth, int newHeight) { + width = newWidth; + height = newHeight; + if (pixmap != 0) { + destroy(); + } + create(); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + private void create() { + display = X11GLContextFactory.getDisplayConnection(); + XVisualInfo vis = chooseVisual(false); + int bitsPerPixel = vis.depth(); + + lockAWT(); + try { + int screen = GLX.DefaultScreen(display); + pixmap = GLX.XCreatePixmap(display, (int) GLX.RootWindow(display, screen), width, height, bitsPerPixel); + if (pixmap == 0) { + throw new GLException("XCreatePixmap failed"); + } + drawable = GLX.glXCreateGLXPixmap(display, vis, pixmap); + if (drawable == 0) { + GLX.XFreePixmap(display, pixmap); + pixmap = 0; + throw new GLException("glXCreateGLXPixmap failed"); + } + isDoubleBuffered = (X11GLContextFactory.glXGetConfig(display, vis, GLX.GLX_DOUBLEBUFFER, new int[1], 0) != 0); + if (DEBUG) { + System.err.println("Created pixmap " + toHexString(pixmap) + + ", GLXPixmap " + toHexString(drawable) + + ", display " + toHexString(display)); + } + } finally { + unlockAWT(); + } + } + + public void destroy() { + if (pixmap != 0) { + if (DEBUG) { + System.err.println("Destroying pixmap " + toHexString(pixmap) + + ", GLXPixmap " + toHexString(drawable) + + ", display " + toHexString(display)); + } + + // Must destroy pixmap and GLXPixmap + lockAWT(); + + if (DEBUG) { + long cur = GLX.glXGetCurrentContext(); + if (cur != 0) { + System.err.println("WARNING: found context " + toHexString(cur) + " current during pixmap destruction"); + } + } + + // FIXME: workaround for crashes on NVidia hardware when + // destroying pixmap (no context is current at the point of the + // crash, at least from the point of view of + // glXGetCurrentContext) + GLX.glXMakeCurrent(display, 0, 0); + + GLX.glXDestroyGLXPixmap(display, drawable); + GLX.XFreePixmap(display, pixmap); + unlockAWT(); + drawable = 0; + pixmap = 0; + display = 0; + } + } + + public boolean isDoubleBuffered() { + return isDoubleBuffered; + } +} diff --git a/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java b/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java index 5a6fe23bb..1828f8378 100644 --- a/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11OnscreenGLContext.java @@ -39,47 +39,20 @@ package net.java.games.jogl.impl.x11; -import java.awt.Component; import java.util.*; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class X11OnscreenGLContext extends X11GLContext { - // Variables for lockSurface/unlockSurface - private JAWT_DrawingSurface ds; - 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; - + protected X11OnscreenGLDrawable drawable; // Variables for pbuffer support List pbuffersToInstantiate = new ArrayList(); - public X11OnscreenGLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public X11OnscreenGLContext(X11OnscreenGLDrawable drawable, GLContext shareWith) { - super(component, capabilities, chooser, shareWith); - } - - protected GL createGL() - { - return new X11GLImpl(this); - } - - protected boolean isOffscreen() { - return false; + super(drawable, shareWith); + this.drawable = drawable; } public int getOffscreenContextReadBuffer() { @@ -91,17 +64,15 @@ public class X11OnscreenGLContext extends X11GLContext { } public boolean canCreatePbufferContext() { - // FIXME: should we gate this on GLX 1.3 being available? - return true; + return isExtensionAvailable("GL_ARB_pbuffer"); } - public GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { - X11PbufferGLContext ctx = new X11PbufferGLContext(capabilities, initialWidth, initialHeight); - ctx.setSynchronized(true); - pbuffersToInstantiate.add(ctx); - return ctx; + public GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { + X11PbufferGLDrawable buf = new X11PbufferGLDrawable(capabilities, initialWidth, initialHeight); + pbuffersToInstantiate.add(buf); + return buf; } public void bindPbufferToTexture() { @@ -112,39 +83,39 @@ public class X11OnscreenGLContext extends X11GLContext { throw new GLException("Should not call this"); } - public void setSwapInterval(int interval) { - GL gl = getGL(); - if (gl.isExtensionAvailable("GLX_SGI_swap_control")) { - gl.glXSwapIntervalSGI(interval); - } - } - - public void setRealized() { - realized = true; - } - protected int makeCurrentImpl() throws GLException { try { - if (!realized) { + int lockRes = drawable.lockSurface(); + if (lockRes == X11OnscreenGLDrawable.LOCK_SURFACE_NOT_READY) { return CONTEXT_NOT_CURRENT; } - if (!lockSurface()) { - return CONTEXT_NOT_CURRENT; + if (lockRes == X11OnscreenGLDrawable.LOCK_SURFACE_CHANGED) { + if (context != 0) { + GLX.glXDestroyContext(mostRecentDisplay, context); + GLContextShareSet.contextDestroyed(this); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + toHexString(context) + " due to JAWT_LOCK_SURFACE_CHANGED"); + } + context = 0; + } } int ret = super.makeCurrentImpl(); if ((ret == CONTEXT_CURRENT) || (ret == CONTEXT_CURRENT_NEW)) { // Instantiate any pending pbuffers while (!pbuffersToInstantiate.isEmpty()) { - X11PbufferGLContext ctx = - (X11PbufferGLContext) pbuffersToInstantiate.remove(pbuffersToInstantiate.size() - 1); - ctx.createPbuffer(display, context, getGL()); + X11PbufferGLDrawable buf = + (X11PbufferGLDrawable) pbuffersToInstantiate.remove(pbuffersToInstantiate.size() - 1); + buf.createPbuffer(getGL(), drawable.getDisplay()); + if (DEBUG) { + System.err.println(getThreadName() + ": created pbuffer " + buf); + } } } return ret; } catch (RuntimeException e) { try { - unlockSurface(); + drawable.unlockSurface(); } catch (Exception e2) { // do nothing if unlockSurface throws } @@ -156,88 +127,11 @@ public class X11OnscreenGLContext extends X11GLContext { try { super.releaseImpl(); } finally { - unlockSurface(); - } - } - - 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) - GLX.glXSwapBuffers(display, (int) drawable); - } - - private boolean lockSurface() throws GLException { - if (drawable != 0) { - throw new GLException("Surface already locked"); - } - ds = getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - return false; + drawable.unlockSurface(); } - int res = ds.Lock(); - if ((res & JAWTFactory.JAWT_LOCK_ERROR) != 0) { - throw new GLException("Unable to lock surface"); - } - // See whether the surface changed and if so destroy the old - // OpenGL context so it will be recreated - if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { - if (context != 0) { - GLX.glXDestroyContext(display, context); - context = 0; - } - } - dsi = ds.GetDrawingSurfaceInfo(); - if (dsi == null) { - // Widget not yet realized - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - return false; - } - x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); - display = x11dsi.display(); - drawable = x11dsi.drawable(); - visualID = x11dsi.visualID(); - if (display == 0 || drawable == 0) { - // Widget not yet realized - ds.FreeDrawingSurfaceInfo(dsi); - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - dsi = null; - x11dsi = null; - display = 0; - drawable = 0; - visualID = 0; - return false; - } - mostRecentDisplay = display; - return true; - } - - private void unlockSurface() { - if (drawable == 0) { - throw new GLException("Surface already unlocked"); - } - ds.FreeDrawingSurfaceInfo(dsi); - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - dsi = null; - x11dsi = null; - display = 0; - drawable = 0; - visualID = 0; } protected void create() { - chooseVisualAndCreateContext(true); - } + createContext(true); + } } diff --git a/src/net/java/games/jogl/impl/x11/X11OnscreenGLDrawable.java b/src/net/java/games/jogl/impl/x11/X11OnscreenGLDrawable.java new file mode 100644 index 000000000..9b9705122 --- /dev/null +++ b/src/net/java/games/jogl/impl/x11/X11OnscreenGLDrawable.java @@ -0,0 +1,174 @@ +/* + * 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.x11; + +import java.awt.Component; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class X11OnscreenGLDrawable extends X11GLDrawable { + public static final int LOCK_SURFACE_NOT_READY = 1; + public static final int LOCK_SURFACE_CHANGED = 2; + public static final int LOCK_SUCCESS = 3; + + // Variables for lockSurface/unlockSurface + private JAWT_DrawingSurface ds; + 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; + + public X11OnscreenGLDrawable(Component component) { + super(component, null, null); + } + + public GLContext createContext(GLContext shareWith) { + return new X11OnscreenGLContext(this, shareWith); + } + + public void setRealized(boolean realized) { + this.realized = realized; + } + + public void setSize(int width, int height) { + component.setSize(width, height); + } + + public int getWidth() { + return component.getWidth(); + } + + public int getHeight() { + return component.getHeight(); + } + + public void swapBuffers() throws GLException { + lockAWT(); + GLX.glXSwapBuffers(display, drawable); + unlockAWT(); + } + + public int lockSurface() throws GLException { + if (!realized) { + return LOCK_SURFACE_NOT_READY; + } + if (drawable != 0) { + throw new GLException("Surface already locked"); + } + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + return LOCK_SURFACE_NOT_READY; + } + int res = ds.Lock(); + if ((res & JAWTFactory.JAWT_LOCK_ERROR) != 0) { + throw new GLException("Unable to lock surface"); + } + // See whether the surface changed and if so destroy the old + // OpenGL context so it will be recreated (NOTE: removeNotify + // should handle this case, but it may be possible that race + // conditions can cause this code to be triggered -- should test + // more) + int ret = LOCK_SUCCESS; + if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { + ret = LOCK_SURFACE_CHANGED; + } + dsi = ds.GetDrawingSurfaceInfo(); + if (dsi == null) { + // Widget not yet realized + ds.Unlock(); + getJAWT().FreeDrawingSurface(ds); + ds = null; + return LOCK_SURFACE_NOT_READY; + } + x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); + display = x11dsi.display(); + drawable = x11dsi.drawable(); + visualID = x11dsi.visualID(); + if (display == 0 || drawable == 0) { + // Widget not yet realized + ds.FreeDrawingSurfaceInfo(dsi); + ds.Unlock(); + getJAWT().FreeDrawingSurface(ds); + ds = null; + dsi = null; + x11dsi = null; + display = 0; + drawable = 0; + visualID = 0; + return LOCK_SURFACE_NOT_READY; + } + return ret; + } + + public void unlockSurface() { + if (drawable == 0) { + throw new GLException("Surface already unlocked"); + } + ds.FreeDrawingSurfaceInfo(dsi); + ds.Unlock(); + getJAWT().FreeDrawingSurface(ds); + ds = null; + dsi = null; + x11dsi = null; + display = 0; + drawable = 0; + visualID = 0; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private JAWT getJAWT() { + return X11GLContextFactory.getJAWT(); + } +} diff --git a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java index 30a60ba61..bebbdb91c 100644 --- a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java +++ b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java @@ -43,40 +43,21 @@ import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class X11PbufferGLContext extends X11GLContext { - private static final boolean DEBUG = Debug.debug("X11PbufferGLContext"); + private X11PbufferGLDrawable drawable; - private int initWidth; - private int initHeight; - - private long buffer; // GLXPbuffer - private GLXFBConfig fbConfig; - private int width; - private int height; - - // FIXME: kept around because we create the OpenGL context lazily to - // better integrate with the X11GLContext framework - private long parentContext; - - private static final int MAX_PFORMATS = 256; - private static final int MAX_ATTRIBS = 256; - - public X11PbufferGLContext(GLCapabilities capabilities, int initialWidth, int initialHeight) { - super(null, capabilities, null, null); - this.initWidth = initialWidth; - this.initHeight = initialHeight; - if (initWidth <= 0 || initHeight <= 0) { - throw new GLException("Initial width and height of pbuffer must be positive (were (" + - initWidth + ", " + initHeight + "))"); - } + public X11PbufferGLContext(X11PbufferGLDrawable drawable, + GLContext shareWith) { + super(drawable, shareWith); + this.drawable = drawable; } public boolean canCreatePbufferContext() { return false; } - public GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { + public GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { throw new GLException("Not supported"); } @@ -90,169 +71,40 @@ public class X11PbufferGLContext extends X11GLContext { throw new GLException("Not yet implemented"); } - public void createPbuffer(long display, long parentContext, GL gl) { - if (display == 0) { - throw new GLException("Null display"); - } - - if (parentContext == 0) { - throw new GLException("Null parentContext"); - } - - if (capabilities.getOffscreenRenderToTexture()) { - throw new GLException("Render-to-texture pbuffers not supported yet on X11"); - } - - if (capabilities.getOffscreenRenderToTextureRectangle()) { - throw new GLException("Render-to-texture-rectangle pbuffers not supported yet on X11"); - } - - int[] iattributes = new int [2*MAX_ATTRIBS]; - float[] fattributes = new float[2*MAX_ATTRIBS]; - int nfattribs = 0; - int niattribs = 0; - - // Since we are trying to create a pbuffer, the GLXFBConfig we - // request (and subsequently use) must be "p-buffer capable". - iattributes[niattribs++] = GL.GLX_DRAWABLE_TYPE; - iattributes[niattribs++] = GL.GLX_PBUFFER_BIT; - - iattributes[niattribs++] = GL.GLX_RENDER_TYPE; - iattributes[niattribs++] = GL.GLX_RGBA_BIT; - - iattributes[niattribs++] = GLX.GLX_DOUBLEBUFFER; - if (capabilities.getDoubleBuffered()) { - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = GL.GL_FALSE; - } - - iattributes[niattribs++] = GLX.GLX_DEPTH_SIZE; - iattributes[niattribs++] = capabilities.getDepthBits(); - - iattributes[niattribs++] = GLX.GLX_RED_SIZE; - iattributes[niattribs++] = capabilities.getRedBits(); - - iattributes[niattribs++] = GLX.GLX_GREEN_SIZE; - iattributes[niattribs++] = capabilities.getGreenBits(); - - iattributes[niattribs++] = GLX.GLX_BLUE_SIZE; - iattributes[niattribs++] = capabilities.getBlueBits(); - - iattributes[niattribs++] = GLX.GLX_ALPHA_SIZE; - iattributes[niattribs++] = capabilities.getAlphaBits(); - - if (capabilities.getStencilBits() > 0) { - iattributes[niattribs++] = GLX.GLX_STENCIL_SIZE; - iattributes[niattribs++] = capabilities.getStencilBits(); - } - - if (capabilities.getAccumRedBits() > 0 || - capabilities.getAccumGreenBits() > 0 || - capabilities.getAccumBlueBits() > 0) { - iattributes[niattribs++] = GLX.GLX_ACCUM_RED_SIZE; - iattributes[niattribs++] = capabilities.getAccumRedBits(); - iattributes[niattribs++] = GLX.GLX_ACCUM_GREEN_SIZE; - iattributes[niattribs++] = capabilities.getAccumGreenBits(); - iattributes[niattribs++] = GLX.GLX_ACCUM_BLUE_SIZE; - iattributes[niattribs++] = capabilities.getAccumBlueBits(); - } - - if (capabilities.getOffscreenFloatingPointBuffers()) { - if (!gl.isExtensionAvailable("GLX_NV_float_buffer")) { - throw new GLException("Floating-point pbuffers on X11 currently require NVidia hardware"); - } - iattributes[niattribs++] = GLX.GLX_FLOAT_COMPONENTS_NV; - iattributes[niattribs++] = GL.GL_TRUE; - } - - // FIXME: add FSAA support? Don't want to get into a situation - // where we have to retry the glXChooseFBConfig call if it fails - // due to a lack of an antialiased visual... - - iattributes[niattribs++] = 0; // null-terminate - - int screen = 0; // FIXME: provide way to specify this? - int[] nelementsTmp = new int[1]; - GLXFBConfig[] fbConfigs = GLX.glXChooseFBConfig(display, screen, iattributes, 0, nelementsTmp, 0); - if (fbConfigs == null || fbConfigs.length == 0 || fbConfigs[0] == null) { - throw new GLException("pbuffer creation error: glXChooseFBConfig() failed"); - } - // Note that we currently don't allow selection of anything but - // the first GLXFBConfig in the returned list - GLXFBConfig fbConfig = fbConfigs[0]; - int nelements = nelementsTmp[0]; - if (nelements <= 0) { - throw new GLException("pbuffer creation error: couldn't find a suitable frame buffer configuration"); - } - - if (DEBUG) { - System.err.println("Found " + fbConfigs.length + " matching GLXFBConfigs"); - System.err.println("Parameters of default one:"); - System.err.println("render type: 0x" + Integer.toHexString(queryFBConfig(display, fbConfig, GLX.GLX_RENDER_TYPE))); - System.err.println("rgba: " + ((queryFBConfig(display, fbConfig, GLX.GLX_RENDER_TYPE) & GLX.GLX_RGBA_BIT) != 0)); - System.err.println("r: " + queryFBConfig(display, fbConfig, GLX.GLX_RED_SIZE)); - System.err.println("g: " + queryFBConfig(display, fbConfig, GLX.GLX_GREEN_SIZE)); - System.err.println("b: " + queryFBConfig(display, fbConfig, GLX.GLX_BLUE_SIZE)); - System.err.println("a: " + queryFBConfig(display, fbConfig, GLX.GLX_ALPHA_SIZE)); - System.err.println("depth: " + queryFBConfig(display, fbConfig, GLX.GLX_DEPTH_SIZE)); - System.err.println("double buffered: " + queryFBConfig(display, fbConfig, GLX.GLX_DOUBLEBUFFER)); - } - - // Create the p-buffer. - niattribs = 0; - - iattributes[niattribs++] = GL.GLX_PBUFFER_WIDTH; - iattributes[niattribs++] = initWidth; - iattributes[niattribs++] = GL.GLX_PBUFFER_HEIGHT; - iattributes[niattribs++] = initHeight; - - iattributes[niattribs++] = 0; - - long tmpBuffer = GLX.glXCreatePbuffer(display, fbConfig, iattributes, 0); - if (tmpBuffer == 0) { - // FIXME: query X error code for detail error message - throw new GLException("pbuffer creation error: glXCreatePbuffer() failed"); - } - - // Set up instance variables - this.display = display; - mostRecentDisplay = display; - this.parentContext = parentContext; - buffer = tmpBuffer; - this.fbConfig = fbConfig; - - // Determine the actual width and height we were able to create. - int[] tmp = new int[1]; - GLX.glXQueryDrawable(display, (int) buffer, GL.GLX_WIDTH, tmp, 0); - width = tmp[0]; - GLX.glXQueryDrawable(display, (int) buffer, GL.GLX_HEIGHT, tmp, 0); - height = tmp[0]; - - if (DEBUG) { - System.err.println("Created pbuffer " + width + " x " + height); - } - } - protected int makeCurrentImpl() throws GLException { - if (buffer == 0) { - // pbuffer not instantiated yet + if (drawable.getDrawable() == 0) { + // pbuffer not instantiated (yet?) + if (DEBUG) { + System.err.println("pbuffer not instantiated"); + } return CONTEXT_NOT_CURRENT; } + // Note that we have to completely override makeCurrentImpl + // because the underlying makeCurrent call differs for pbuffers lockAWT(); try { boolean created = false; if (context == 0) { create(); if (DEBUG) { - System.err.println("!!! Created GL context for " + getClass().getName()); + System.err.println(getThreadName() + ": !!! Created GL context for " + getClass().getName()); } created = true; } - if (!GLX.glXMakeContextCurrent(display, buffer, buffer, context)) { + if (!GLX.glXMakeContextCurrent(drawable.getDisplay(), + drawable.getDrawable(), + drawable.getDrawable(), + context)) { throw new GLException("Error making context current"); + } else { + mostRecentDisplay = drawable.getDisplay(); + if (DEBUG && VERBOSE) { + System.err.println(getThreadName() + ": glXMakeCurrent(display " + toHexString(drawable.getDisplay()) + + ", drawable " + toHexString(drawable.getDrawable()) + + ", context " + toHexString(context) + ") succeeded"); + } } if (created) { @@ -268,7 +120,7 @@ public class X11PbufferGLContext extends X11GLContext { protected void releaseImpl() throws GLException { lockAWT(); try { - if (!GLX.glXMakeContextCurrent(display, 0, 0, 0)) { + if (!GLX.glXMakeContextCurrent(drawable.getDisplay(), 0, 0, 0)) { throw new GLException("Error freeing OpenGL context"); } } finally { @@ -276,16 +128,6 @@ public class X11PbufferGLContext extends X11GLContext { } } - public void handleModeSwitch(long parentHdc, long parentHglrc) { - throw new GLException("Not yet implemented"); - } - - protected boolean isOffscreen() { - // FIXME: currently the only caller of this won't cause proper - // resizing of the pbuffer anyway. - return false; - } - public int getOffscreenContextReadBuffer() { throw new GLException("Should not call this"); } @@ -294,50 +136,34 @@ public class X11PbufferGLContext extends X11GLContext { throw new GLException("Should not call this"); } + public int getFloatingPointMode() { + return drawable.getFloatingPointMode(); + } + protected void create() { if (DEBUG) { - System.err.println("Creating context for pbuffer " + width + " x " + height); + System.err.println("Creating context for pbuffer " + drawable.getWidth() + + " x " + drawable.getHeight()); } // Create a gl context for the p-buffer. - // FIXME: provide option to not share display lists with subordinate pbuffer? - context = GLX.glXCreateNewContext(display, fbConfig, GL.GLX_RGBA_TYPE, parentContext, true); + X11GLContext other = (X11GLContext) GLContextShareSet.getShareContext(this); + long share = 0; + if (other != null) { + share = other.getContext(); + if (share == 0) { + throw new GLException("GLContextShareSet returned an invalid OpenGL context"); + } + } + context = GLX.glXCreateNewContext(drawable.getDisplay(), drawable.getFBConfig(), GL.GLX_RGBA_TYPE, share, true); if (context == 0) { throw new GLException("pbuffer creation error: glXCreateNewContext() failed"); } + GLContextShareSet.contextCreated(this); if (DEBUG) { - System.err.println("Created context for pbuffer " + width + " x " + height); - } - } - - protected void destroyImpl() throws GLException { - lockAWT(); - try { - if (context != 0) { - super.destroyImpl(); - GLX.glXDestroyPbuffer(display, buffer); - buffer = 0; - } - } finally { - unlockAWT(); - } - } - - public void swapBuffers() throws GLException { - // FIXME: do we need to do anything if the pbuffer is double-buffered? - } - - public int getFloatingPointMode() { - // Floating-point pbuffers currently require NVidia hardware on X11 - return GLPbuffer.NV_FLOAT; - } - - private int queryFBConfig(long display, GLXFBConfig fbConfig, int attrib) { - int[] tmp = new int[1]; - if (GLX.glXGetFBConfigAttrib(display, fbConfig, attrib, tmp, 0) != 0) { - throw new GLException("glXGetFBConfigAttrib failed"); + System.err.println("Created context for pbuffer " + drawable.getWidth() + + " x " + drawable.getHeight()); } - return tmp[0]; } } diff --git a/src/net/java/games/jogl/impl/x11/X11PbufferGLDrawable.java b/src/net/java/games/jogl/impl/x11/X11PbufferGLDrawable.java new file mode 100644 index 000000000..fc37f331b --- /dev/null +++ b/src/net/java/games/jogl/impl/x11/X11PbufferGLDrawable.java @@ -0,0 +1,254 @@ +/* + * 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.x11; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class X11PbufferGLDrawable extends X11GLDrawable { + private int initWidth; + private int initHeight; + + // drawable in superclass is a GLXPbuffer + private GLXFBConfig fbConfig; + private int width; + private int height; + + protected static final int MAX_PFORMATS = 256; + protected static final int MAX_ATTRIBS = 256; + + public X11PbufferGLDrawable(GLCapabilities capabilities, int initialWidth, int initialHeight) { + super(null, capabilities, null); + this.initWidth = initialWidth; + this.initHeight = initialHeight; + if (initWidth <= 0 || initHeight <= 0) { + throw new GLException("Initial width and height of pbuffer must be positive (were (" + + initWidth + ", " + initHeight + "))"); + } + + if (DEBUG) { + System.out.println("Pbuffer caps on init: " + capabilities + + (capabilities.getOffscreenRenderToTexture() ? " [rtt]" : "") + + (capabilities.getOffscreenRenderToTextureRectangle() ? " [rect]" : "") + + (capabilities.getOffscreenFloatingPointBuffers() ? " [float]" : "")); + } + } + + public GLContext createContext(GLContext shareWith) { + return new X11PbufferGLContext(this, shareWith); + } + + public void destroy() { + lockAWT(); + if (drawable != 0) { + GLX.glXDestroyPbuffer(display, drawable); + } + unlockAWT(); + display = 0; + } + + public void setSize(int width, int height) { + // FIXME + throw new GLException("Not yet implemented"); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void createPbuffer(GL gl, long display) { + if (display == 0) { + throw new GLException("Null display"); + } + + if (capabilities.getOffscreenRenderToTexture()) { + throw new GLException("Render-to-texture pbuffers not supported yet on X11"); + } + + if (capabilities.getOffscreenRenderToTextureRectangle()) { + throw new GLException("Render-to-texture-rectangle pbuffers not supported yet on X11"); + } + + int[] iattributes = new int [2*MAX_ATTRIBS]; + float[] fattributes = new float[2*MAX_ATTRIBS]; + int nfattribs = 0; + int niattribs = 0; + + // Since we are trying to create a pbuffer, the GLXFBConfig we + // request (and subsequently use) must be "p-buffer capable". + iattributes[niattribs++] = GL.GLX_DRAWABLE_TYPE; + iattributes[niattribs++] = GL.GLX_PBUFFER_BIT; + + iattributes[niattribs++] = GL.GLX_RENDER_TYPE; + iattributes[niattribs++] = GL.GLX_RGBA_BIT; + + iattributes[niattribs++] = GLX.GLX_DOUBLEBUFFER; + if (capabilities.getDoubleBuffered()) { + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = GL.GL_FALSE; + } + + iattributes[niattribs++] = GLX.GLX_DEPTH_SIZE; + iattributes[niattribs++] = capabilities.getDepthBits(); + + iattributes[niattribs++] = GLX.GLX_RED_SIZE; + iattributes[niattribs++] = capabilities.getRedBits(); + + iattributes[niattribs++] = GLX.GLX_GREEN_SIZE; + iattributes[niattribs++] = capabilities.getGreenBits(); + + iattributes[niattribs++] = GLX.GLX_BLUE_SIZE; + iattributes[niattribs++] = capabilities.getBlueBits(); + + iattributes[niattribs++] = GLX.GLX_ALPHA_SIZE; + iattributes[niattribs++] = capabilities.getAlphaBits(); + + if (capabilities.getStencilBits() > 0) { + iattributes[niattribs++] = GLX.GLX_STENCIL_SIZE; + iattributes[niattribs++] = capabilities.getStencilBits(); + } + + if (capabilities.getAccumRedBits() > 0 || + capabilities.getAccumGreenBits() > 0 || + capabilities.getAccumBlueBits() > 0) { + iattributes[niattribs++] = GLX.GLX_ACCUM_RED_SIZE; + iattributes[niattribs++] = capabilities.getAccumRedBits(); + iattributes[niattribs++] = GLX.GLX_ACCUM_GREEN_SIZE; + iattributes[niattribs++] = capabilities.getAccumGreenBits(); + iattributes[niattribs++] = GLX.GLX_ACCUM_BLUE_SIZE; + iattributes[niattribs++] = capabilities.getAccumBlueBits(); + } + + if (capabilities.getOffscreenFloatingPointBuffers()) { + if (!gl.isExtensionAvailable("GLX_NV_float_buffer")) { + throw new GLException("Floating-point pbuffers on X11 currently require NVidia hardware"); + } + iattributes[niattribs++] = GLX.GLX_FLOAT_COMPONENTS_NV; + iattributes[niattribs++] = GL.GL_TRUE; + } + + // FIXME: add FSAA support? Don't want to get into a situation + // where we have to retry the glXChooseFBConfig call if it fails + // due to a lack of an antialiased visual... + + iattributes[niattribs++] = 0; // null-terminate + + int screen = 0; // FIXME: provide way to specify this? + int[] nelementsTmp = new int[1]; + GLXFBConfig[] fbConfigs = GLX.glXChooseFBConfig(display, screen, iattributes, 0, nelementsTmp, 0); + if (fbConfigs == null || fbConfigs.length == 0 || fbConfigs[0] == null) { + throw new GLException("pbuffer creation error: glXChooseFBConfig() failed"); + } + // Note that we currently don't allow selection of anything but + // the first GLXFBConfig in the returned list + GLXFBConfig fbConfig = fbConfigs[0]; + int nelements = nelementsTmp[0]; + if (nelements <= 0) { + throw new GLException("pbuffer creation error: couldn't find a suitable frame buffer configuration"); + } + + if (DEBUG) { + System.err.println("Found " + fbConfigs.length + " matching GLXFBConfigs"); + System.err.println("Parameters of default one:"); + System.err.println("render type: 0x" + Integer.toHexString(queryFBConfig(display, fbConfig, GLX.GLX_RENDER_TYPE))); + System.err.println("rgba: " + ((queryFBConfig(display, fbConfig, GLX.GLX_RENDER_TYPE) & GLX.GLX_RGBA_BIT) != 0)); + System.err.println("r: " + queryFBConfig(display, fbConfig, GLX.GLX_RED_SIZE)); + System.err.println("g: " + queryFBConfig(display, fbConfig, GLX.GLX_GREEN_SIZE)); + System.err.println("b: " + queryFBConfig(display, fbConfig, GLX.GLX_BLUE_SIZE)); + System.err.println("a: " + queryFBConfig(display, fbConfig, GLX.GLX_ALPHA_SIZE)); + System.err.println("depth: " + queryFBConfig(display, fbConfig, GLX.GLX_DEPTH_SIZE)); + System.err.println("double buffered: " + queryFBConfig(display, fbConfig, GLX.GLX_DOUBLEBUFFER)); + } + + // Create the p-buffer. + niattribs = 0; + + iattributes[niattribs++] = GL.GLX_PBUFFER_WIDTH; + iattributes[niattribs++] = initWidth; + iattributes[niattribs++] = GL.GLX_PBUFFER_HEIGHT; + iattributes[niattribs++] = initHeight; + + iattributes[niattribs++] = 0; + + long tmpBuffer = GLX.glXCreatePbuffer(display, fbConfig, iattributes, 0); + if (tmpBuffer == 0) { + // FIXME: query X error code for detail error message + throw new GLException("pbuffer creation error: glXCreatePbuffer() failed"); + } + + // Set up instance variables + this.display = display; + drawable = tmpBuffer; + this.fbConfig = fbConfig; + + // Determine the actual width and height we were able to create. + int[] tmp = new int[1]; + GLX.glXQueryDrawable(display, drawable, GL.GLX_WIDTH, tmp, 0); + width = tmp[0]; + GLX.glXQueryDrawable(display, drawable, GL.GLX_HEIGHT, tmp, 0); + height = tmp[0]; + + if (DEBUG) { + System.err.println("Created pbuffer " + width + " x " + height); + } + } + + public int getFloatingPointMode() { + // Floating-point pbuffers currently require NVidia hardware on X11 + return GLPbuffer.NV_FLOAT; + } + + public GLXFBConfig getFBConfig() { + return fbConfig; + } + + private int queryFBConfig(long display, GLXFBConfig fbConfig, int attrib) { + int[] tmp = new int[1]; + if (GLX.glXGetFBConfigAttrib(display, fbConfig, attrib, tmp, 0) != 0) { + throw new GLException("glXGetFBConfigAttrib failed"); + } + return tmp[0]; + } +} |