diff options
Diffstat (limited to 'src/net/java/games/jogl/impl/windows')
9 files changed, 1366 insertions, 1119 deletions
diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java index 338b11e6a..44f2894eb 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java @@ -39,19 +39,14 @@ package net.java.games.jogl.impl.windows; -import java.awt.Component; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.Rectangle; import java.util.*; import net.java.games.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public abstract class WindowsGLContext extends GLContextImpl { - private static JAWT jawt; + protected WindowsGLDrawable drawable; protected long hglrc; - protected long hdc; private boolean wglGetExtensionsStringEXTInitialized; private boolean wglGetExtensionsStringEXTAvailable; private static final Map/*<String, String>*/ functionNameMap; @@ -63,9 +58,6 @@ public abstract class WindowsGLContext extends GLContextImpl { private long hglu32; private boolean haveWGLARBPbuffer = true; - private static final int MAX_PFORMATS = 256; - private static final int MAX_ATTRIBS = 256; - static { functionNameMap = new HashMap(); functionNameMap.put("glAllocateMemoryNV", "wglAllocateMemoryNV"); @@ -76,11 +68,10 @@ public abstract class WindowsGLContext extends GLContextImpl { extensionNameMap.put("GL_ARB_pixel_format", "WGL_ARB_pixel_format"); } - public WindowsGLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public WindowsGLContext(WindowsGLDrawable drawable, GLContext shareWith) { - super(component, capabilities, chooser, shareWith); + super(shareWith); + this.drawable = drawable; } protected GL createGL() @@ -104,16 +95,6 @@ public abstract class WindowsGLContext 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,7 +107,32 @@ public abstract class WindowsGLContext extends GLContextImpl { * Creates and initializes an appropriate OpenGL context. Should only be * called by {@link #makeCurrentImpl()}. */ - protected abstract void create(); + protected void create() { + if (drawable.getHDC() == 0) { + throw new GLException("Internal error: attempted to create OpenGL context without an associated drawable"); + } + hglrc = WGL.wglCreateContext(drawable.getHDC()); + if (hglrc == 0) { + throw new GLException("Unable to create OpenGL context"); + } + // Windows can set up sharing of display lists after creation time + WindowsGLContext other = (WindowsGLContext) GLContextShareSet.getShareContext(this); + if (other != null) { + long hglrc2 = other.getHGLRC(); + if (hglrc2 == 0) { + throw new GLException("GLContextShareSet returned an invalid OpenGL context"); + } + if (!WGL.wglShareLists(hglrc2, hglrc)) { + throw new GLException("wglShareLists(0x" + Long.toHexString(hglrc2) + + ", 0x" + Long.toHexString(hglrc) + ") failed: error code " + + WGL.GetLastError()); + } + } + GLContextShareSet.contextCreated(this); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Created OpenGL context " + toHexString(hglrc) + " for " + this + ", device context " + toHexString(drawable.getHDC())); + } + } protected int makeCurrentImpl() throws GLException { boolean created = false; @@ -149,12 +155,12 @@ public abstract class WindowsGLContext extends GLContextImpl { } if (!skipMakeCurrent) { - if (!WGL.wglMakeCurrent(hdc, hglrc)) { + if (!WGL.wglMakeCurrent(drawable.getHDC(), hglrc)) { throw new GLException("Error making context current: " + WGL.GetLastError()); } else { if (DEBUG && VERBOSE) { - System.err.println(getThreadName() + ": wglMakeCurrent(hdc " + hdcToString(hdc) + - ", hglrc " + hdcToString(hglrc) + ") succeeded"); + System.err.println(getThreadName() + ": wglMakeCurrent(hdc " + toHexString(drawable.getHDC()) + + ", hglrc " + toHexString(hglrc) + ") succeeded"); } } } @@ -163,20 +169,6 @@ public abstract class WindowsGLContext extends GLContextImpl { resetGLFunctionAvailability(); haveWGLARBPbuffer = (isExtensionAvailable("WGL_ARB_pbuffer") && isExtensionAvailable("WGL_ARB_pixel_format")); - // Windows can set up sharing of display lists after creation time - WindowsGLContext other = (WindowsGLContext) GLContextShareSet.getShareContext(this); - if (other != null) { - long hglrc2 = other.getHGLRC(); - if (hglrc2 == 0) { - throw new GLException("GLContextShareSet returned an invalid OpenGL context"); - } - if (!WGL.wglShareLists(hglrc2, hglrc)) { - throw new GLException("wglShareLists(0x" + Long.toHexString(hglrc2) + - ", 0x" + Long.toHexString(hglrc) + ") failed: error code " + - WGL.GetLastError()); - } - } - GLContextShareSet.contextCreated(this); return CONTEXT_CURRENT_NEW; } return CONTEXT_CURRENT; @@ -195,15 +187,14 @@ public abstract class WindowsGLContext extends GLContextImpl { if (!WGL.wglDeleteContext(hglrc)) { throw new GLException("Unable to delete OpenGL context"); } + hglrc = 0; + GLContextShareSet.contextDestroyed(this); if (DEBUG) { - System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + hglrc); + System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + toHexString(hglrc)); } - hglrc = 0; } } - public abstract void swapBuffers() throws GLException; - protected long dynamicLookupFunction(String glFuncName) { long res = WGL.wglGetProcAddress(glFuncName); if (res == 0) { @@ -272,444 +263,10 @@ public abstract class WindowsGLContext extends GLContextImpl { // Internals only below this point // - protected JAWT getJAWT() { - if (jawt == null) { - JAWT j = new JAWT(); - j.version(JAWTFactory.JAWT_VERSION_1_4); - if (!JAWTFactory.JAWT_GetAWT(j)) { - throw new RuntimeException("Unable to initialize JAWT"); - } - jawt = j; - } - return jawt; - } - - // Helper routine for the overridden create() to call - protected void choosePixelFormatAndCreateContext(boolean onscreen) { - PIXELFORMATDESCRIPTOR pfd = null; - int pixelFormat = 0; - if (onscreen) { - GLCapabilities[] availableCaps = null; - int numFormats = 0; - pfd = newPixelFormatDescriptor(); - GraphicsConfiguration config = component.getGraphicsConfiguration(); - GraphicsDevice device = config.getDevice(); - // Produce a recommended pixel format selection for the GLCapabilitiesChooser. - // Use wglChoosePixelFormatARB if user requested multisampling and if we have it available - GL dummyGL = null; - if (capabilities.getSampleBuffers()) { - dummyGL = WindowsGLContextFactory.getDummyGL(device); - } - int recommendedPixelFormat = -1; - boolean haveWGLChoosePixelFormatARB = false; - boolean haveWGLARBMultisample = false; - if (dummyGL != null) { - String availableWGLExtensions = WindowsGLContextFactory.getDummyGLExtensions(device); - if (availableWGLExtensions.indexOf("WGL_ARB_pixel_format") >= 0) { - haveWGLChoosePixelFormatARB = true; - if (availableWGLExtensions.indexOf("WGL_ARB_multisample") >= 0) { - haveWGLARBMultisample = true; - } - } - } - Rectangle rect = config.getBounds(); - long dc = 0; - long rc = 0; - boolean freeWGLC = false; - if( dummyGL != null ) { - dc = WindowsGLContextFactory.getDummyGLContext( device ).hdc; - rc = WindowsGLContextFactory.getDummyGLContext( device ).hglrc; - if( !WGL.wglMakeCurrent( dc, rc ) ) { - System.err.println(getThreadName() + ": Error Making WGLC Current: " + WGL.GetLastError() ); - } else { - freeWGLC = true; - } - } - // Fallback path for older cards, in particular Intel Extreme motherboard graphics - boolean gotAvailableCaps = false; - if (dummyGL != null && haveWGLChoosePixelFormatARB) { - int[] iattributes = new int [2 * MAX_ATTRIBS]; - int[] iresults = new int [2 * MAX_ATTRIBS]; - float[] fattributes = new float[2 * MAX_ATTRIBS]; - int niattribs = 0; - int nfattribs = 0; - iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - iattributes[niattribs++] = GL.WGL_DRAW_TO_WINDOW_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; - iattributes[niattribs++] = GL.WGL_TYPE_RGBA_ARB; - iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; - if (capabilities.getDoubleBuffered()) { - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = GL.GL_FALSE; - } - iattributes[niattribs++] = GL.WGL_STEREO_ARB; - if (capabilities.getStereo()) { - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = GL.GL_FALSE; - } - iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; - iattributes[niattribs++] = capabilities.getDepthBits(); - iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; - iattributes[niattribs++] = capabilities.getRedBits(); - iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; - iattributes[niattribs++] = capabilities.getGreenBits(); - iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; - iattributes[niattribs++] = capabilities.getBlueBits(); - iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; - iattributes[niattribs++] = capabilities.getAlphaBits(); - iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; - iattributes[niattribs++] = capabilities.getStencilBits(); - if (capabilities.getAccumRedBits() > 0 || - capabilities.getAccumGreenBits() > 0 || - capabilities.getAccumBlueBits() > 0 || - capabilities.getAccumAlphaBits() > 0) { - iattributes[niattribs++] = GL.WGL_ACCUM_BITS_ARB; - iattributes[niattribs++] = (capabilities.getAccumRedBits() + - capabilities.getAccumGreenBits() + - capabilities.getAccumBlueBits() + - capabilities.getAccumAlphaBits()); - iattributes[niattribs++] = GL.WGL_ACCUM_RED_BITS_ARB; - iattributes[niattribs++] = capabilities.getAccumRedBits(); - iattributes[niattribs++] = GL.WGL_ACCUM_GREEN_BITS_ARB; - iattributes[niattribs++] = capabilities.getAccumGreenBits(); - iattributes[niattribs++] = GL.WGL_ACCUM_BLUE_BITS_ARB; - iattributes[niattribs++] = capabilities.getAccumBlueBits(); - iattributes[niattribs++] = GL.WGL_ACCUM_ALPHA_BITS_ARB; - iattributes[niattribs++] = capabilities.getAccumAlphaBits(); - } - if (haveWGLARBMultisample) { - if (capabilities.getSampleBuffers()) { - iattributes[niattribs++] = GL.WGL_SAMPLE_BUFFERS_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - iattributes[niattribs++] = GL.WGL_SAMPLES_ARB; - iattributes[niattribs++] = capabilities.getNumSamples(); - } - } - - int[] pformats = new int[MAX_PFORMATS]; - int[] numFormatsTmp = new int[1]; - if (dummyGL.wglChoosePixelFormatARB(hdc, - iattributes, 0, - fattributes, 0, - MAX_PFORMATS, - pformats, 0, - numFormatsTmp, 0)) { - numFormats = numFormatsTmp[0]; - if (numFormats > 0) { - // Remove one-basing of pixel format (added on later) - recommendedPixelFormat = pformats[0] - 1; - if (DEBUG) { - System.err.println(getThreadName() + ": Used wglChoosePixelFormatARB to recommend pixel format " + recommendedPixelFormat); - } - } - } else { - if (DEBUG) { - System.err.println(getThreadName() + ": wglChoosePixelFormatARB failed: " + WGL.GetLastError() ); - Thread.dumpStack(); - } - } - if (DEBUG) { - if (recommendedPixelFormat < 0) { - System.err.print(getThreadName() + ": wglChoosePixelFormatARB didn't recommend a pixel format"); - if (capabilities.getSampleBuffers()) { - System.err.print(" for multisampled GLCapabilities"); - } - System.err.println(); - } - } - - // Produce a list of GLCapabilities to give to the - // GLCapabilitiesChooser. - // Use wglGetPixelFormatAttribivARB instead of - // DescribePixelFormat to get higher-precision information - // about the pixel format (should make the GLCapabilities - // more precise as well...i.e., remove the - // "HardwareAccelerated" bit, which is basically - // meaningless, and put in whether it can render to a - // window, to a pbuffer, or to a pixmap) - niattribs = 0; - iattributes[0] = GL.WGL_NUMBER_PIXEL_FORMATS_ARB; - if (dummyGL.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, 0, iresults, 0)) { - numFormats = iresults[0]; - // Should we be filtering out the pixel formats which aren't - // applicable, as we are doing here? - // We don't have enough information in the GLCapabilities to - // represent those that aren't... - iattributes[niattribs++] = GL.WGL_DRAW_TO_WINDOW_ARB; - iattributes[niattribs++] = GL.WGL_ACCELERATION_ARB; - iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; - iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; - iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; - iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; - iattributes[niattribs++] = GL.WGL_STEREO_ARB; - iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; - iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; - iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; - iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; - iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; - iattributes[niattribs++] = GL.WGL_ACCUM_RED_BITS_ARB; - iattributes[niattribs++] = GL.WGL_ACCUM_GREEN_BITS_ARB; - iattributes[niattribs++] = GL.WGL_ACCUM_BLUE_BITS_ARB; - iattributes[niattribs++] = GL.WGL_ACCUM_ALPHA_BITS_ARB; - if (haveWGLARBMultisample) { - iattributes[niattribs++] = GL.WGL_SAMPLE_BUFFERS_ARB; - iattributes[niattribs++] = GL.WGL_SAMPLES_ARB; - } - - availableCaps = new GLCapabilities[numFormats]; - for (int i = 0; i < numFormats; i++) { - if (!dummyGL.wglGetPixelFormatAttribivARB(hdc, i+1, 0, niattribs, iattributes, 0, iresults, 0)) { - throw new GLException("Error getting pixel format attributes for pixel format " + (i + 1) + " of device context"); - } - availableCaps[i] = iattributes2GLCapabilities(iattributes, iresults, niattribs, true); - } - if( freeWGLC ) { - WGL.wglMakeCurrent( 0, 0 ); - } - gotAvailableCaps = true; - } else { - int lastErr = WGL.GetLastError(); - // Intel Extreme graphics fails with a zero error code - if (lastErr != 0) { - throw new GLException("Unable to enumerate pixel formats of window using wglGetPixelFormatAttribivARB: error code " + WGL.GetLastError()); - } - } - } - - if (!gotAvailableCaps) { - if (DEBUG) { - if (!capabilities.getSampleBuffers()) { - System.err.println(getThreadName() + ": Using ChoosePixelFormat because multisampling not requested"); - } else { - System.err.println(getThreadName() + ": Using ChoosePixelFormat because no wglChoosePixelFormatARB: dummyGL = " + dummyGL); - } - } - pfd = glCapabilities2PFD(capabilities, onscreen); - // Remove one-basing of pixel format (added on later) - recommendedPixelFormat = WGL.ChoosePixelFormat(hdc, pfd) - 1; - - numFormats = WGL.DescribePixelFormat(hdc, 1, 0, null); - if (numFormats == 0) { - throw new GLException("Unable to enumerate pixel formats of window for GLCapabilitiesChooser"); - } - availableCaps = new GLCapabilities[numFormats]; - for (int i = 0; i < numFormats; i++) { - if (WGL.DescribePixelFormat(hdc, 1 + i, pfd.size(), pfd) == 0) { - throw new GLException("Error describing pixel format " + (1 + i) + " of device context"); - } - availableCaps[i] = pfd2GLCapabilities(pfd); - } - } - - // Supply information to chooser - pixelFormat = chooser.chooseCapabilities(capabilities, availableCaps, recommendedPixelFormat); - if ((pixelFormat < 0) || (pixelFormat >= numFormats)) { - throw new GLException("Invalid result " + pixelFormat + - " from GLCapabilitiesChooser (should be between 0 and " + - (numFormats - 1) + ")"); - } - if (DEBUG) { - System.err.println(getThreadName() + ": Chosen pixel format (" + pixelFormat + "):"); - System.err.println(availableCaps[pixelFormat]); - } - pixelFormat += 1; // one-base the index - if (WGL.DescribePixelFormat(hdc, pixelFormat, pfd.size(), pfd) == 0) { - throw new GLException("Error re-describing the chosen pixel format: " + WGL.GetLastError()); - } - } else { - // For now, use ChoosePixelFormat for offscreen surfaces until - // we figure out how to properly choose an offscreen- - // compatible pixel format - pfd = glCapabilities2PFD(capabilities, onscreen); - pixelFormat = WGL.ChoosePixelFormat(hdc, pfd); - } - if (!WGL.SetPixelFormat(hdc, pixelFormat, pfd)) { - int lastError = WGL.GetLastError(); - if (DEBUG) { - System.err.println(getThreadName() + ": SetPixelFormat failed: current context = " + WGL.wglGetCurrentContext() + - ", current DC = " + WGL.wglGetCurrentDC()); - System.err.println(getThreadName() + ": GetPixelFormat(hdc " + hdcToString(hdc) + ") returns " + WGL.GetPixelFormat(hdc)); - } - throw new GLException("Unable to set pixel format " + pixelFormat + " for device context " + hdcToString(hdc) + ": error code " + lastError); - } - hglrc = WGL.wglCreateContext(hdc); - if (DEBUG) { - System.err.println(getThreadName() + ": !!! Created OpenGL context " + hglrc + " for device context " + hdcToString(hdc) + " using pixel format " + pixelFormat); - } - if (hglrc == 0) { - throw new GLException("Unable to create OpenGL context"); - } - } - protected long getHGLRC() { return hglrc; } - static PIXELFORMATDESCRIPTOR glCapabilities2PFD(GLCapabilities caps, boolean onscreen) { - int colorDepth = (caps.getRedBits() + - caps.getGreenBits() + - caps.getBlueBits()); - if (colorDepth < 15) { - throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported"); - } - PIXELFORMATDESCRIPTOR pfd = newPixelFormatDescriptor(); - int pfdFlags = (WGL.PFD_SUPPORT_OPENGL | - WGL.PFD_GENERIC_ACCELERATED); - if (caps.getDoubleBuffered()) { - pfdFlags |= WGL.PFD_DOUBLEBUFFER; - } - if (onscreen) { - pfdFlags |= WGL.PFD_DRAW_TO_WINDOW; - } else { - pfdFlags |= WGL.PFD_DRAW_TO_BITMAP; - } - pfd.dwFlags(pfdFlags); - pfd.iPixelType((byte) WGL.PFD_TYPE_RGBA); - pfd.cColorBits((byte) colorDepth); - pfd.cRedBits ((byte) caps.getRedBits()); - pfd.cGreenBits((byte) caps.getGreenBits()); - pfd.cBlueBits ((byte) caps.getBlueBits()); - pfd.cAlphaBits((byte) caps.getAlphaBits()); - int accumDepth = (caps.getAccumRedBits() + - caps.getAccumGreenBits() + - caps.getAccumBlueBits()); - pfd.cAccumBits ((byte) accumDepth); - pfd.cAccumRedBits ((byte) caps.getAccumRedBits()); - pfd.cAccumGreenBits((byte) caps.getAccumGreenBits()); - pfd.cAccumBlueBits ((byte) caps.getAccumBlueBits()); - pfd.cAccumAlphaBits((byte) caps.getAccumAlphaBits()); - pfd.cDepthBits((byte) caps.getDepthBits()); - pfd.cStencilBits((byte) caps.getStencilBits()); - pfd.iLayerType((byte) WGL.PFD_MAIN_PLANE); - return pfd; - } - - static PIXELFORMATDESCRIPTOR newPixelFormatDescriptor() { - PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR(); - pfd.nSize((short) pfd.size()); - pfd.nVersion((short) 1); - return pfd; - } - - static GLCapabilities pfd2GLCapabilities(PIXELFORMATDESCRIPTOR pfd) { - if ((pfd.dwFlags() & WGL.PFD_SUPPORT_OPENGL) == 0) { - return null; - } - GLCapabilities res = new GLCapabilities(); - res.setRedBits (pfd.cRedBits()); - res.setGreenBits (pfd.cGreenBits()); - res.setBlueBits (pfd.cBlueBits()); - res.setAlphaBits (pfd.cAlphaBits()); - res.setAccumRedBits (pfd.cAccumRedBits()); - res.setAccumGreenBits(pfd.cAccumGreenBits()); - res.setAccumBlueBits (pfd.cAccumBlueBits()); - res.setAccumAlphaBits(pfd.cAccumAlphaBits()); - res.setDepthBits (pfd.cDepthBits()); - res.setStencilBits (pfd.cStencilBits()); - res.setDoubleBuffered((pfd.dwFlags() & WGL.PFD_DOUBLEBUFFER) != 0); - res.setStereo ((pfd.dwFlags() & WGL.PFD_STEREO) != 0); - res.setHardwareAccelerated(((pfd.dwFlags() & WGL.PFD_GENERIC_FORMAT) == 0) || - ((pfd.dwFlags() & WGL.PFD_GENERIC_ACCELERATED) != 0)); - return res; - } - - static GLCapabilities iattributes2GLCapabilities(int[] iattribs, - int[] iresults, - int niattribs, - boolean requireRenderToWindow) { - GLCapabilities res = new GLCapabilities(); - for (int i = 0; i < niattribs; i++) { - switch (iattribs[i]) { - case GL.WGL_DRAW_TO_WINDOW_ARB: - if (iresults[i] != GL.GL_TRUE) - return null; - break; - - case GL.WGL_ACCELERATION_ARB: - res.setHardwareAccelerated(iresults[i] == GL.WGL_FULL_ACCELERATION_ARB); - break; - - case GL.WGL_SUPPORT_OPENGL_ARB: - if (iresults[i] != GL.GL_TRUE) - return null; - break; - - case GL.WGL_DEPTH_BITS_ARB: - res.setDepthBits(iresults[i]); - break; - - case GL.WGL_STENCIL_BITS_ARB: - res.setStencilBits(iresults[i]); - break; - - case GL.WGL_DOUBLE_BUFFER_ARB: - res.setDoubleBuffered(iresults[i] == GL.GL_TRUE); - break; - - case GL.WGL_STEREO_ARB: - res.setStereo(iresults[i] == GL.GL_TRUE); - break; - - case GL.WGL_PIXEL_TYPE_ARB: - if (iresults[i] != GL.WGL_TYPE_RGBA_ARB) - return null; - break; - - case GL.WGL_RED_BITS_ARB: - res.setRedBits(iresults[i]); - break; - - case GL.WGL_GREEN_BITS_ARB: - res.setGreenBits(iresults[i]); - break; - - case GL.WGL_BLUE_BITS_ARB: - res.setBlueBits(iresults[i]); - break; - - case GL.WGL_ALPHA_BITS_ARB: - res.setAlphaBits(iresults[i]); - break; - - case GL.WGL_ACCUM_RED_BITS_ARB: - res.setAccumRedBits(iresults[i]); - break; - - case GL.WGL_ACCUM_GREEN_BITS_ARB: - res.setAccumGreenBits(iresults[i]); - break; - - case GL.WGL_ACCUM_BLUE_BITS_ARB: - res.setAccumBlueBits(iresults[i]); - break; - - case GL.WGL_ACCUM_ALPHA_BITS_ARB: - res.setAccumAlphaBits(iresults[i]); - break; - - case GL.WGL_SAMPLE_BUFFERS_ARB: - res.setSampleBuffers(iresults[i] == GL.GL_TRUE); - break; - - case GL.WGL_SAMPLES_ARB: - res.setNumSamples(iresults[i]); - break; - - default: - throw new GLException("Unknown pixel format attribute " + iattribs[i]); - } - } - return res; - } - - protected static String hdcToString(long hdc) { - return "0x" + Long.toHexString(hdc); - } - protected boolean haveWGLARBPbuffer() { return haveWGLARBPbuffer; } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java index dd6f8daca..d99554fcf 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java @@ -59,6 +59,10 @@ public class WindowsGLContextFactory extends GLContextFactory { private static final boolean DEBUG = Debug.debug("WindowsGLContextFactory"); private static final boolean VERBOSE = Debug.verbose(); + static { + NativeLibLoader.load(); + } + // On Windows we want to be able to use some extension routines like // wglChoosePixelFormatARB during the creation of the user's first // GLContext. However, this and other routines' function pointers @@ -139,17 +143,31 @@ public class WindowsGLContextFactory extends GLContextFactory { return null; } - public GLContext createGLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, - GLContext shareWith) { - if (component != null) { - return new WindowsOnscreenGLContext(component, capabilities, chooser, shareWith); - } else { - return new WindowsOffscreenGLContext(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 WindowsOnscreenGLDrawable((Component) target, capabilities, chooser); } - + + public GLDrawableImpl createOffscreenDrawable(GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + return new WindowsOffscreenGLDrawable(capabilities, chooser); + } + + // Return cached GL drawable + public static WindowsGLDrawable getDummyGLDrawable( final GraphicsDevice device ) { + checkForDummyContext( device ); + NativeWindowStruct nws = (NativeWindowStruct) dummyContextMap.get(device); + return nws.getWindowsDrawable(); + } + // Return cached GL context public static WindowsGLContext getDummyGLContext( final GraphicsDevice device ) { checkForDummyContext( device ); @@ -188,7 +206,9 @@ public class WindowsGLContextFactory extends GLContextFactory { GLCapabilities caps = new GLCapabilities(); caps.setDepthBits( 16 ); // Create a context that we use to query pixel formats - WindowsOnscreenGLContext context = new WindowsOnscreenGLContext( null, caps, null, null ); + + WindowsOnscreenGLDrawable drawable = new WindowsOnscreenGLDrawable(null, caps, null); + WindowsOnscreenGLContext context = new WindowsOnscreenGLContext( drawable, null ); // Start a native thread and grab native screen resources from the thread NativeWindowThread nwt = new NativeWindowThread( rect ); nwt.start(); @@ -198,7 +218,7 @@ public class WindowsGLContextFactory extends GLContextFactory { Thread.yield(); } // Choose a hardware accelerated pixel format - PIXELFORMATDESCRIPTOR pfd = context.glCapabilities2PFD( caps, true ); + PIXELFORMATDESCRIPTOR pfd = drawable.glCapabilities2PFD( caps, true ); int pixelFormat = WGL.ChoosePixelFormat( tempHDC, pfd ); if( pixelFormat == 0 ) { System.err.println("Pixel Format is Zero"); @@ -220,6 +240,7 @@ public class WindowsGLContextFactory extends GLContextFactory { // Store native handles for later use NativeWindowStruct nws = new NativeWindowStruct(); nws.setHWND( hWnd ); + nws.setWindowsDrawable( drawable ); nws.setWindowsContext( context ); nws.setWindowThread( nwt ); long currentHDC = WGL.wglGetCurrentDC(); @@ -230,7 +251,7 @@ public class WindowsGLContextFactory extends GLContextFactory { return; } // Grab function pointers - context.hdc = tempHDC; + drawable.hdc = tempHDC; context.hglrc = tempHGLRC; context.resetGLFunctionAvailability(); context.createGL(); @@ -259,6 +280,7 @@ public class WindowsGLContextFactory extends GLContextFactory { */ static class NativeWindowStruct { private long HWND; + private WindowsGLDrawable windowsDrawable; private WindowsGLContext windowsContext; private Thread windowThread; @@ -266,7 +288,7 @@ public class WindowsGLContextFactory extends GLContextFactory { } public long getHDC() { - return( windowsContext.hdc ); + return( windowsDrawable.hdc ); } public long getHGLRC() { @@ -281,10 +303,18 @@ public class WindowsGLContextFactory extends GLContextFactory { return( HWND ); } + public void setWindowsDrawable( WindowsGLDrawable drawable ) { + windowsDrawable = drawable; + } + public void setWindowsContext( WindowsGLContext context ) { windowsContext = context; } + public WindowsGLDrawable getWindowsDrawable() { + return( windowsDrawable ); + } + public WindowsGLContext getWindowsContext() { return( windowsContext ); } @@ -358,4 +388,19 @@ public class WindowsGLContextFactory extends GLContextFactory { } } } + + + static String wglGetLastError() { + int err = WGL.GetLastError(); + String detail = null; + switch (err) { + case WGL.ERROR_INVALID_PIXEL_FORMAT: detail = "ERROR_INVALID_PIXEL_FORMAT"; break; + case WGL.ERROR_NO_SYSTEM_RESOURCES: detail = "ERROR_NO_SYSTEM_RESOURCES"; break; + case WGL.ERROR_INVALID_DATA: detail = "ERROR_INVALID_DATA"; break; + case WGL.ERROR_PROC_NOT_FOUND: detail = "ERROR_PROC_NOT_FOUND"; break; + case WGL.ERROR_INVALID_WINDOW_HANDLE:detail = "ERROR_INVALID_WINDOW_HANDLE"; break; + default: detail = "(Unknown error code " + err + ")"; break; + } + return detail; + } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLDrawable.java b/src/net/java/games/jogl/impl/windows/WindowsGLDrawable.java new file mode 100644 index 000000000..42e83c05d --- /dev/null +++ b/src/net/java/games/jogl/impl/windows/WindowsGLDrawable.java @@ -0,0 +1,497 @@ +/* + * 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.windows; + +import java.awt.Component; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public abstract class WindowsGLDrawable extends GLDrawableImpl { + protected static final boolean DEBUG = Debug.debug("WindowsGLDrawable"); + + protected long hdc; + protected Component component; + protected GLCapabilities capabilities; + protected GLCapabilitiesChooser chooser; + protected boolean pixelFormatChosen; + + protected static final int MAX_PFORMATS = 256; + protected static final int MAX_ATTRIBS = 256; + + public WindowsGLDrawable(Component component, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + this.component = component; + this.capabilities = (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 getHDC() { + return hdc; + } + + public void choosePixelFormat(boolean onscreen) { + PIXELFORMATDESCRIPTOR pfd = null; + int pixelFormat = 0; + if (onscreen) { + GLCapabilities[] availableCaps = null; + int numFormats = 0; + pfd = newPixelFormatDescriptor(); + GraphicsConfiguration config = component.getGraphicsConfiguration(); + GraphicsDevice device = config.getDevice(); + // Produce a recommended pixel format selection for the GLCapabilitiesChooser. + // Use wglChoosePixelFormatARB if user requested multisampling and if we have it available + GL dummyGL = null; + if (capabilities.getSampleBuffers()) { + dummyGL = WindowsGLContextFactory.getDummyGL(device); + } + int recommendedPixelFormat = -1; + boolean haveWGLChoosePixelFormatARB = false; + boolean haveWGLARBMultisample = false; + if (dummyGL != null) { + String availableWGLExtensions = WindowsGLContextFactory.getDummyGLExtensions(device); + if (availableWGLExtensions.indexOf("WGL_ARB_pixel_format") >= 0) { + haveWGLChoosePixelFormatARB = true; + if (availableWGLExtensions.indexOf("WGL_ARB_multisample") >= 0) { + haveWGLARBMultisample = true; + } + } + } + long dc = 0; + long rc = 0; + boolean freeWGLC = false; + if( dummyGL != null ) { + dc = WindowsGLContextFactory.getDummyGLDrawable( device ).hdc; + rc = WindowsGLContextFactory.getDummyGLContext( device ).hglrc; + if( !WGL.wglMakeCurrent( dc, rc ) ) { + System.err.println(getThreadName() + ": Error Making WGLC Current: " + WGL.GetLastError() ); + } else { + freeWGLC = true; + } + } + // Fallback path for older cards, in particular Intel Extreme motherboard graphics + boolean gotAvailableCaps = false; + if (dummyGL != null && haveWGLChoosePixelFormatARB) { + int[] iattributes = new int [2 * MAX_ATTRIBS]; + int[] iresults = new int [2 * MAX_ATTRIBS]; + float[] fattributes = new float[2 * MAX_ATTRIBS]; + int niattribs = 0; + int nfattribs = 0; + iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + iattributes[niattribs++] = GL.WGL_DRAW_TO_WINDOW_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; + iattributes[niattribs++] = GL.WGL_TYPE_RGBA_ARB; + iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; + if (capabilities.getDoubleBuffered()) { + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = GL.GL_FALSE; + } + iattributes[niattribs++] = GL.WGL_STEREO_ARB; + if (capabilities.getStereo()) { + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = GL.GL_FALSE; + } + iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; + iattributes[niattribs++] = capabilities.getDepthBits(); + iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; + iattributes[niattribs++] = capabilities.getRedBits(); + iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; + iattributes[niattribs++] = capabilities.getGreenBits(); + iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; + iattributes[niattribs++] = capabilities.getBlueBits(); + iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; + iattributes[niattribs++] = capabilities.getAlphaBits(); + iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; + iattributes[niattribs++] = capabilities.getStencilBits(); + if (capabilities.getAccumRedBits() > 0 || + capabilities.getAccumGreenBits() > 0 || + capabilities.getAccumBlueBits() > 0 || + capabilities.getAccumAlphaBits() > 0) { + iattributes[niattribs++] = GL.WGL_ACCUM_BITS_ARB; + iattributes[niattribs++] = (capabilities.getAccumRedBits() + + capabilities.getAccumGreenBits() + + capabilities.getAccumBlueBits() + + capabilities.getAccumAlphaBits()); + iattributes[niattribs++] = GL.WGL_ACCUM_RED_BITS_ARB; + iattributes[niattribs++] = capabilities.getAccumRedBits(); + iattributes[niattribs++] = GL.WGL_ACCUM_GREEN_BITS_ARB; + iattributes[niattribs++] = capabilities.getAccumGreenBits(); + iattributes[niattribs++] = GL.WGL_ACCUM_BLUE_BITS_ARB; + iattributes[niattribs++] = capabilities.getAccumBlueBits(); + iattributes[niattribs++] = GL.WGL_ACCUM_ALPHA_BITS_ARB; + iattributes[niattribs++] = capabilities.getAccumAlphaBits(); + } + if (haveWGLARBMultisample) { + if (capabilities.getSampleBuffers()) { + iattributes[niattribs++] = GL.WGL_SAMPLE_BUFFERS_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + iattributes[niattribs++] = GL.WGL_SAMPLES_ARB; + iattributes[niattribs++] = capabilities.getNumSamples(); + } + } + + int[] pformats = new int[MAX_PFORMATS]; + int[] numFormatsTmp = new int[1]; + if (dummyGL.wglChoosePixelFormatARB(hdc, + iattributes, 0, + fattributes, 0, + MAX_PFORMATS, + pformats, 0, + numFormatsTmp, 0)) { + numFormats = numFormatsTmp[0]; + if (numFormats > 0) { + // Remove one-basing of pixel format (added on later) + recommendedPixelFormat = pformats[0] - 1; + if (DEBUG) { + System.err.println(getThreadName() + ": Used wglChoosePixelFormatARB to recommend pixel format " + recommendedPixelFormat); + } + } + } else { + if (DEBUG) { + System.err.println(getThreadName() + ": wglChoosePixelFormatARB failed: " + WGL.GetLastError() ); + Thread.dumpStack(); + } + } + if (DEBUG) { + if (recommendedPixelFormat < 0) { + System.err.print(getThreadName() + ": wglChoosePixelFormatARB didn't recommend a pixel format"); + if (capabilities.getSampleBuffers()) { + System.err.print(" for multisampled GLCapabilities"); + } + System.err.println(); + } + } + + // Produce a list of GLCapabilities to give to the + // GLCapabilitiesChooser. + // Use wglGetPixelFormatAttribivARB instead of + // DescribePixelFormat to get higher-precision information + // about the pixel format (should make the GLCapabilities + // more precise as well...i.e., remove the + // "HardwareAccelerated" bit, which is basically + // meaningless, and put in whether it can render to a + // window, to a pbuffer, or to a pixmap) + niattribs = 0; + iattributes[0] = GL.WGL_NUMBER_PIXEL_FORMATS_ARB; + if (dummyGL.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, 0, iresults, 0)) { + numFormats = iresults[0]; + // Should we be filtering out the pixel formats which aren't + // applicable, as we are doing here? + // We don't have enough information in the GLCapabilities to + // represent those that aren't... + iattributes[niattribs++] = GL.WGL_DRAW_TO_WINDOW_ARB; + iattributes[niattribs++] = GL.WGL_ACCELERATION_ARB; + iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; + iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; + iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; + iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; + iattributes[niattribs++] = GL.WGL_STEREO_ARB; + iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; + iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; + iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; + iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; + iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; + iattributes[niattribs++] = GL.WGL_ACCUM_RED_BITS_ARB; + iattributes[niattribs++] = GL.WGL_ACCUM_GREEN_BITS_ARB; + iattributes[niattribs++] = GL.WGL_ACCUM_BLUE_BITS_ARB; + iattributes[niattribs++] = GL.WGL_ACCUM_ALPHA_BITS_ARB; + if (haveWGLARBMultisample) { + iattributes[niattribs++] = GL.WGL_SAMPLE_BUFFERS_ARB; + iattributes[niattribs++] = GL.WGL_SAMPLES_ARB; + } + + availableCaps = new GLCapabilities[numFormats]; + for (int i = 0; i < numFormats; i++) { + if (!dummyGL.wglGetPixelFormatAttribivARB(hdc, i+1, 0, niattribs, iattributes, 0, iresults, 0)) { + throw new GLException("Error getting pixel format attributes for pixel format " + (i + 1) + " of device context"); + } + availableCaps[i] = iattributes2GLCapabilities(iattributes, iresults, niattribs, true); + } + if( freeWGLC ) { + WGL.wglMakeCurrent( 0, 0 ); + } + gotAvailableCaps = true; + } else { + int lastErr = WGL.GetLastError(); + // Intel Extreme graphics fails with a zero error code + if (lastErr != 0) { + throw new GLException("Unable to enumerate pixel formats of window using wglGetPixelFormatAttribivARB: error code " + WGL.GetLastError()); + } + } + } + + if (!gotAvailableCaps) { + if (DEBUG) { + if (!capabilities.getSampleBuffers()) { + System.err.println(getThreadName() + ": Using ChoosePixelFormat because multisampling not requested"); + } else { + System.err.println(getThreadName() + ": Using ChoosePixelFormat because no wglChoosePixelFormatARB: dummyGL = " + dummyGL); + } + } + pfd = glCapabilities2PFD(capabilities, onscreen); + // Remove one-basing of pixel format (added on later) + recommendedPixelFormat = WGL.ChoosePixelFormat(hdc, pfd) - 1; + + numFormats = WGL.DescribePixelFormat(hdc, 1, 0, null); + if (numFormats == 0) { + throw new GLException("Unable to enumerate pixel formats of window for GLCapabilitiesChooser"); + } + availableCaps = new GLCapabilities[numFormats]; + for (int i = 0; i < numFormats; i++) { + if (WGL.DescribePixelFormat(hdc, 1 + i, pfd.size(), pfd) == 0) { + throw new GLException("Error describing pixel format " + (1 + i) + " of device context"); + } + availableCaps[i] = pfd2GLCapabilities(pfd); + } + } + + // Supply information to chooser + pixelFormat = chooser.chooseCapabilities(capabilities, availableCaps, recommendedPixelFormat); + if ((pixelFormat < 0) || (pixelFormat >= numFormats)) { + throw new GLException("Invalid result " + pixelFormat + + " from GLCapabilitiesChooser (should be between 0 and " + + (numFormats - 1) + ")"); + } + if (DEBUG) { + System.err.println(getThreadName() + ": Chosen pixel format (" + pixelFormat + "):"); + System.err.println(availableCaps[pixelFormat]); + } + pixelFormat += 1; // one-base the index + if (WGL.DescribePixelFormat(hdc, pixelFormat, pfd.size(), pfd) == 0) { + throw new GLException("Error re-describing the chosen pixel format: " + WGL.GetLastError()); + } + } else { + // For now, use ChoosePixelFormat for offscreen surfaces until + // we figure out how to properly choose an offscreen- + // compatible pixel format + pfd = glCapabilities2PFD(capabilities, onscreen); + pixelFormat = WGL.ChoosePixelFormat(hdc, pfd); + } + if (!WGL.SetPixelFormat(hdc, pixelFormat, pfd)) { + int lastError = WGL.GetLastError(); + if (DEBUG) { + System.err.println(getThreadName() + ": SetPixelFormat failed: current context = " + WGL.wglGetCurrentContext() + + ", current DC = " + WGL.wglGetCurrentDC()); + System.err.println(getThreadName() + ": GetPixelFormat(hdc " + toHexString(hdc) + ") returns " + WGL.GetPixelFormat(hdc)); + } + throw new GLException("Unable to set pixel format " + pixelFormat + " for device context " + toHexString(hdc) + ": error code " + lastError); + } + pixelFormatChosen = true; + } + + static PIXELFORMATDESCRIPTOR glCapabilities2PFD(GLCapabilities caps, boolean onscreen) { + int colorDepth = (caps.getRedBits() + + caps.getGreenBits() + + caps.getBlueBits()); + if (colorDepth < 15) { + throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported"); + } + PIXELFORMATDESCRIPTOR pfd = newPixelFormatDescriptor(); + int pfdFlags = (WGL.PFD_SUPPORT_OPENGL | + WGL.PFD_GENERIC_ACCELERATED); + if (caps.getDoubleBuffered()) { + pfdFlags |= WGL.PFD_DOUBLEBUFFER; + } + if (onscreen) { + pfdFlags |= WGL.PFD_DRAW_TO_WINDOW; + } else { + pfdFlags |= WGL.PFD_DRAW_TO_BITMAP; + } + pfd.dwFlags(pfdFlags); + pfd.iPixelType((byte) WGL.PFD_TYPE_RGBA); + pfd.cColorBits((byte) colorDepth); + pfd.cRedBits ((byte) caps.getRedBits()); + pfd.cGreenBits((byte) caps.getGreenBits()); + pfd.cBlueBits ((byte) caps.getBlueBits()); + pfd.cAlphaBits((byte) caps.getAlphaBits()); + int accumDepth = (caps.getAccumRedBits() + + caps.getAccumGreenBits() + + caps.getAccumBlueBits()); + pfd.cAccumBits ((byte) accumDepth); + pfd.cAccumRedBits ((byte) caps.getAccumRedBits()); + pfd.cAccumGreenBits((byte) caps.getAccumGreenBits()); + pfd.cAccumBlueBits ((byte) caps.getAccumBlueBits()); + pfd.cAccumAlphaBits((byte) caps.getAccumAlphaBits()); + pfd.cDepthBits((byte) caps.getDepthBits()); + pfd.cStencilBits((byte) caps.getStencilBits()); + pfd.iLayerType((byte) WGL.PFD_MAIN_PLANE); + return pfd; + } + + static PIXELFORMATDESCRIPTOR newPixelFormatDescriptor() { + PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR(); + pfd.nSize((short) pfd.size()); + pfd.nVersion((short) 1); + return pfd; + } + + static GLCapabilities pfd2GLCapabilities(PIXELFORMATDESCRIPTOR pfd) { + if ((pfd.dwFlags() & WGL.PFD_SUPPORT_OPENGL) == 0) { + return null; + } + GLCapabilities res = new GLCapabilities(); + res.setRedBits (pfd.cRedBits()); + res.setGreenBits (pfd.cGreenBits()); + res.setBlueBits (pfd.cBlueBits()); + res.setAlphaBits (pfd.cAlphaBits()); + res.setAccumRedBits (pfd.cAccumRedBits()); + res.setAccumGreenBits(pfd.cAccumGreenBits()); + res.setAccumBlueBits (pfd.cAccumBlueBits()); + res.setAccumAlphaBits(pfd.cAccumAlphaBits()); + res.setDepthBits (pfd.cDepthBits()); + res.setStencilBits (pfd.cStencilBits()); + res.setDoubleBuffered((pfd.dwFlags() & WGL.PFD_DOUBLEBUFFER) != 0); + res.setStereo ((pfd.dwFlags() & WGL.PFD_STEREO) != 0); + res.setHardwareAccelerated(((pfd.dwFlags() & WGL.PFD_GENERIC_FORMAT) == 0) || + ((pfd.dwFlags() & WGL.PFD_GENERIC_ACCELERATED) != 0)); + return res; + } + + static GLCapabilities iattributes2GLCapabilities(int[] iattribs, + int[] iresults, + int niattribs, + boolean requireRenderToWindow) { + GLCapabilities res = new GLCapabilities(); + for (int i = 0; i < niattribs; i++) { + switch (iattribs[i]) { + case GL.WGL_DRAW_TO_WINDOW_ARB: + if (iresults[i] != GL.GL_TRUE) + return null; + break; + + case GL.WGL_ACCELERATION_ARB: + res.setHardwareAccelerated(iresults[i] == GL.WGL_FULL_ACCELERATION_ARB); + break; + + case GL.WGL_SUPPORT_OPENGL_ARB: + if (iresults[i] != GL.GL_TRUE) + return null; + break; + + case GL.WGL_DEPTH_BITS_ARB: + res.setDepthBits(iresults[i]); + break; + + case GL.WGL_STENCIL_BITS_ARB: + res.setStencilBits(iresults[i]); + break; + + case GL.WGL_DOUBLE_BUFFER_ARB: + res.setDoubleBuffered(iresults[i] == GL.GL_TRUE); + break; + + case GL.WGL_STEREO_ARB: + res.setStereo(iresults[i] == GL.GL_TRUE); + break; + + case GL.WGL_PIXEL_TYPE_ARB: + if (iresults[i] != GL.WGL_TYPE_RGBA_ARB) + return null; + break; + + case GL.WGL_RED_BITS_ARB: + res.setRedBits(iresults[i]); + break; + + case GL.WGL_GREEN_BITS_ARB: + res.setGreenBits(iresults[i]); + break; + + case GL.WGL_BLUE_BITS_ARB: + res.setBlueBits(iresults[i]); + break; + + case GL.WGL_ALPHA_BITS_ARB: + res.setAlphaBits(iresults[i]); + break; + + case GL.WGL_ACCUM_RED_BITS_ARB: + res.setAccumRedBits(iresults[i]); + break; + + case GL.WGL_ACCUM_GREEN_BITS_ARB: + res.setAccumGreenBits(iresults[i]); + break; + + case GL.WGL_ACCUM_BLUE_BITS_ARB: + res.setAccumBlueBits(iresults[i]); + break; + + case GL.WGL_ACCUM_ALPHA_BITS_ARB: + res.setAccumAlphaBits(iresults[i]); + break; + + case GL.WGL_SAMPLE_BUFFERS_ARB: + res.setSampleBuffers(iresults[i] == GL.GL_TRUE); + break; + + case GL.WGL_SAMPLES_ARB: + res.setNumSamples(iresults[i]); + break; + + default: + throw new GLException("Unknown pixel format attribute " + iattribs[i]); + } + } + return res; + } + + protected static String getThreadName() { + return Thread.currentThread().getName(); + } +} diff --git a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java index d944a8684..a2fae5971 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java @@ -39,38 +39,13 @@ package net.java.games.jogl.impl.windows; -import java.awt.image.BufferedImage; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class WindowsOffscreenGLContext extends WindowsGLContext { - private long origbitmap; - private long hbitmap; - // Width and height of the underlying bitmap - private int width; - private int height; - - public WindowsOffscreenGLContext(GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public WindowsOffscreenGLContext(WindowsOffscreenGLDrawable drawable, GLContext shareWith) { - super(null, capabilities, chooser, shareWith); - } - - protected GL createGL() - { - return new WindowsGLImpl(this); - } - - protected boolean isOffscreen() { - return true; - } - - public int getOffscreenContextWidth() { - return width; - } - - public int getOffscreenContextHeight() { - return height; + super(drawable, shareWith); } public int getOffscreenContextPixelDataType() { @@ -92,9 +67,9 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { 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"); } @@ -105,72 +80,4 @@ public class WindowsOffscreenGLContext extends WindowsGLContext { public void releasePbufferFromTexture() { throw new GLException("Should not call this"); } - - protected int makeCurrentImpl() throws GLException { - if (pendingOffscreenResize) { - if (pendingOffscreenWidth != width || pendingOffscreenHeight != height) { - if (hglrc != 0) { - destroyImpl(); - } - width = pendingOffscreenWidth; - height = pendingOffscreenHeight; - pendingOffscreenResize = false; - } - } - return super.makeCurrentImpl(); - } - - protected void destroyImpl() { - if (hglrc != 0) { - super.destroyImpl(); - // Must destroy OpenGL context, bitmap and device context - WGL.SelectObject(hdc, origbitmap); - WGL.DeleteObject(hbitmap); - WGL.DeleteDC(hdc); - origbitmap = 0; - hbitmap = 0; - hdc = 0; - } - } - - public void swapBuffers() throws GLException { - } - - protected void create() { - BITMAPINFO info = new BITMAPINFO(); - BITMAPINFOHEADER header = info.bmiHeader(); - int bitsPerPixel = (capabilities.getRedBits() + - capabilities.getGreenBits() + - capabilities.getBlueBits()); - header.biSize(header.size()); - header.biWidth(width); - // NOTE: negating the height causes the DIB to be in top-down row - // order rather than bottom-up; ends up being correct during pixel - // readback - header.biHeight(-1 * height); - header.biPlanes((short) 1); - header.biBitCount((short) bitsPerPixel); - header.biXPelsPerMeter(0); - header.biYPelsPerMeter(0); - header.biClrUsed(0); - header.biClrImportant(0); - header.biCompression(WGL.BI_RGB); - header.biSizeImage(width * height * bitsPerPixel / 8); - - hdc = WGL.CreateCompatibleDC(0); - if (hdc == 0) { - System.out.println("LastError: " + WGL.GetLastError()); - throw new GLException("Error creating device context for offscreen OpenGL context"); - } - hbitmap = WGL.CreateDIBSection(hdc, info, WGL.DIB_RGB_COLORS, 0, 0, 0); - if (hbitmap == 0) { - throw new GLException("Error creating offscreen bitmap of width " + width + - ", height " + height); - } - if ((origbitmap = WGL.SelectObject(hdc, hbitmap)) == 0) { - throw new GLException("Error selecting bitmap into new device context"); - } - - choosePixelFormatAndCreateContext(false); - } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLDrawable.java b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLDrawable.java new file mode 100644 index 000000000..03d76574a --- /dev/null +++ b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLDrawable.java @@ -0,0 +1,133 @@ +/* + * 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.windows; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class WindowsOffscreenGLDrawable extends WindowsGLDrawable { + private long origbitmap; + private long hbitmap; + // Width and height of the underlying bitmap + private int width; + private int height; + + public WindowsOffscreenGLDrawable(GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + super(null, capabilities, chooser); + } + + public GLContext createContext(GLContext shareWith) { + return new WindowsOffscreenGLContext(this, shareWith); + } + + public void setSize(int newWidth, int newHeight) { + width = newWidth; + height = newHeight; + if (hdc != 0) { + destroy(); + } + create(); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + private void create() { + BITMAPINFO info = new BITMAPINFO(); + BITMAPINFOHEADER header = info.bmiHeader(); + int bitsPerPixel = (capabilities.getRedBits() + + capabilities.getGreenBits() + + capabilities.getBlueBits()); + header.biSize(header.size()); + header.biWidth(width); + // NOTE: negating the height causes the DIB to be in top-down row + // order rather than bottom-up; ends up being correct during pixel + // readback + header.biHeight(-1 * height); + header.biPlanes((short) 1); + header.biBitCount((short) bitsPerPixel); + header.biXPelsPerMeter(0); + header.biYPelsPerMeter(0); + header.biClrUsed(0); + header.biClrImportant(0); + header.biCompression(WGL.BI_RGB); + header.biSizeImage(width * height * bitsPerPixel / 8); + + hdc = WGL.CreateCompatibleDC(0); + if (hdc == 0) { + System.out.println("LastError: " + WGL.GetLastError()); + throw new GLException("Error creating device context for offscreen OpenGL context"); + } + hbitmap = WGL.CreateDIBSection(hdc, info, WGL.DIB_RGB_COLORS, 0, 0, 0); + if (hbitmap == 0) { + WGL.DeleteDC(hdc); + hdc = 0; + throw new GLException("Error creating offscreen bitmap of width " + width + + ", height " + height); + } + if ((origbitmap = WGL.SelectObject(hdc, hbitmap)) == 0) { + WGL.DeleteObject(hbitmap); + hbitmap = 0; + WGL.DeleteDC(hdc); + hdc = 0; + throw new GLException("Error selecting bitmap into new device context"); + } + + choosePixelFormat(false); + } + + public void destroy() { + if (hdc != 0) { + // Must destroy bitmap and device context + WGL.SelectObject(hdc, origbitmap); + WGL.DeleteObject(hbitmap); + WGL.DeleteDC(hdc); + origbitmap = 0; + hbitmap = 0; + hdc = 0; + } + } +} diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java index d4af4b3b7..c71f35ff0 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java @@ -39,68 +39,20 @@ package net.java.games.jogl.impl.windows; -import java.awt.Component; import java.util.*; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class WindowsOnscreenGLContext extends WindowsGLContext { - // Variables for lockSurface/unlockSurface - JAWT_DrawingSurface ds; - JAWT_DrawingSurfaceInfo dsi; - JAWT_Win32DrawingSurfaceInfo win32dsi; - - // 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 WindowsOnscreenGLDrawable drawable; // Variables for pbuffer support - List pbuffersToInstantiate = new ArrayList(); + protected List pbuffersToInstantiate = new ArrayList(); - public WindowsOnscreenGLContext(Component component, - GLCapabilities capabilities, - GLCapabilitiesChooser chooser, + public WindowsOnscreenGLContext(WindowsOnscreenGLDrawable drawable, GLContext shareWith) { - super(component, capabilities, chooser, shareWith); - } - - /* - public void invokeGL(Runnable runnable, boolean isReshape, Runnable initAction) throws GLException { - // Unfortunately, invokeGL can be called with the AWT tree lock - // held, and the Windows onscreen implementation of - // choosePixelFormatAndCreateContext calls - // Component.getGraphicsConfiguration(), which grabs the tree - // lock. To avoid deadlock we have to lock the tree lock before - // grabbing the GLContext's lock if we're going to create an - // OpenGL context during this call. This code might not be - // completely correct, and we might need to uniformly grab the AWT - // tree lock, which might become a performance issue... - if (hglrc == 0) { - synchronized(component.getTreeLock()) { - super.invokeGL(runnable, isReshape, initAction); - } - } else { - super.invokeGL(runnable, isReshape, initAction); - } - } - */ - - protected GL createGL() - { - return new WindowsGLImpl(this); - } - - protected boolean isOffscreen() { - return false; + super(drawable, shareWith); + this.drawable = drawable; } public int getOffscreenContextReadBuffer() { @@ -115,13 +67,12 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { return haveWGLARBPbuffer(); } - public GLContext createPbufferContext(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { - WindowsPbufferGLContext ctx = new WindowsPbufferGLContext(capabilities, initialWidth, initialHeight); - ctx.setSynchronized(true); - pbuffersToInstantiate.add(ctx); - return ctx; + public GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { + WindowsPbufferGLDrawable buf = new WindowsPbufferGLDrawable(capabilities, initialWidth, initialHeight); + pbuffersToInstantiate.add(buf); + return buf; } public void bindPbufferToTexture() { @@ -132,32 +83,47 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { throw new GLException("Should not call this"); } - public void setRealized() { - realized = true; - } - protected int makeCurrentImpl() throws GLException { try { - if (!realized) { + int lockRes = drawable.lockSurface(); + if (lockRes == WindowsOnscreenGLDrawable.LOCK_SURFACE_NOT_READY) { return CONTEXT_NOT_CURRENT; } - if (!lockSurface()) { - return CONTEXT_NOT_CURRENT; + if (lockRes == WindowsOnscreenGLDrawable.LOCK_SURFACE_CHANGED) { + if (hglrc != 0) { + if (!WGL.wglDeleteContext(hglrc)) { + throw new GLException("Unable to delete old GL context after surface changed"); + } + GLContextShareSet.contextDestroyed(this); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + toHexString(hglrc) + " due to JAWT_LOCK_SURFACE_CHANGED"); + } + hglrc = 0; + } } int ret = super.makeCurrentImpl(); if ((ret == CONTEXT_CURRENT) || (ret == CONTEXT_CURRENT_NEW)) { // Instantiate any pending pbuffers - while (!pbuffersToInstantiate.isEmpty()) { - WindowsPbufferGLContext ctx = - (WindowsPbufferGLContext) pbuffersToInstantiate.remove(pbuffersToInstantiate.size() - 1); - ctx.createPbuffer(hdc, hglrc); + // NOTE that we supply the drawable a GL instance for our + // context and that we eliminate all pipelines for it -- see + // WindowsPbufferGLDrawable.destroy() + if (!pbuffersToInstantiate.isEmpty()) { + GL tmpGL = createGL(); + while (!pbuffersToInstantiate.isEmpty()) { + WindowsPbufferGLDrawable buf = + (WindowsPbufferGLDrawable) pbuffersToInstantiate.remove(pbuffersToInstantiate.size() - 1); + buf.createPbuffer(tmpGL, drawable.getHDC()); + 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 } @@ -169,88 +135,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { try { super.releaseImpl(); } finally { - unlockSurface(); - } - } - - protected void destroyImpl() throws GLException { - realized = false; - super.destroyImpl(); - } - - public void swapBuffers() throws GLException { - if (!WGL.SwapBuffers(hdc) && (WGL.GetLastError() != 0)) { - throw new GLException("Error swapping buffers"); + drawable.unlockSurface(); } } - - private boolean lockSurface() throws GLException { - if (hdc != 0) { - throw new GLException("Surface already locked"); - } - ds = getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - return false; - } - 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) - if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { - if (hglrc != 0) { - if (!WGL.wglDeleteContext(hglrc)) { - throw new GLException("Unable to delete old GL context after surface changed"); - } - GLContextShareSet.contextDestroyed(this); - if (DEBUG) { - System.err.println(getThreadName() + ": !!! Destroyed OpenGL context " + hglrc + " due to JAWT_LOCK_SURFACE_CHANGED"); - } - hglrc = 0; - } - } - dsi = ds.GetDrawingSurfaceInfo(); - if (dsi == null) { - // Widget not yet realized - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - return false; - } - win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(); - hdc = win32dsi.hdc(); - if (hdc == 0) { - // Widget not yet realized - ds.FreeDrawingSurfaceInfo(dsi); - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - dsi = null; - win32dsi = null; - return false; - } - return true; - } - - private void unlockSurface() { - if (hdc == 0) { - throw new GLException("Surface already unlocked"); - } - ds.FreeDrawingSurfaceInfo(dsi); - ds.Unlock(); - getJAWT().FreeDrawingSurface(ds); - ds = null; - dsi = null; - win32dsi = null; - hdc = 0; - } - - protected void create() { - choosePixelFormatAndCreateContext(true); - } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLDrawable.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLDrawable.java new file mode 100644 index 000000000..50cf5c9f4 --- /dev/null +++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLDrawable.java @@ -0,0 +1,181 @@ +/* + * 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.windows; + +import java.awt.Component; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class WindowsOnscreenGLDrawable extends WindowsGLDrawable { + public static final int LOCK_SURFACE_NOT_READY = 1; + public static final int LOCK_SURFACE_CHANGED = 2; + public static final int LOCK_SUCCESS = 3; + private static JAWT jawt; + + // Variables for lockSurface/unlockSurface + private JAWT_DrawingSurface ds; + private JAWT_DrawingSurfaceInfo dsi; + private JAWT_Win32DrawingSurfaceInfo win32dsi; + + // 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 WindowsOnscreenGLDrawable(Component component, + GLCapabilities capabilities, + GLCapabilitiesChooser chooser) { + super(component, capabilities, chooser); + } + + public GLContext createContext(GLContext shareWith) { + return new WindowsOnscreenGLContext(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 { + if (!WGL.SwapBuffers(hdc) && (WGL.GetLastError() != 0)) { + throw new GLException("Error swapping buffers"); + } + } + + public int lockSurface() throws GLException { + if (!realized) { + return LOCK_SURFACE_NOT_READY; + } + if (hdc != 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; + } + win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(); + hdc = win32dsi.hdc(); + if (hdc == 0) { + // Widget not yet realized + ds.FreeDrawingSurfaceInfo(dsi); + ds.Unlock(); + getJAWT().FreeDrawingSurface(ds); + ds = null; + dsi = null; + win32dsi = null; + return LOCK_SURFACE_NOT_READY; + } + if (!pixelFormatChosen) { + choosePixelFormat(true); + } + return ret; + } + + public void unlockSurface() { + if (hdc == 0) { + throw new GLException("Surface already unlocked"); + } + ds.FreeDrawingSurfaceInfo(dsi); + ds.Unlock(); + getJAWT().FreeDrawingSurface(ds); + ds = null; + dsi = null; + win32dsi = null; + hdc = 0; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private JAWT getJAWT() { + if (jawt == null) { + JAWT j = new JAWT(); + j.version(JAWTFactory.JAWT_VERSION_1_4); + if (!JAWTFactory.JAWT_GetAWT(j)) { + throw new RuntimeException("Unable to initialize JAWT"); + } + jawt = j; + } + return jawt; + } +} diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java index d58d15d02..ca2f4aaa9 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java @@ -43,55 +43,27 @@ import net.java.games.jogl.*; import net.java.games.jogl.impl.*; public class WindowsPbufferGLContext extends WindowsGLContext { - private static final boolean DEBUG = Debug.debug("WindowsPbufferGLContext"); - - private int initWidth; - private int initHeight; - - private long buffer; // pbuffer handle - private int width; - private int height; - - // FIXME: kept around because we create the OpenGL context lazily to - // better integrate with the WindowsGLContext framework - private long parentHglrc; - - private static final int MAX_PFORMATS = 256; - private static final int MAX_ATTRIBS = 256; - // State for render-to-texture and render-to-texture-rectangle support - private boolean created; + private WindowsPbufferGLDrawable drawable; private boolean rtt; // render-to-texture? private boolean hasRTT; // render-to-texture extension available? private boolean rect; // render-to-texture-rectangle? private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV private int texture; // actual texture object - private int floatMode; - - public WindowsPbufferGLContext(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 + "))"); - } - if (DEBUG) { - System.out.println("Pbuffer caps on init: " + capabilities + - (capabilities.getOffscreenRenderToTexture() ? " [rtt]" : "") + - (capabilities.getOffscreenRenderToTextureRectangle() ? " [rect]" : "") + - (capabilities.getOffscreenFloatingPointBuffers() ? " [float]" : "")); - } + public WindowsPbufferGLContext(WindowsPbufferGLDrawable 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"); } @@ -103,10 +75,11 @@ public class WindowsPbufferGLContext extends WindowsGLContext { GL gl = getGL(); gl.glBindTexture(textureTarget, texture); if (rtt && hasRTT) { - if (!gl.wglBindTexImageARB(buffer, GL.WGL_FRONT_LEFT_ARB)) { + if (!gl.wglBindTexImageARB(drawable.getPbuffer(), GL.WGL_FRONT_LEFT_ARB)) { throw new GLException("Binding of pbuffer to texture failed: " + wglGetLastError()); } } + // FIXME: comment is wrong now // Note that if the render-to-texture extension is not supported, // we perform a glCopyTexImage2D in swapBuffers(). } @@ -118,289 +91,32 @@ public class WindowsPbufferGLContext extends WindowsGLContext { } if (rtt && hasRTT) { GL gl = getGL(); - if (!gl.wglReleaseTexImageARB(buffer, GL.WGL_FRONT_LEFT_ARB)) { + if (!gl.wglReleaseTexImageARB(drawable.getPbuffer(), GL.WGL_FRONT_LEFT_ARB)) { throw new GLException("Releasing of pbuffer from texture failed: " + wglGetLastError()); } } } - public void createPbuffer(long parentHdc, long parentHglrc) { - GL gl = getGL(); - // Must initally grab OpenGL function pointers while parent's - // context is current because otherwise we don't have the wgl - // extensions available to us - resetGLFunctionAvailability(); - - int[] iattributes = new int [2*MAX_ATTRIBS]; - float[] fattributes = new float[2*MAX_ATTRIBS]; - int nfattribs = 0; - int niattribs = 0; - - if (DEBUG) { - System.out.println("Pbuffer caps: " + capabilities + - (capabilities.getOffscreenRenderToTexture() ? " [rtt]" : "") + - (capabilities.getOffscreenRenderToTextureRectangle() ? " [rect]" : "") + - (capabilities.getOffscreenFloatingPointBuffers() ? " [float]" : "")); - } - - rtt = capabilities.getOffscreenRenderToTexture(); - rect = capabilities.getOffscreenRenderToTextureRectangle(); - boolean useFloat = capabilities.getOffscreenFloatingPointBuffers(); - boolean ati = false; - - // Since we are trying to create a pbuffer, the pixel format we - // request (and subsequently use) must be "p-buffer capable". - iattributes[niattribs++] = GL.WGL_DRAW_TO_PBUFFER_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - - if (rtt && !rect) { - throw new GLException("Render-to-texture-rectangle requires render-to-texture to be specified"); - } - - if (rect) { - if (!gl.isExtensionAvailable("GL_NV_texture_rectangle")) { - throw new GLException("Render-to-texture-rectangle requires GL_NV_texture_rectangle extension"); - } - } - - if (useFloat) { - if (!gl.isExtensionAvailable("WGL_ATI_pixel_format_float") && - !gl.isExtensionAvailable("WGL_NV_float_buffer")) { - throw new GLException("Floating-point pbuffers not supported by this hardware"); - } - - // Prefer NVidia extension over ATI - if (gl.isExtensionAvailable("WGL_NV_float_buffer")) { - ati = false; - floatMode = GLPbuffer.NV_FLOAT; - } else { - ati = true; - floatMode = GLPbuffer.ATI_FLOAT; - } - if (DEBUG) { - System.err.println("Using " + (ati ? "ATI" : "NVidia") + " floating-point extension"); - } - } - - if (useFloat && ati) { - if (rtt) { - throw new GLException("Render-to-floating-point-texture not supported on ATI hardware"); - } else { - iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; - iattributes[niattribs++] = GL.WGL_TYPE_RGBA_FLOAT_ATI; - } - } else { - if (!rtt) { - // Currently we don't support non-truecolor visuals in the - // GLCapabilities, so we don't offer the option of making - // color-index pbuffers. - iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; - iattributes[niattribs++] = GL.WGL_TYPE_RGBA_ARB; - } - } - - iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; - if (capabilities.getDoubleBuffered()) { - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = GL.GL_FALSE; - } - - iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; - iattributes[niattribs++] = capabilities.getDepthBits(); - - iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; - iattributes[niattribs++] = capabilities.getRedBits(); - - iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; - iattributes[niattribs++] = capabilities.getGreenBits(); - - iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; - iattributes[niattribs++] = capabilities.getBlueBits(); - - iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; - iattributes[niattribs++] = capabilities.getAlphaBits(); - - iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; - if (capabilities.getStencilBits() > 0) { - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = GL.GL_FALSE; - } - - if (capabilities.getAccumRedBits() > 0 || - capabilities.getAccumGreenBits() > 0 || - capabilities.getAccumBlueBits() > 0) { - iattributes[niattribs++] = GL.WGL_ACCUM_BITS_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - } - - if (useFloat && !ati) { - iattributes[niattribs++] = GL.WGL_FLOAT_COMPONENTS_NV; - iattributes[niattribs++] = GL.GL_TRUE; - } - - if (rtt) { - if (useFloat) { - assert(!ati); - if (!rect) { - throw new GLException("Render-to-floating-point-texture only supported on NVidia hardware with render-to-texture-rectangle"); - } - iattributes[niattribs++] = GL.WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV; - iattributes[niattribs++] = GL.GL_TRUE; - } else { - iattributes[niattribs++] = rect ? GL.WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV : GL.WGL_BIND_TO_TEXTURE_RGB_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - } - } - - iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - - int[] pformats = new int[MAX_PFORMATS]; - int nformats; - int[] nformatsTmp = new int[1]; - if (!gl.wglChoosePixelFormatARB(parentHdc, - iattributes, 0, - fattributes, 0, - MAX_PFORMATS, - pformats, 0, - nformatsTmp, 0)) { - throw new GLException("pbuffer creation error: wglChoosePixelFormatARB() failed"); - } - nformats = nformatsTmp[0]; - if (nformats <= 0) { - throw new GLException("pbuffer creation error: Couldn't find a suitable pixel format"); - } - - if (DEBUG) { - System.err.println("" + nformats + " suitable pixel formats found"); - // query pixel format - iattributes[0] = GL.WGL_RED_BITS_ARB; - iattributes[1] = GL.WGL_GREEN_BITS_ARB; - iattributes[2] = GL.WGL_BLUE_BITS_ARB; - iattributes[3] = GL.WGL_ALPHA_BITS_ARB; - iattributes[4] = GL.WGL_DEPTH_BITS_ARB; - iattributes[5] = (useFloat ? (ati ? GL.WGL_PIXEL_TYPE_ARB : GL.WGL_FLOAT_COMPONENTS_NV) : GL.WGL_RED_BITS_ARB); - iattributes[6] = GL.WGL_SAMPLE_BUFFERS_EXT; - iattributes[7] = GL.WGL_SAMPLES_EXT; - iattributes[8] = GL.WGL_DRAW_TO_PBUFFER_ARB; - int[] ivalues = new int[9]; - for (int i = 0; i < nformats; i++) { - if (!gl.wglGetPixelFormatAttribivARB(parentHdc, pformats[i], 0, 9, iattributes, 0, ivalues, 0)) { - throw new GLException("Error while querying pixel format " + pformats[i] + - "'s (index " + i + "'s) capabilities for debugging"); - } - System.err.print("pixel format " + pformats[i] + " (index " + i + "): "); - System.err.print( "r: " + ivalues[0]); - System.err.print(" g: " + ivalues[1]); - System.err.print(" b: " + ivalues[2]); - System.err.print(" a: " + ivalues[3]); - System.err.print(" depth: " + ivalues[4]); - System.err.print(" multisample: " + ivalues[6]); - System.err.print(" samples: " + ivalues[7]); - if (useFloat) { - if (ati) { - if (ivalues[5] == GL.WGL_TYPE_RGBA_FLOAT_ATI) { - System.err.print(" [ati float]"); - } else if (ivalues[5] != GL.WGL_TYPE_RGBA_ARB) { - System.err.print(" [unknown pixel type " + ivalues[5] + "]"); - } - } else { - if (ivalues[5] != 0) { - System.err.print(" [float]"); - } - } - } - - if (ivalues[8] != 0) { - System.err.print(" [pbuffer]"); - } - System.err.println(); - } - } - - long tmpBuffer = 0; - int whichFormat = 0; - // Loop is a workaround for bugs in NVidia's recent drivers - do { - int format = pformats[whichFormat]; - - // Create the p-buffer. - niattribs = 0; - - if (rtt) { - iattributes[niattribs++] = GL.WGL_TEXTURE_FORMAT_ARB; - if (useFloat) { - iattributes[niattribs++] = GL.WGL_TEXTURE_FLOAT_RGB_NV; - } else { - iattributes[niattribs++] = GL.WGL_TEXTURE_RGBA_ARB; - } - - iattributes[niattribs++] = GL.WGL_TEXTURE_TARGET_ARB; - iattributes[niattribs++] = rect ? GL.WGL_TEXTURE_RECTANGLE_NV : GL.WGL_TEXTURE_2D_ARB; - - iattributes[niattribs++] = GL.WGL_MIPMAP_TEXTURE_ARB; - iattributes[niattribs++] = GL.GL_FALSE; - - iattributes[niattribs++] = GL.WGL_PBUFFER_LARGEST_ARB; - iattributes[niattribs++] = GL.GL_FALSE; - } - - iattributes[niattribs++] = 0; - - tmpBuffer = gl.wglCreatePbufferARB(parentHdc, format, initWidth, initHeight, iattributes, 0); - ++whichFormat; - } while ((tmpBuffer == 0) && (whichFormat < nformats)); - - if (tmpBuffer == 0) { - throw new GLException("pbuffer creation error: wglCreatePbufferARB() failed: tried " + nformats + - " pixel formats, last error was: " + wglGetLastError()); - } - - // Get the device context. - long tmpHdc = gl.wglGetPbufferDCARB(tmpBuffer); - if (tmpHdc == 0) { - throw new GLException("pbuffer creation error: wglGetPbufferDCARB() failed"); - } - - this.parentHglrc = parentHglrc; - - // Set up instance variables - buffer = tmpBuffer; - hdc = tmpHdc; - - // Determine the actual width and height we were able to create. - int[] tmp = new int[1]; - gl.wglQueryPbufferARB( buffer, GL.WGL_PBUFFER_WIDTH_ARB, tmp, 0 ); - width = tmp[0]; - gl.wglQueryPbufferARB( buffer, GL.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); - height = tmp[0]; - - if (DEBUG) { - System.err.println("Created pbuffer " + width + " x " + height); - } - } - protected int makeCurrentImpl() throws GLException { - created = false; - - if (buffer == 0) { - // pbuffer not instantiated yet + if (drawable.getHDC() == 0) { + // pbuffer not instantiated (yet?) if (DEBUG) { - System.err.println("pbuffer not instantiated yet"); + System.err.println("pbuffer not instantiated"); } return CONTEXT_NOT_CURRENT; } int res = super.makeCurrentImpl(); - if (DEBUG) { - System.err.println("super.makeCurrent() = " + res + ", created = " + created); + if (DEBUG && VERBOSE) { + System.err.println("super.makeCurrent() = " + res); } - if (created) { + if (res == CONTEXT_CURRENT_NEW) { + GLCapabilities capabilities = drawable.getCapabilities(); + // Initialize render-to-texture support if requested rtt = capabilities.getOffscreenRenderToTexture(); rect = capabilities.getOffscreenRenderToTextureRectangle(); + GL gl = getGL(); if (rtt) { if (DEBUG) { @@ -412,7 +128,6 @@ public class WindowsPbufferGLContext extends WindowsGLContext { "supported; implementing render_to_texture support using slow texture readback"); } else { hasRTT = true; - GL gl = getGL(); if (rect && !gl.isExtensionAvailable("GL_NV_texture_rectangle")) { System.err.println("WindowsPbufferGLContext: WARNING: GL_NV_texture_rectangle extension not " + @@ -438,23 +153,13 @@ public class WindowsPbufferGLContext extends WindowsGLContext { gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, width, height, 0); + gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, drawable.getWidth(), drawable.getHeight(), 0); } } } return res; } - 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"); } @@ -463,67 +168,11 @@ public class WindowsPbufferGLContext extends WindowsGLContext { throw new GLException("Should not call this"); } - protected void create() { - created = true; - // Create a gl context for the p-buffer. - hglrc = WGL.wglCreateContext(hdc); - if (hglrc == 0) { - throw new GLException("pbuffer creation error: wglCreateContext() failed"); - } - - // FIXME: provide option to not share display lists with subordinate pbuffer? - if (!WGL.wglShareLists(parentHglrc, hglrc)) { - throw new GLException("pbuffer: wglShareLists() failed"); - } - } - - protected void destroyImpl() throws GLException { - if (hglrc != 0) { - super.destroyImpl(); - // Must release DC and pbuffer - // NOTE that since the context is not current, glGetError() can - // not be called here, so we skip the use of any composable - // pipelines - GL gl = createGL(); - if (gl.wglReleasePbufferDCARB(buffer, hdc) == 0) { - throw new GLException("Error releasing pbuffer device context: error code " + WGL.GetLastError()); - } - hdc = 0; - if (!gl.wglDestroyPbufferARB(buffer)) { - throw new GLException("Error destroying pbuffer: error code " + WGL.GetLastError()); - } - buffer = 0; - } - } - - public void swapBuffers() throws GLException { - // FIXME: do we need to do anything if the pbuffer is double-buffered? - // For now, just grab the pixels for the render-to-texture support. - if (rtt && !hasRTT) { - if (DEBUG) { - System.err.println("Copying pbuffer data to GL_TEXTURE_2D state"); - } - - GL gl = getGL(); - gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, width, height); - } - } - public int getFloatingPointMode() { - return floatMode; + return drawable.getFloatingPointMode(); } - private String wglGetLastError() { - int err = WGL.GetLastError(); - String detail = null; - switch (err) { - case WGL.ERROR_INVALID_PIXEL_FORMAT: detail = "ERROR_INVALID_PIXEL_FORMAT"; break; - case WGL.ERROR_NO_SYSTEM_RESOURCES: detail = "ERROR_NO_SYSTEM_RESOURCES"; break; - case WGL.ERROR_INVALID_DATA: detail = "ERROR_INVALID_DATA"; break; - case WGL.ERROR_PROC_NOT_FOUND: detail = "ERROR_PROC_NOT_FOUND"; break; - case WGL.ERROR_INVALID_WINDOW_HANDLE:detail = "ERROR_INVALID_WINDOW_HANDLE"; break; - default: detail = "(Unknown error code " + err + ")"; break; - } - return detail; + private static String wglGetLastError() { + return WindowsGLContextFactory.wglGetLastError(); } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java new file mode 100644 index 000000000..6917b281d --- /dev/null +++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLDrawable.java @@ -0,0 +1,393 @@ +/* + * 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.windows; + +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public class WindowsPbufferGLDrawable extends WindowsGLDrawable { + private int initWidth; + private int initHeight; + + private GL cachedGL; // cached GL instance from parent GLCanvas, + // needed to destroy pbuffer + private long buffer; // pbuffer handle + private int width; + private int height; + + private int floatMode; + + public WindowsPbufferGLDrawable(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 WindowsPbufferGLContext(this, shareWith); + } + + public void destroy() { + if (hdc != 0) { + // Must release DC and pbuffer + // NOTE that since the context is not current, glGetError() can + // not be called here, so we skip the use of any composable + // pipelines (see WindowsOnscreenGLContext.makeCurrentImpl) + GL gl = cachedGL; + if (gl.wglReleasePbufferDCARB(buffer, hdc) == 0) { + throw new GLException("Error releasing pbuffer device context: error code " + WGL.GetLastError()); + } + hdc = 0; + if (!gl.wglDestroyPbufferARB(buffer)) { + throw new GLException("Error destroying pbuffer: error code " + WGL.GetLastError()); + } + buffer = 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 parentHdc) { + int[] iattributes = new int [2*MAX_ATTRIBS]; + float[] fattributes = new float[2*MAX_ATTRIBS]; + int nfattribs = 0; + int niattribs = 0; + + if (DEBUG) { + System.out.println("Pbuffer parentHdc = " + toHexString(parentHdc)); + System.out.println("Pbuffer caps: " + capabilities + + (capabilities.getOffscreenRenderToTexture() ? " [rtt]" : "") + + (capabilities.getOffscreenRenderToTextureRectangle() ? " [rect]" : "") + + (capabilities.getOffscreenFloatingPointBuffers() ? " [float]" : "")); + } + + boolean rtt = capabilities.getOffscreenRenderToTexture(); + boolean rect = capabilities.getOffscreenRenderToTextureRectangle(); + boolean useFloat = capabilities.getOffscreenFloatingPointBuffers(); + boolean ati = false; + + // Since we are trying to create a pbuffer, the pixel format we + // request (and subsequently use) must be "p-buffer capable". + iattributes[niattribs++] = GL.WGL_DRAW_TO_PBUFFER_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + + if (rtt && !rect) { + throw new GLException("Render-to-texture-rectangle requires render-to-texture to be specified"); + } + + if (rect) { + if (!gl.isExtensionAvailable("GL_NV_texture_rectangle")) { + throw new GLException("Render-to-texture-rectangle requires GL_NV_texture_rectangle extension"); + } + } + + if (useFloat) { + if (!gl.isExtensionAvailable("WGL_ATI_pixel_format_float") && + !gl.isExtensionAvailable("WGL_NV_float_buffer")) { + throw new GLException("Floating-point pbuffers not supported by this hardware"); + } + + // Prefer NVidia extension over ATI + if (gl.isExtensionAvailable("WGL_NV_float_buffer")) { + ati = false; + floatMode = GLPbuffer.NV_FLOAT; + } else { + ati = true; + floatMode = GLPbuffer.ATI_FLOAT; + } + if (DEBUG) { + System.err.println("Using " + (ati ? "ATI" : "NVidia") + " floating-point extension"); + } + } + + if (useFloat && ati) { + if (rtt) { + throw new GLException("Render-to-floating-point-texture not supported on ATI hardware"); + } else { + iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; + iattributes[niattribs++] = GL.WGL_TYPE_RGBA_FLOAT_ATI; + } + } else { + if (!rtt) { + // Currently we don't support non-truecolor visuals in the + // GLCapabilities, so we don't offer the option of making + // color-index pbuffers. + iattributes[niattribs++] = GL.WGL_PIXEL_TYPE_ARB; + iattributes[niattribs++] = GL.WGL_TYPE_RGBA_ARB; + } + } + + iattributes[niattribs++] = GL.WGL_DOUBLE_BUFFER_ARB; + if (capabilities.getDoubleBuffered()) { + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = GL.GL_FALSE; + } + + iattributes[niattribs++] = GL.WGL_DEPTH_BITS_ARB; + iattributes[niattribs++] = capabilities.getDepthBits(); + + iattributes[niattribs++] = GL.WGL_RED_BITS_ARB; + iattributes[niattribs++] = capabilities.getRedBits(); + + iattributes[niattribs++] = GL.WGL_GREEN_BITS_ARB; + iattributes[niattribs++] = capabilities.getGreenBits(); + + iattributes[niattribs++] = GL.WGL_BLUE_BITS_ARB; + iattributes[niattribs++] = capabilities.getBlueBits(); + + iattributes[niattribs++] = GL.WGL_ALPHA_BITS_ARB; + iattributes[niattribs++] = capabilities.getAlphaBits(); + + iattributes[niattribs++] = GL.WGL_STENCIL_BITS_ARB; + if (capabilities.getStencilBits() > 0) { + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = GL.GL_FALSE; + } + + if (capabilities.getAccumRedBits() > 0 || + capabilities.getAccumGreenBits() > 0 || + capabilities.getAccumBlueBits() > 0) { + iattributes[niattribs++] = GL.WGL_ACCUM_BITS_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + } + + if (useFloat && !ati) { + iattributes[niattribs++] = GL.WGL_FLOAT_COMPONENTS_NV; + iattributes[niattribs++] = GL.GL_TRUE; + } + + if (rtt) { + if (useFloat) { + assert(!ati); + if (!rect) { + throw new GLException("Render-to-floating-point-texture only supported on NVidia hardware with render-to-texture-rectangle"); + } + iattributes[niattribs++] = GL.WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV; + iattributes[niattribs++] = GL.GL_TRUE; + } else { + iattributes[niattribs++] = rect ? GL.WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV : GL.WGL_BIND_TO_TEXTURE_RGB_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + } + } + + iattributes[niattribs++] = GL.WGL_SUPPORT_OPENGL_ARB; + iattributes[niattribs++] = GL.GL_TRUE; + + int[] pformats = new int[MAX_PFORMATS]; + int nformats; + int[] nformatsTmp = new int[1]; + if (!gl.wglChoosePixelFormatARB(parentHdc, + iattributes, 0, + fattributes, 0, + MAX_PFORMATS, + pformats, 0, + nformatsTmp, 0)) { + throw new GLException("pbuffer creation error: wglChoosePixelFormatARB() failed"); + } + nformats = nformatsTmp[0]; + if (nformats <= 0) { + throw new GLException("pbuffer creation error: Couldn't find a suitable pixel format"); + } + + if (DEBUG) { + System.err.println("" + nformats + " suitable pixel formats found"); + // query pixel format + iattributes[0] = GL.WGL_RED_BITS_ARB; + iattributes[1] = GL.WGL_GREEN_BITS_ARB; + iattributes[2] = GL.WGL_BLUE_BITS_ARB; + iattributes[3] = GL.WGL_ALPHA_BITS_ARB; + iattributes[4] = GL.WGL_DEPTH_BITS_ARB; + iattributes[5] = (useFloat ? (ati ? GL.WGL_PIXEL_TYPE_ARB : GL.WGL_FLOAT_COMPONENTS_NV) : GL.WGL_RED_BITS_ARB); + iattributes[6] = GL.WGL_SAMPLE_BUFFERS_EXT; + iattributes[7] = GL.WGL_SAMPLES_EXT; + iattributes[8] = GL.WGL_DRAW_TO_PBUFFER_ARB; + int[] ivalues = new int[9]; + for (int i = 0; i < nformats; i++) { + if (!gl.wglGetPixelFormatAttribivARB(parentHdc, pformats[i], 0, 9, iattributes, 0, ivalues, 0)) { + throw new GLException("Error while querying pixel format " + pformats[i] + + "'s (index " + i + "'s) capabilities for debugging"); + } + System.err.print("pixel format " + pformats[i] + " (index " + i + "): "); + System.err.print( "r: " + ivalues[0]); + System.err.print(" g: " + ivalues[1]); + System.err.print(" b: " + ivalues[2]); + System.err.print(" a: " + ivalues[3]); + System.err.print(" depth: " + ivalues[4]); + System.err.print(" multisample: " + ivalues[6]); + System.err.print(" samples: " + ivalues[7]); + if (useFloat) { + if (ati) { + if (ivalues[5] == GL.WGL_TYPE_RGBA_FLOAT_ATI) { + System.err.print(" [ati float]"); + } else if (ivalues[5] != GL.WGL_TYPE_RGBA_ARB) { + System.err.print(" [unknown pixel type " + ivalues[5] + "]"); + } + } else { + if (ivalues[5] != 0) { + System.err.print(" [float]"); + } + } + } + + if (ivalues[8] != 0) { + System.err.print(" [pbuffer]"); + } + System.err.println(); + } + } + + long tmpBuffer = 0; + int whichFormat = 0; + // Loop is a workaround for bugs in NVidia's recent drivers + do { + int format = pformats[whichFormat]; + + // Create the p-buffer. + niattribs = 0; + + if (rtt) { + iattributes[niattribs++] = GL.WGL_TEXTURE_FORMAT_ARB; + if (useFloat) { + iattributes[niattribs++] = GL.WGL_TEXTURE_FLOAT_RGB_NV; + } else { + iattributes[niattribs++] = GL.WGL_TEXTURE_RGBA_ARB; + } + + iattributes[niattribs++] = GL.WGL_TEXTURE_TARGET_ARB; + iattributes[niattribs++] = rect ? GL.WGL_TEXTURE_RECTANGLE_NV : GL.WGL_TEXTURE_2D_ARB; + + iattributes[niattribs++] = GL.WGL_MIPMAP_TEXTURE_ARB; + iattributes[niattribs++] = GL.GL_FALSE; + + iattributes[niattribs++] = GL.WGL_PBUFFER_LARGEST_ARB; + iattributes[niattribs++] = GL.GL_FALSE; + } + + iattributes[niattribs++] = 0; + + tmpBuffer = gl.wglCreatePbufferARB(parentHdc, format, initWidth, initHeight, iattributes, 0); + ++whichFormat; + } while ((tmpBuffer == 0) && (whichFormat < nformats)); + + if (tmpBuffer == 0) { + throw new GLException("pbuffer creation error: wglCreatePbufferARB() failed: tried " + nformats + + " pixel formats, last error was: " + wglGetLastError()); + } + + // Get the device context. + long tmpHdc = gl.wglGetPbufferDCARB(tmpBuffer); + if (tmpHdc == 0) { + throw new GLException("pbuffer creation error: wglGetPbufferDCARB() failed"); + } + + // Set up instance variables + buffer = tmpBuffer; + hdc = tmpHdc; + cachedGL = gl; + + // Determine the actual width and height we were able to create. + int[] tmp = new int[1]; + gl.wglQueryPbufferARB( buffer, GL.WGL_PBUFFER_WIDTH_ARB, tmp, 0 ); + width = tmp[0]; + gl.wglQueryPbufferARB( buffer, GL.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); + height = tmp[0]; + + if (DEBUG) { + System.err.println("Created pbuffer " + width + " x " + height); + } + } + + public GLCapabilities getCapabilities() { + return capabilities; + } + + public long getPbuffer() { + return buffer; + } + + public int getFloatingPointMode() { + return floatMode; + } + + public void swapBuffers() throws GLException { + // FIXME: this doesn't make sense any more because we don't have + // access to our OpenGL context here + /* + // FIXME: do we need to do anything if the pbuffer is double-buffered? + // For now, just grab the pixels for the render-to-texture support. + if (rtt && !hasRTT) { + if (DEBUG) { + System.err.println("Copying pbuffer data to GL_TEXTURE_2D state"); + } + + GL gl = getGL(); + gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, width, height); + } + */ + } + + private static String wglGetLastError() { + return WindowsGLContextFactory.wglGetLastError(); + } +} |