diff options
author | Kenneth Russel <[email protected]> | 2006-11-19 20:51:57 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2006-11-19 20:51:57 +0000 |
commit | a303cd13ff62f94a0459978735620e37d72bbb77 (patch) | |
tree | 32b580af4e878d479890c12b8eae9c98e10a4874 | |
parent | bf82eceb6f78d5ee6e4c0f9f02590d2a58e647d3 (diff) |
Fixed Issue 213: Expose GLCaps from GLDrawable
Added getChosenGLCapabilities() to the GLDrawable interface.
Implemented on Windows, Unix and Mac OS X platforms with various
techniques. Attempts to provide correct answers in all cases, even
when the GLCapabilitiesChooser mechanism is not supported. Required
addition of new platform-specific Java code in most cases to either
re-convert existing PIXELFORMATDESCRIPTORS / XVisualInfos, or to query
the pixel format or visual chosen for drawables like pbuffers for
which the chooser mechanism is not (yet) implemented. Tested on
Windows, Solaris/x86, and Mac OS X with on-screen, off-screen and
pbuffer drawables. (Full support for the Java2D/JOGL bridge is not yet
in place; the answer returned from the GLJPanel in this case is
currently the default GLCapabilities, and it is likely that "external"
GLDrawables will return null.)
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@989 232f8b59-042b-4e1e-8c03-345bb8c30851
18 files changed, 570 insertions, 115 deletions
diff --git a/make/stub_includes/macosx/window-system.c b/make/stub_includes/macosx/window-system.c index f2738b454..787d265ed 100644 --- a/make/stub_includes/macosx/window-system.c +++ b/make/stub_includes/macosx/window-system.c @@ -1 +1,47 @@ #include "macosx-window-system.h" + +/* These can not show up in the header file above because they must not be visible during the real build */ + +/* +** Attribute names for [NSOpenGLPixelFormat initWithAttributes] +** and [NSOpenGLPixelFormat getValues:forAttribute:forVirtualScreen]. +*/ +typedef enum { + NSOpenGLPFAAllRenderers = 1, /* choose from all available renderers */ + NSOpenGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */ + NSOpenGLPFAStereo = 6, /* stereo buffering supported */ + NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */ + NSOpenGLPFAColorSize = 8, /* number of color buffer bits */ + NSOpenGLPFAAlphaSize = 11, /* number of alpha component bits */ + NSOpenGLPFADepthSize = 12, /* number of depth buffer bits */ + NSOpenGLPFAStencilSize = 13, /* number of stencil buffer bits */ + NSOpenGLPFAAccumSize = 14, /* number of accum buffer bits */ + NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */ + NSOpenGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */ + NSOpenGLPFAOffScreen = 53, /* choose an off-screen capable renderer */ + NSOpenGLPFAFullScreen = 54, /* choose a full-screen capable renderer */ + NSOpenGLPFASampleBuffers = 55, /* number of multi sample buffers */ + NSOpenGLPFASamples = 56, /* number of samples per multi sample buffer */ + NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */ + NSOpenGLPFAColorFloat = 58, /* color buffers store floating point pixels */ + + NSOpenGLPFAMultisample = 59, /* choose multisampling */ + NSOpenGLPFASupersample = 60, /* choose supersampling */ + NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */ + + NSOpenGLPFARendererID = 70, /* request renderer by ID */ + NSOpenGLPFASingleRenderer = 71, /* choose a single renderer for all screens */ + NSOpenGLPFANoRecovery = 72, /* disable all failure recovery systems */ + NSOpenGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */ + NSOpenGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */ + NSOpenGLPFARobust = 75, /* renderer does not need failure recovery */ + NSOpenGLPFABackingStore = 76, /* back buffer contents are valid after swap */ + NSOpenGLPFAMPSafe = 78, /* renderer is multi-processor safe */ + NSOpenGLPFAWindow = 80, /* can be used to render to an onscreen window */ + NSOpenGLPFAMultiScreen = 81, /* single window can span multiple screens */ + NSOpenGLPFACompliant = 83, /* renderer is opengl compliant */ + NSOpenGLPFAScreenMask = 84, /* bit mask of supported physical screens */ + NSOpenGLPFAPixelBuffer = 90, /* can be used to render to a pbuffer */ + NSOpenGLPFAVirtualScreenCount = 128 /* number of virtual screens in this format */ +} NSOpenGLPixelFormatAttribute; + diff --git a/make/stub_includes/opengl/macosx-window-system.h b/make/stub_includes/opengl/macosx-window-system.h index 1d3df1a08..ed07ce74d 100644 --- a/make/stub_includes/opengl/macosx-window-system.h +++ b/make/stub_includes/opengl/macosx-window-system.h @@ -9,23 +9,13 @@ typedef int Bool; -void* createContext(void* shareContext, void* nsView, - int doubleBuffer, - int stereo, - int redBits, - int greenBits, - int blueBits, - int alphaBits, - int depthBits, - int stencilBits, - int accumRedBits, - int accumGreenBits, - int accumBlueBits, - int accumAlphaBits, - int sampleBuffers, - int numSamples, - int pbuffer, - int floatingPoint, +void* createPixelFormat(int* iattrs, int niattrs, int* ivalues); +void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues); +void deletePixelFormat(void* pixelFormat); + +void* createContext(void* shareContext, + void* nsView, + void* pixelFormat, int* viewNotReady); Bool makeCurrentContext(void* nsContext); Bool clearCurrentContext(void* nsContext); diff --git a/src/classes/com/sun/opengl/impl/GLDrawableImpl.java b/src/classes/com/sun/opengl/impl/GLDrawableImpl.java index f93ed9663..df1aab796 100644 --- a/src/classes/com/sun/opengl/impl/GLDrawableImpl.java +++ b/src/classes/com/sun/opengl/impl/GLDrawableImpl.java @@ -42,6 +42,8 @@ package com.sun.opengl.impl; import javax.media.opengl.*; public abstract class GLDrawableImpl implements GLDrawable { + private GLCapabilities chosenCapabilities; + /** For offscreen GLDrawables (pbuffers and "pixmap" drawables), indicates that native resources should be reclaimed. */ public abstract void destroy() throws GLException; @@ -49,4 +51,16 @@ public abstract class GLDrawableImpl implements GLDrawable { public static String toHexString(long hex) { return GLContextImpl.toHexString(hex); } + + public GLCapabilities getChosenGLCapabilities() { + if (chosenCapabilities == null) + return null; + + // Must return a new copy to avoid mutation by end user + return (GLCapabilities) chosenCapabilities.clone(); + } + + public void setChosenGLCapabilities(GLCapabilities caps) { + chosenCapabilities = caps; + } } diff --git a/src/classes/com/sun/opengl/impl/GLPbufferImpl.java b/src/classes/com/sun/opengl/impl/GLPbufferImpl.java index feb9d3512..cf4ae31af 100644 --- a/src/classes/com/sun/opengl/impl/GLPbufferImpl.java +++ b/src/classes/com/sun/opengl/impl/GLPbufferImpl.java @@ -142,6 +142,13 @@ public class GLPbufferImpl implements GLPbuffer { context.releasePbufferFromTexture(); } + public GLCapabilities getChosenGLCapabilities() { + if (pbufferDrawable == null) + return null; + + return pbufferDrawable.getChosenGLCapabilities(); + } + //---------------------------------------------------------------------- // No-ops for ComponentEvents // diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java index e41ad856d..16855efb8 100644 --- a/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java +++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXGLContext.java @@ -102,34 +102,130 @@ public abstract class MacOSXGLContext extends GLContextImpl } int[] viewNotReady = new int[1]; GLCapabilities capabilities = drawable.getCapabilities(); - nsContext = CGL.createContext(share, - drawable.getView(), - capabilities.getDoubleBuffered() ? 1 : 0, - capabilities.getStereo() ? 1 : 0, - capabilities.getRedBits(), - capabilities.getGreenBits(), - capabilities.getBlueBits(), - capabilities.getAlphaBits(), - capabilities.getDepthBits(), - capabilities.getStencilBits(), - capabilities.getAccumRedBits(), - capabilities.getAccumGreenBits(), - capabilities.getAccumBlueBits(), - capabilities.getAccumAlphaBits(), - capabilities.getSampleBuffers() ? 1 : 0, - capabilities.getNumSamples(), - (pbuffer ? 1 : 0), - (floatingPoint ? 1 : 0), - viewNotReady, 0); - if (nsContext == 0) { - if (viewNotReady[0] == 1) { - if (DEBUG) { - System.err.println("!!! View not ready for " + getClass().getName()); + int[] iattribs = new int[128]; + int[] ivalues = new int[128]; + int idx = 0; + if (pbuffer) { + iattribs[idx] = CGL.NSOpenGLPFAPixelBuffer; ivalues[idx] = 1; idx++; + } + if (floatingPoint) { + iattribs[idx] = CGL.kCGLPFAColorFloat; ivalues[idx] = 1; idx++; + } + iattribs[idx] = CGL.NSOpenGLPFADoubleBuffer; ivalues[idx] = (capabilities.getDoubleBuffered() ? 1 : 0); idx++; + iattribs[idx] = CGL.NSOpenGLPFAStereo; ivalues[idx] = (capabilities.getStereo() ? 1 : 0); idx++; + iattribs[idx] = CGL.NSOpenGLPFAColorSize; ivalues[idx] = (capabilities.getRedBits() + + capabilities.getGreenBits() + + capabilities.getBlueBits()); idx++; + iattribs[idx] = CGL.NSOpenGLPFAAlphaSize; ivalues[idx] = capabilities.getAlphaBits(); idx++; + iattribs[idx] = CGL.NSOpenGLPFADepthSize; ivalues[idx] = capabilities.getDepthBits(); idx++; + iattribs[idx] = CGL.NSOpenGLPFAAccumSize; ivalues[idx] = (capabilities.getAccumRedBits() + + capabilities.getAccumGreenBits() + + capabilities.getAccumBlueBits() + + capabilities.getAccumAlphaBits()); idx++; + iattribs[idx] = CGL.NSOpenGLPFAStencilSize; ivalues[idx] = capabilities.getStencilBits(); idx++; + if (capabilities.getSampleBuffers()) { + iattribs[idx] = CGL.NSOpenGLPFASampleBuffers; ivalues[idx] = 1; idx++; + iattribs[idx] = CGL.NSOpenGLPFASamples; ivalues[idx] = capabilities.getNumSamples(); idx++; + } + + long pixelFormat = CGL.createPixelFormat(iattribs, 0, idx, ivalues, 0); + if (pixelFormat == 0) { + throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); + } + try { + // Try to allocate a context with this + nsContext = CGL.createContext(share, + drawable.getView(), + pixelFormat, + viewNotReady, 0); + if (nsContext == 0) { + if (viewNotReady[0] == 1) { + if (DEBUG) { + System.err.println("!!! View not ready for " + getClass().getName()); + } + // View not ready at the window system level -- this is OK + return false; + } + throw new GLException("Error creating NSOpenGLContext with requested pixel format"); + } + + // On this platform the pixel format is associated with the + // context and not the drawable. However it's a reasonable + // approximation to just store the chosen pixel format up in the + // drawable since the public API doesn't provide for a different + // GLCapabilities per context. + if (drawable.getChosenGLCapabilities() == null) { + // Figure out what attributes we really got + GLCapabilities caps = new GLCapabilities(); + CGL.queryPixelFormat(pixelFormat, iattribs, 0, idx, ivalues, 0); + for (int i = 0; i < idx; i++) { + int attr = iattribs[i]; + switch (attr) { + case CGL.kCGLPFAColorFloat: + caps.setPbufferFloatingPointBuffers(ivalues[i] != 0); + break; + + case CGL.NSOpenGLPFADoubleBuffer: + caps.setDoubleBuffered(ivalues[i] != 0); + break; + + case CGL.NSOpenGLPFAStereo: + caps.setStereo(ivalues[i] != 0); + break; + + case CGL.NSOpenGLPFAColorSize: + { + int bitSize = ivalues[i]; + if (bitSize == 32) + bitSize = 24; + bitSize /= 3; + caps.setRedBits(bitSize); + caps.setGreenBits(bitSize); + caps.setBlueBits(bitSize); + } + break; + + case CGL.NSOpenGLPFAAlphaSize: + caps.setAlphaBits(ivalues[i]); + break; + + case CGL.NSOpenGLPFADepthSize: + caps.setDepthBits(ivalues[i]); + break; + + case CGL.NSOpenGLPFAAccumSize: + { + int bitSize = ivalues[i] / 4; + caps.setAccumRedBits(bitSize); + caps.setAccumGreenBits(bitSize); + caps.setAccumBlueBits(bitSize); + caps.setAccumAlphaBits(bitSize); + } + break; + + case CGL.NSOpenGLPFAStencilSize: + caps.setStencilBits(ivalues[i]); + break; + + case CGL.NSOpenGLPFASampleBuffers: + caps.setSampleBuffers(ivalues[i] != 0); + break; + + case CGL.NSOpenGLPFASamples: + caps.setNumSamples(ivalues[i]); + break; + + default: + break; + } } - // View not ready at the window system level -- this is OK - return false; + + drawable.setChosenGLCapabilities(caps); } - throw new GLException("Error creating nsContext"); + + + } finally { + CGL.deletePixelFormat(pixelFormat); } GLContextShareSet.contextCreated(this); return true; diff --git a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java index 2cb501020..7a42ad37c 100644 --- a/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/macosx/MacOSXOnscreenGLDrawable.java @@ -102,6 +102,9 @@ public class MacOSXOnscreenGLDrawable extends MacOSXGLDrawable { public void setRealized(boolean realized) { this.realized = realized; + // Might as well clear out the "chosen" pixel format, though it's + // associated with the GLContext on this platform and not the drawable + setChosenGLCapabilities(null); } public void setSize(int width, int height) { diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawable.java b/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawable.java index e5b8b6424..1efc1c759 100644 --- a/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawable.java @@ -78,13 +78,20 @@ public abstract class WindowsGLDrawable extends GLDrawableImpl { PIXELFORMATDESCRIPTOR pfd = null; int pixelFormat = 0; if (onscreen) { - if (WGL.GetPixelFormat(hdc) != 0) { + if ((pixelFormat = WGL.GetPixelFormat(hdc)) != 0) { // The Java2D/OpenGL pipeline probably already set a pixel // format for this canvas. if (DEBUG) { System.err.println("NOTE: pixel format already chosen (by Java2D/OpenGL pipeline?) for window: " + WGL.GetPixelFormat(hdc)); } + pfd = newPixelFormatDescriptor(); + if (WGL.DescribePixelFormat(hdc, pixelFormat, pfd.size(), pfd) == 0) { + // FIXME: should this just be a warning? Not really critical... + throw new GLException("Unable to describe pixel format " + pixelFormat + + " of window set by Java2D/OpenGL pipeline"); + } + setChosenGLCapabilities(pfd2GLCapabilities(pfd)); pixelFormatChosen = true; return; } @@ -280,6 +287,7 @@ public abstract class WindowsGLDrawable extends GLDrawableImpl { } throw new GLException("Unable to set pixel format " + pixelFormat + " for device context " + toHexString(hdc) + ": error code " + lastError); } + setChosenGLCapabilities(pfd2GLCapabilities(pfd)); pixelFormatChosen = true; } @@ -518,10 +526,13 @@ public abstract class WindowsGLDrawable extends GLDrawableImpl { int attr = iattribs[i]; switch (attr) { case WGLExt.WGL_DRAW_TO_WINDOW_ARB: - if (iresults[i] != GL.GL_TRUE) + if (requireRenderToWindow && iresults[i] != GL.GL_TRUE) return null; break; + case WGLExt.WGL_DRAW_TO_PBUFFER_ARB: + break; + case WGLExt.WGL_ACCELERATION_ARB: res.setHardwareAccelerated(iresults[i] == WGLExt.WGL_FULL_ACCELERATION_ARB); break; @@ -548,8 +559,17 @@ public abstract class WindowsGLDrawable extends GLDrawableImpl { break; case WGLExt.WGL_PIXEL_TYPE_ARB: - if (iresults[i] != WGLExt.WGL_TYPE_RGBA_ARB) - return null; + // Fail softly with unknown results here + if (iresults[i] == WGLExt.WGL_TYPE_RGBA_ARB || + iresults[i] == WGLExt.WGL_TYPE_RGBA_FLOAT_ATI) { + res.setPbufferFloatingPointBuffers(true); + } + break; + + case WGLExt.WGL_FLOAT_COMPONENTS_NV: + if (iresults[i] != 0) { + res.setPbufferFloatingPointBuffers(true); + } break; case WGLExt.WGL_RED_BITS_ARB: diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawableFactory.java b/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawableFactory.java index 1c77d5b04..6e1b4ca99 100644 --- a/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawableFactory.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsGLDrawableFactory.java @@ -118,6 +118,9 @@ public class WindowsGLDrawableFactory extends GLDrawableFactoryImpl { }; maybeDoSingleThreadedWorkaround(r); } + if (DEBUG) { + System.err.println("WindowsGLDrawableFactory.canCreateGLPbuffer() = " + canCreateGLPbuffer); + } return canCreateGLPbuffer; } diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsOffscreenGLDrawable.java b/src/classes/com/sun/opengl/impl/windows/WindowsOffscreenGLDrawable.java index 4fe9c93b2..474c71598 100644 --- a/src/classes/com/sun/opengl/impl/windows/WindowsOffscreenGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsOffscreenGLDrawable.java @@ -128,6 +128,7 @@ public class WindowsOffscreenGLDrawable extends WindowsGLDrawable { origbitmap = 0; hbitmap = 0; hdc = 0; + setChosenGLCapabilities(null); } } } diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsOnscreenGLDrawable.java b/src/classes/com/sun/opengl/impl/windows/WindowsOnscreenGLDrawable.java index 41f959482..5f74998e5 100644 --- a/src/classes/com/sun/opengl/impl/windows/WindowsOnscreenGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsOnscreenGLDrawable.java @@ -96,6 +96,7 @@ public class WindowsOnscreenGLDrawable extends WindowsGLDrawable { this.realized = realized; if (!realized) { // Assume heavyweight widget was destroyed + setChosenGLCapabilities(null); pixelFormatChosen = false; } } diff --git a/src/classes/com/sun/opengl/impl/windows/WindowsPbufferGLDrawable.java b/src/classes/com/sun/opengl/impl/windows/WindowsPbufferGLDrawable.java index 0dddddddd..4f87eaecf 100644 --- a/src/classes/com/sun/opengl/impl/windows/WindowsPbufferGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/windows/WindowsPbufferGLDrawable.java @@ -96,6 +96,7 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { throw new GLException("Error destroying pbuffer: error code " + WGL.GetLastError()); } buffer = 0; + setChosenGLCapabilities(null); } } @@ -198,8 +199,8 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { iattributes[3] = WGLExt.WGL_ALPHA_BITS_ARB; iattributes[4] = WGLExt.WGL_DEPTH_BITS_ARB; iattributes[5] = (useFloat ? (ati ? WGLExt.WGL_PIXEL_TYPE_ARB : WGLExt.WGL_FLOAT_COMPONENTS_NV) : WGLExt.WGL_RED_BITS_ARB); - iattributes[6] = WGLExt.WGL_SAMPLE_BUFFERS_EXT; - iattributes[7] = WGLExt.WGL_SAMPLES_EXT; + iattributes[6] = WGLExt.WGL_SAMPLE_BUFFERS_ARB; + iattributes[7] = WGLExt.WGL_SAMPLES_ARB; iattributes[8] = WGLExt.WGL_DRAW_TO_PBUFFER_ARB; int[] ivalues = new int[9]; for (int i = 0; i < nformats; i++) { @@ -237,9 +238,9 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { } long tmpBuffer = 0; - int whichFormat = 0; + int whichFormat = -1; // Loop is a workaround for bugs in NVidia's recent drivers - do { + for (whichFormat = 0; whichFormat < nformats; whichFormat++) { int format = pformats[whichFormat]; // Create the p-buffer. @@ -266,8 +267,11 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { iattributes[niattribs++] = 0; tmpBuffer = wglExt.wglCreatePbufferARB(parentHdc, format, initWidth, initHeight, iattributes, 0); - ++whichFormat; - } while ((tmpBuffer == 0) && (whichFormat < nformats)); + if (tmpBuffer != 0) { + // Done + break; + } + } if (tmpBuffer == 0) { throw new GLException("pbuffer creation error: wglCreatePbufferARB() failed: tried " + nformats + @@ -285,6 +289,33 @@ public class WindowsPbufferGLDrawable extends WindowsGLDrawable { hdc = tmpHdc; cachedWGLExt = wglExt; + // Re-query chosen pixel format + { + niattribs = 0; + iattributes[niattribs++] = WGLExt.WGL_ACCELERATION_ARB; + iattributes[niattribs++] = WGLExt.WGL_RED_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_GREEN_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_BLUE_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_ALPHA_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_DEPTH_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_STENCIL_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_DOUBLE_BUFFER_ARB; + iattributes[niattribs++] = WGLExt.WGL_STEREO_ARB; + iattributes[niattribs++] = WGLExt.WGL_ACCUM_RED_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_ACCUM_GREEN_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_ACCUM_BLUE_BITS_ARB; + iattributes[niattribs++] = WGLExt.WGL_ACCUM_ALPHA_BITS_ARB; + iattributes[niattribs++] = (useFloat ? (ati ? WGLExt.WGL_PIXEL_TYPE_ARB : WGLExt.WGL_FLOAT_COMPONENTS_NV) : WGLExt.WGL_RED_BITS_ARB); + iattributes[niattribs++] = WGLExt.WGL_SAMPLE_BUFFERS_ARB; + iattributes[niattribs++] = WGLExt.WGL_SAMPLES_ARB; + iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_PBUFFER_ARB; + int[] ivalues = new int[niattribs]; + // FIXME: usually prefer to throw exceptions, but failure here is not critical + if (wglExt.wglGetPixelFormatAttribivARB(parentHdc, pformats[whichFormat], 0, niattribs, iattributes, 0, ivalues, 0)) { + setChosenGLCapabilities(iattributes2GLCapabilities(iattributes, niattribs, ivalues, false)); + } + } + // Determine the actual width and height we were able to create. int[] tmp = new int[1]; wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_WIDTH_ARB, tmp, 0 ); diff --git a/src/classes/com/sun/opengl/impl/x11/X11GLDrawableFactory.java b/src/classes/com/sun/opengl/impl/x11/X11GLDrawableFactory.java index b1863d41c..4f92681d0 100644 --- a/src/classes/com/sun/opengl/impl/x11/X11GLDrawableFactory.java +++ b/src/classes/com/sun/opengl/impl/x11/X11GLDrawableFactory.java @@ -62,6 +62,38 @@ public class X11GLDrawableFactory extends GLDrawableFactoryImpl { // in this case private static boolean isVendorATI; + // Map for rediscovering the GLCapabilities associated with a + // particular screen and visualID after the fact + private static Map visualToGLCapsMap = Collections.synchronizedMap(new HashMap()); + + static class ScreenAndVisualIDKey { + private int screen; + private long visualID; + + ScreenAndVisualIDKey(int screen, + long visualID) { + this.screen = screen; + this.visualID = visualID; + } + + public int hashCode() { + return (int) (screen + 13 * visualID); + } + + public boolean equals(Object obj) { + if ((obj == null) || (!(obj instanceof ScreenAndVisualIDKey))) { + return false; + } + + ScreenAndVisualIDKey key = (ScreenAndVisualIDKey) obj; + return (screen == key.screen && + visualID == key.visualID); + } + + int screen() { return screen; } + long visualID() { return visualID; } + } + static { // See DRIHack.java for an explanation of why this is necessary DRIHack.begin(); @@ -157,6 +189,11 @@ public class X11GLDrawableFactory extends GLDrawableFactoryImpl { } finally { unlockToolkit(); } + // Store these away for later + for (int i = 0; i < infos.length; i++) { + visualToGLCapsMap.put(new ScreenAndVisualIDKey(screen, infos[i].visualid()), + caps[i].clone()); + } int chosen = chooser.chooseCapabilities(capabilities, caps, recommendedIndex); if (chosen < 0 || chosen >= caps.length) { throw new GLException("GLCapabilitiesChooser specified invalid index (expected 0.." + (caps.length - 1) + ")"); @@ -200,7 +237,22 @@ public class X11GLDrawableFactory extends GLDrawableFactoryImpl { 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); + Component comp = (Component) target; + X11OnscreenGLDrawable drawable = new X11OnscreenGLDrawable(comp); + // Figure out the GLCapabilities of this component + GraphicsConfiguration config = comp.getGraphicsConfiguration(); + if (config == null) { + throw new IllegalArgumentException("GLDrawableFactory.chooseGraphicsConfiguration() was not used when creating this Component"); + } + int visualID = X11SunJDKReflection.graphicsConfigurationGetVisualID(config); + int screen; + if (isXineramaEnabled()) { + screen = 0; + } else { + screen = X11SunJDKReflection.graphicsDeviceGetScreen(config.getDevice()); + } + drawable.setChosenGLCapabilities((GLCapabilities) visualToGLCapsMap.get(new ScreenAndVisualIDKey(screen, visualID))); + return drawable; } public GLDrawableImpl createOffscreenDrawable(GLCapabilities capabilities, @@ -431,6 +483,83 @@ public class X11GLDrawableFactory extends GLDrawableFactoryImpl { return res; } + public static GLCapabilities attribList2GLCapabilities(int[] iattribs, + int niattribs, + int[] ivalues, + boolean pbuffer) { + GLCapabilities caps = new GLCapabilities(); + + for (int i = 0; i < niattribs; i++) { + int attr = iattribs[i]; + switch (attr) { + case GLX.GLX_DOUBLEBUFFER: + caps.setDoubleBuffered(ivalues[i] != GL.GL_FALSE); + break; + + case GLX.GLX_STEREO: + caps.setStereo(ivalues[i] != GL.GL_FALSE); + break; + + case GLX.GLX_RED_SIZE: + caps.setRedBits(ivalues[i]); + break; + + case GLX.GLX_GREEN_SIZE: + caps.setGreenBits(ivalues[i]); + break; + + case GLX.GLX_BLUE_SIZE: + caps.setBlueBits(ivalues[i]); + break; + + case GLX.GLX_ALPHA_SIZE: + caps.setAlphaBits(ivalues[i]); + break; + + case GLX.GLX_DEPTH_SIZE: + caps.setDepthBits(ivalues[i]); + break; + + case GLX.GLX_STENCIL_SIZE: + caps.setStencilBits(ivalues[i]); + break; + + case GLX.GLX_ACCUM_RED_SIZE: + caps.setAccumRedBits(ivalues[i]); + break; + + case GLX.GLX_ACCUM_GREEN_SIZE: + caps.setAccumGreenBits(ivalues[i]); + break; + + case GLX.GLX_ACCUM_BLUE_SIZE: + caps.setAccumBlueBits(ivalues[i]); + break; + + case GLX.GLX_ACCUM_ALPHA_SIZE: + caps.setAccumAlphaBits(ivalues[i]); + break; + + case GLXExt.GLX_SAMPLE_BUFFERS_ARB: + caps.setSampleBuffers(ivalues[i] != GL.GL_FALSE); + break; + + case GLXExt.GLX_SAMPLES_ARB: + caps.setNumSamples(ivalues[i]); + break; + + case GLX.GLX_FLOAT_COMPONENTS_NV: + caps.setPbufferFloatingPointBuffers(ivalues[i] != GL.GL_FALSE); + break; + + default: + break; + } + } + + return caps; + } + public void lockToolkit() { if (!Java2D.isOGLPipelineActive() || !Java2D.isQueueFlusherThread()) { JAWT.getJAWT().Lock(); diff --git a/src/classes/com/sun/opengl/impl/x11/X11OffscreenGLDrawable.java b/src/classes/com/sun/opengl/impl/x11/X11OffscreenGLDrawable.java index 3b3879b8e..d70c79334 100644 --- a/src/classes/com/sun/opengl/impl/x11/X11OffscreenGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/x11/X11OffscreenGLDrawable.java @@ -99,6 +99,7 @@ public class X11OffscreenGLDrawable extends X11GLDrawable { ", GLXPixmap " + toHexString(drawable) + ", display " + toHexString(display)); } + setChosenGLCapabilities(X11GLDrawableFactory.xvi2GLCapabilities(display, vis)); } finally { unlockToolkit(); } @@ -134,6 +135,7 @@ public class X11OffscreenGLDrawable extends X11GLDrawable { drawable = 0; pixmap = 0; display = 0; + setChosenGLCapabilities(null); } } diff --git a/src/classes/com/sun/opengl/impl/x11/X11PbufferGLDrawable.java b/src/classes/com/sun/opengl/impl/x11/X11PbufferGLDrawable.java index 27abdf5b6..b03fdde03 100644 --- a/src/classes/com/sun/opengl/impl/x11/X11PbufferGLDrawable.java +++ b/src/classes/com/sun/opengl/impl/x11/X11PbufferGLDrawable.java @@ -166,6 +166,34 @@ public class X11PbufferGLDrawable extends X11GLDrawable { this.display = display; drawable = tmpBuffer; this.fbConfig = fbConfig; + + // Pick innocent query values if multisampling or floating point buffers not available + int sbAttrib = X11GLDrawableFactory.isMultisampleAvailable() ? GLXExt.GLX_SAMPLE_BUFFERS_ARB : GLX.GLX_RED_SIZE; + int samplesAttrib = X11GLDrawableFactory.isMultisampleAvailable() ? GLXExt.GLX_SAMPLES_ARB : GLX.GLX_RED_SIZE; + int floatNV = capabilities.getPbufferFloatingPointBuffers() ? GLX.GLX_FLOAT_COMPONENTS_NV : GLX.GLX_RED_SIZE; + + // Query the fbconfig to determine its GLCapabilities + int[] iattribs = { + GLX.GLX_DOUBLEBUFFER, + GLX.GLX_STEREO, + GLX.GLX_RED_SIZE, + GLX.GLX_GREEN_SIZE, + GLX.GLX_BLUE_SIZE, + GLX.GLX_ALPHA_SIZE, + GLX.GLX_DEPTH_SIZE, + GLX.GLX_STENCIL_SIZE, + GLX.GLX_ACCUM_RED_SIZE, + GLX.GLX_ACCUM_GREEN_SIZE, + GLX.GLX_ACCUM_BLUE_SIZE, + GLX.GLX_ACCUM_ALPHA_SIZE, + sbAttrib, + samplesAttrib, + floatNV + }; + + int[] ivalues = new int[iattribs.length]; + queryFBConfig(display, fbConfig, iattribs, iattribs.length, ivalues); + setChosenGLCapabilities(X11GLDrawableFactory.attribList2GLCapabilities(iattribs, iattribs.length, ivalues, true)); // Determine the actual width and height we were able to create. int[] tmp = new int[1]; @@ -198,4 +226,14 @@ public class X11PbufferGLDrawable extends X11GLDrawable { } return tmp[0]; } + + private void queryFBConfig(long display, GLXFBConfig fbConfig, int[] attribs, int nattribs, int[] values) { + int[] tmp = new int[1]; + for (int i = 0; i < nattribs; i++) { + if (GLX.glXGetFBConfigAttrib(display, fbConfig, attribs[i], tmp, 0) != 0) { + throw new GLException("glXGetFBConfigAttrib failed"); + } + values[i] = tmp[0]; + } + } } diff --git a/src/classes/javax/media/opengl/GLCanvas.java b/src/classes/javax/media/opengl/GLCanvas.java index 83072ffc5..3848cca2c 100644 --- a/src/classes/javax/media/opengl/GLCanvas.java +++ b/src/classes/javax/media/opengl/GLCanvas.java @@ -245,6 +245,13 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction); } + public GLCapabilities getChosenGLCapabilities() { + if (drawable == null) + return null; + + return drawable.getChosenGLCapabilities(); + } + //---------------------------------------------------------------------- // Internals only below this point // diff --git a/src/classes/javax/media/opengl/GLDrawable.java b/src/classes/javax/media/opengl/GLDrawable.java index 13b905167..6c0178474 100644 --- a/src/classes/javax/media/opengl/GLDrawable.java +++ b/src/classes/javax/media/opengl/GLDrawable.java @@ -119,4 +119,14 @@ public interface GLDrawable { is enabled (as is the default), this method is called automatically and should not be called by the end user. */ public void swapBuffers() throws GLException; + + /** Fetches the {@link GLCapabilities} corresponding to the chosen + OpenGL capabilities (pixel format / visual) for this drawable. + Some drawables, in particular on-screen drawables, may be + created lazily; null is returned if the drawable is not + currently created or if its pixel format has not been set yet. + On some platforms, the pixel format is not directly associated + with the drawable; a best attempt is made to return a reasonable + value in this case. */ + public GLCapabilities getChosenGLCapabilities(); } diff --git a/src/classes/javax/media/opengl/GLJPanel.java b/src/classes/javax/media/opengl/GLJPanel.java index e69c03c2f..3340c75d4 100644 --- a/src/classes/javax/media/opengl/GLJPanel.java +++ b/src/classes/javax/media/opengl/GLJPanel.java @@ -793,6 +793,23 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { return oglPipelineEnabled; } + public GLCapabilities getChosenGLCapabilities() { + if (oglPipelineEnabled) { + // FIXME: should do better than this; is it possible to using only platform-independent code? + return new GLCapabilities(); + } + + if (hardwareAccelerationDisabled) { + if (offscreenDrawable != null) + return offscreenDrawable.getChosenGLCapabilities(); + } else { + if (pbuffer != null) + return pbuffer.getChosenGLCapabilities(); + } + + return null; + } + //---------------------------------------------------------------------- // Internals only below this point // diff --git a/src/native/jogl/MacOSXWindowSystemInterface.m b/src/native/jogl/MacOSXWindowSystemInterface.m index e9d90fcdc..5cf975c10 100644 --- a/src/native/jogl/MacOSXWindowSystemInterface.m +++ b/src/native/jogl/MacOSXWindowSystemInterface.m @@ -379,33 +379,110 @@ long validateParameter(NSOpenGLPixelFormatAttribute atttribute, long value) return value; } -void* createContext(void* shareContext, void* view, - int doubleBuffer, - int stereo, - int redBits, - int greenBits, - int blueBits, - int alphaBits, - int depthBits, - int stencilBits, - int accumRedBits, - int accumGreenBits, - int accumBlueBits, - int accumAlphaBits, - int sampleBuffers, - int numSamples, - int pbuffer, - int floatingPoint, +void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + getRendererInfo(); + + // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSOpenGLPixelFormat.html + NSOpenGLPixelFormatAttribute attribs[256]; + + int idx = 0; + int i; + for (i = 0; i < niattrs; i++) { + int attr = iattrs[i]; + switch (attr) { + case NSOpenGLPFAPixelBuffer: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAPixelBuffer; + } + break; + + case kCGLPFAColorFloat: + if (ivalues[i] != 0) { + attribs[idx++] = kCGLPFAColorFloat; + } + break; + + case NSOpenGLPFADoubleBuffer: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFADoubleBuffer; + } + break; + + case NSOpenGLPFAStereo: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAStereo; + } + break; + + case NSOpenGLPFAColorSize: + case NSOpenGLPFAAlphaSize: + case NSOpenGLPFADepthSize: + case NSOpenGLPFAAccumSize: + case NSOpenGLPFASampleBuffers: + case NSOpenGLPFASamples: + attribs[idx++] = attr; + attribs[idx++] = ivalues[i]; + break; + + case NSOpenGLPFAStencilSize: + attribs[idx++] = attr; + attribs[idx++] = validateParameter(NSOpenGLPFAStencilSize, ivalues[i]); + break; + + default: + // Need better way to signal to caller + return nil; + } + } + + // Zero-terminate + attribs[idx++] = 0; + + NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + if (fmt == nil) { + // should we fallback to defaults or not? + fmt = [NSOpenGLView defaultPixelFormat]; + } + + [pool release]; + return fmt; +} + +void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; + long tmp; + // FIXME: think about how specifying this might affect the API + int virtualScreen = 0; + + int i; + for (i = 0; i < niattrs; i++) { + [fmt getValues: &tmp + forAttribute: (NSOpenGLPixelFormatAttribute) iattrs[i] + forVirtualScreen: virtualScreen]; + ivalues[i] = (int) tmp; + } + [pool release]; +} + +void deletePixelFormat(void* pixelFormat) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; + [fmt release]; + [pool release]; +} + +void* createContext(void* shareContext, + void* view, + void* pixelFormat, int* viewNotReady) { getRendererInfo(); - int colorSize = alphaBits + redBits + greenBits + blueBits; - int accumSize = accumAlphaBits + accumRedBits + accumGreenBits + accumBlueBits; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLContext *nsChareCtx = (NSOpenGLContext*)shareContext; NSView *nsView = (NSView*)view; if (nsView != NULL) @@ -438,47 +515,10 @@ void* createContext(void* shareContext, void* view, return NULL; } } - - // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSOpenGLPixelFormat.html - NSOpenGLPixelFormatAttribute attribs[256]; - int idx = 0; - if (pbuffer != 0) - { - attribs[idx++] = NSOpenGLPFAPixelBuffer; - } - if (floatingPoint != 0) - { - attribs[idx++] = kCGLPFAColorFloat /* NSOpenGLPFAColorFloat */; - } - if (doubleBuffer != 0) - { - attribs[idx++] = NSOpenGLPFADoubleBuffer; - } - if (stereo != 0) - { - attribs[idx++] = NSOpenGLPFAStereo; - } - attribs[idx++] = NSOpenGLPFAColorSize; attribs[idx++] = colorSize; - attribs[idx++] = NSOpenGLPFAAlphaSize; attribs[idx++] = alphaBits; - attribs[idx++] = NSOpenGLPFADepthSize; attribs[idx++] = depthBits; - attribs[idx++] = NSOpenGLPFAStencilSize; attribs[idx++] = validateParameter(NSOpenGLPFAStencilSize, stencilBits); - attribs[idx++] = NSOpenGLPFAAccumSize; attribs[idx++] = accumSize; - if (sampleBuffers != 0) - { - attribs[idx++] = NSOpenGLPFASampleBuffers; attribs[idx++] = sampleBuffers; - attribs[idx++] = NSOpenGLPFASamples; attribs[idx++] = numSamples; - } - attribs[idx++] = 0; - - NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - if (fmt == nil) - { - // should we fallback to defaults or not? - fmt = [NSOpenGLView defaultPixelFormat]; - } - NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nsChareCtx]; - [fmt release]; + NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] + initWithFormat: (NSOpenGLPixelFormat*) pixelFormat + shareContext: (NSOpenGLContext*) shareContext]; if (nsView != nil) { |