diff options
Diffstat (limited to 'src/net/java/games/jogl/impl/windows')
3 files changed, 230 insertions, 69 deletions
diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java index 0dd05f7ba..eed383794 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java @@ -40,7 +40,9 @@ 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.*; @@ -138,7 +140,7 @@ public abstract class WindowsGLContext extends GLContext { } if (!WGL.wglMakeCurrent(hdc, hglrc)) { - throw new GLException("Error making context current"); + throw new GLException("Error making context current: " + WGL.GetLastError()); } if (created) { @@ -164,7 +166,7 @@ public abstract class WindowsGLContext extends GLContext { protected synchronized void free() throws GLException { if (!WGL.wglMakeCurrent(0, 0)) { - throw new GLException("Error freeing OpenGL context"); + throw new GLException("Error freeing OpenGL context: " + WGL.GetLastError()); } } @@ -270,10 +272,11 @@ public abstract class WindowsGLContext extends GLContext { GLCapabilities[] availableCaps = null; int numFormats = 0; pfd = newPixelFormatDescriptor(); - GraphicsDevice device = component.getGraphicsConfiguration().getDevice(); + GraphicsConfiguration config = component.getGraphicsConfiguration(); + GraphicsDevice device = config.getDevice(); // Produce a recommended pixel format selection for the GLCapabilitiesChooser. // Try to use wglChoosePixelFormatARB if we have it available - GL dummyGL = WindowsGLContextFactory.getDummyGLContext(device); + GL dummyGL = WindowsGLContextFactory.getDummyGL(device); int recommendedPixelFormat = -1; boolean haveWGLChoosePixelFormatARB = false; boolean haveWGLARBMultisample = false; @@ -286,6 +289,19 @@ public abstract class WindowsGLContext extends GLContext { } } } + 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("Error Making WGLC Current: " + WGL.GetLastError() ); + } else { + freeWGLC = true; + } + } if (dummyGL != null && haveWGLChoosePixelFormatARB) { int[] iattributes = new int [2 * MAX_ATTRIBS]; int[] iresults = new int [2 * MAX_ATTRIBS]; @@ -365,6 +381,11 @@ public abstract class WindowsGLContext extends GLContext { System.err.println("Used wglChoosePixelFormatARB to recommend pixel format " + recommendedPixelFormat); } } + } else { + if (DEBUG) { + System.err.println("wglChoosePixelFormatARB failed: " + WGL.GetLastError() ); + Thread.dumpStack(); + } } if (DEBUG) { if (recommendedPixelFormat < 0) { @@ -388,7 +409,7 @@ public abstract class WindowsGLContext extends GLContext { niattribs = 0; iattributes[0] = GL.WGL_NUMBER_PIXEL_FORMATS_ARB; if (!dummyGL.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, iresults)) { - throw new GLException("Unable to enumerate pixel formats of window using wglGetPixelFormatAttribivARB"); + throw new GLException("Unable to enumerate pixel formats of window using wglGetPixelFormatAttribivARB: " + WGL.GetLastError()); } numFormats = iresults[0]; // Should we be filtering out the pixel formats which aren't @@ -423,6 +444,9 @@ public abstract class WindowsGLContext extends GLContext { } availableCaps[i] = iattributes2GLCapabilities(iattributes, iresults, niattribs, true); } + if( freeWGLC ) { + WGL.wglMakeCurrent( 0, 0 ); + } } else { if (DEBUG) { System.err.println("Using ChoosePixelFormat because no wglChoosePixelFormatARB: dummyGL = " + dummyGL); @@ -456,7 +480,7 @@ public abstract class WindowsGLContext extends GLContext { } 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"); + throw new GLException("Error re-describing the chosen pixel format: " + WGL.GetLastError()); } } else { // For now, use ChoosePixelFormat for offscreen surfaces until diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java index 74d72645d..6603dc2eb 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java @@ -40,15 +40,16 @@ package net.java.games.jogl.impl.windows; import java.awt.Component; -import java.awt.Dialog; -import java.awt.EventQueue; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; +import java.awt.Rectangle; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.Collection; +import java.util.Iterator; import net.java.games.jogl.*; import net.java.games.jogl.impl.*; @@ -68,6 +69,10 @@ public class WindowsGLContextFactory extends GLContextFactory { private static Map/*<GraphicsDevice, String>*/ dummyExtensionsMap = new HashMap(); private static Set/*<GraphicsDevice >*/ pendingContextSet = new HashSet(); + public WindowsGLContextFactory() { + Runtime.getRuntime().addShutdownHook( new ShutdownHook() ); + } + public GraphicsConfiguration chooseGraphicsConfiguration(GLCapabilities capabilities, GLCapabilitiesChooser chooser, GraphicsDevice device) { @@ -84,80 +89,212 @@ public class WindowsGLContextFactory extends GLContextFactory { return new WindowsOffscreenGLContext(capabilities, chooser, shareWith); } } + + // Return cached GL context + public static WindowsGLContext getDummyGLContext( final GraphicsDevice device ) { + checkForDummyContext( device ); + NativeWindowStruct nws = (NativeWindowStruct) dummyContextMap.get(device); + return nws.getWindowsContext(); + } + // Return cached extension string public static String getDummyGLExtensions(final GraphicsDevice device) { - String exts = (String) dummyExtensionsMap.get(device); - return (exts == null) ? "" : exts; + checkForDummyContext( device ); + String exts = (String) dummyExtensionsMap.get(device); + return (exts == null) ? "" : exts; } - public static GL getDummyGLContext(final GraphicsDevice device) { - GL gl = (GL) dummyContextMap.get(device); - if (gl != null) { - return gl; - } + // Return cached GL function pointers + public static GL getDummyGL(final GraphicsDevice device) { + checkForDummyContext( device ); + NativeWindowStruct nws = (NativeWindowStruct) dummyContextMap.get(device); + return( nws.getWindowsContext().getGL() ); + } - if (!pendingContextSet.contains(device)) { + /* + * Locate a cached native window, if one doesn't exist create one amd + * cache it. + */ + private static void checkForDummyContext( final GraphicsDevice device ) { + if (!pendingContextSet.contains(device) && !dummyContextMap.containsKey( device ) ) { pendingContextSet.add(device); GraphicsConfiguration config = device.getDefaultConfiguration(); - final Dialog frame = new Dialog(new Frame(config), "", false, config); - frame.setUndecorated(true); - final GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), - null, - null, - device); - canvas.addGLEventListener(new GLEventListener() { - public void init(GLDrawable drawable) { - pendingContextSet.remove(device); - dummyContextMap.put(device, drawable.getGL()); - String availableGLExtensions = ""; - String availableWGLExtensions = ""; - String availableEXTExtensions = ""; - try { - availableWGLExtensions = drawable.getGL().wglGetExtensionsStringARB(WGL.wglGetCurrentDC()); - } catch (GLException e) {} - try { - availableEXTExtensions = drawable.getGL().wglGetExtensionsStringEXT(); - } catch (GLException e) {} - availableGLExtensions = drawable.getGL().glGetString(GL.GL_EXTENSIONS); - dummyExtensionsMap.put(device, availableGLExtensions + " " + availableEXTExtensions + " " + availableWGLExtensions); - EventQueue.invokeLater(new Runnable() { - public void run() { - frame.dispose(); - } - }); - } + Rectangle rect = config.getBounds(); + 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 ); + // Start a native thread and grab native screen resources from the thread + NativeWindowThread nwt = new NativeWindowThread( rect ); + nwt.start(); + long hWnd = 0; + long tempHDC = 0; + while( (hWnd = nwt.getHWND()) == 0 || (tempHDC = nwt.getHDC()) == 0 ) { + Thread.yield(); + } + // Choose a hardware accelerated pixel format + PIXELFORMATDESCRIPTOR pfd = context.glCapabilities2PFD( caps, true ); + int pixelFormat = WGL.ChoosePixelFormat( tempHDC, pfd ); + if( pixelFormat == 0 ) { + System.err.println("Pixel Format is Zero"); + pendingContextSet.remove(device); + return; + } + // Set the hardware accelerated pixel format + if (!WGL.SetPixelFormat(tempHDC, pixelFormat, pfd)) { + System.err.println("SetPixelFormat Failed"); + pendingContextSet.remove( device ); + return; + } + // Create a rendering context + long tempHGLRC = WGL.wglCreateContext( tempHDC ); + if( hWnd == 0 || tempHDC == 0 || tempHGLRC == 0 ) { + pendingContextSet.remove( device ); + return; + } + // Store native handles for later use + NativeWindowStruct nws = new NativeWindowStruct(); + nws.setHWND( hWnd ); + nws.setWindowsContext( context ); + nws.setWindowThread( nwt ); + long currentHDC = WGL.wglGetCurrentDC(); + long currentHGLRC = WGL.wglGetCurrentContext(); + // Make the new hardware accelerated context current + if( !WGL.wglMakeCurrent( tempHDC, tempHGLRC ) ) { + pendingContextSet.remove( device ); + return; + } + // Grab function pointers + context.hdc = tempHDC; + context.hglrc = tempHGLRC; + context.resetGLFunctionAvailability(); + context.createGL(); + pendingContextSet.remove( device ); + dummyContextMap.put( device, nws ); + String availableGLExtensions = ""; + String availableWGLExtensions = ""; + String availableEXTExtensions = ""; + try { + availableWGLExtensions = context.getGL().wglGetExtensionsStringARB( currentHDC ); + } catch( GLException e ) { + } + try { + availableEXTExtensions = context.getGL().wglGetExtensionsStringEXT(); + } catch( GLException e ) { + } + availableGLExtensions = context.getGL().glGetString( GL.GL_EXTENSIONS ); + dummyExtensionsMap.put(device, availableGLExtensions + " " + availableEXTExtensions + " " + availableWGLExtensions); + WGL.wglMakeCurrent( currentHDC, currentHGLRC ); + } + } - public void display(GLDrawable drawable) { - } + /* + * This class stores handles to native resources that need to be destroyed + * at JVM shutdown. + */ + static class NativeWindowStruct { + private long HWND; + private WindowsGLContext windowsContext; + private Thread windowThread; + + public NativeWindowStruct() { + } - public void reshape(GLDrawable drawable, int x, int y, int width, int height) { - } + public long getHDC() { + return( windowsContext.hdc ); + } - public void destroy(GLDrawable drawable) { - } + public long getHGLRC() { + return( windowsContext.hglrc ); + } - public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) { - } - }); - // Attempt to work around deadlock issues with SingleThreadedWorkaround, - // which causes some of the methods below to block doing work on the AWT thread + public void setHWND( long hwnd ) { + HWND = hwnd; + } + + public long getHWND() { + return( HWND ); + } + + public void setWindowsContext( WindowsGLContext context ) { + windowsContext = context; + } + + public WindowsGLContext getWindowsContext() { + return( windowsContext ); + } + + public void setWindowThread( Thread thread ) { + windowThread = thread; + } + + public Thread getWindowThread() { + return( windowThread ); + } + } + + /* + * Native HWDN and HDC handles must be created and destroyed on the same + * thread. + */ + + static class NativeWindowThread extends Thread { + private long HWND = 0; + private long HDC = 0; + private Rectangle rectangle; + + public NativeWindowThread( Rectangle rect ) { + rectangle = rect; + } + + public synchronized long getHWND() { + return( HWND ); + } + + public synchronized long getHDC() { + return( HDC ); + } + + public void run() { + // Create a native window and device context + HWND = WGL.CreateDummyWindow( rectangle.x, rectangle.y, rectangle.width, rectangle.height ); + HDC = WGL.GetDC( HWND ); + // Pause this thread until JVM shutdown try { - EventQueue.invokeLater(new Runnable() { - public void run() { - canvas.setSize(0, 0); - canvas.setNoAutoRedrawMode(true); - canvas.setAutoSwapBufferMode(false); - frame.add(canvas); - frame.pack(); - frame.show(); - canvas.display(); - } - }); - } catch (Exception e) { - throw new GLException(e); + synchronized( this ) { + wait(); + } + } catch( InterruptedException e ) { } + // Start the message pump at shutdown + WGL.NativeEventLoop(); } + } + + /* + * This class is registered with the JVM to destroy all cached redering + * contexts, device contexts, and window handles. + */ - return (GL) dummyContextMap.get(device); + class ShutdownHook extends Thread { + public void run() { + // Collect all saved screen resources + Collection c = dummyContextMap.values(); + Iterator iter = c.iterator(); + while( iter.hasNext() ) { + // NativeWindowStruct holds refs to native resources that need to be destroyed + NativeWindowStruct struct = (NativeWindowStruct)iter.next(); + // Restart native window threads to respond to window closing events + synchronized( struct.getWindowThread() ) { + struct.getWindowThread().notifyAll(); + } + // Destroy OpenGL rendering context + if( !WGL.wglDeleteContext( struct.getHGLRC() ) ) { + System.err.println( "Error Destroying NativeWindowStruct RC: " + WGL.GetLastError() ); + } + // Send context handles to native method for deletion + WGL.DestroyDummyWindow( struct.getHWND(), struct.getHDC() ); + } + } } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java index 5bcdb4559..3bfdee5d1 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java @@ -136,7 +136,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext { } public synchronized void swapBuffers() throws GLException { - if (!WGL.SwapBuffers(hdc)) { + if (!WGL.SwapBuffers(hdc) && (WGL.GetLastError() != 0)) { throw new GLException("Error swapping buffers"); } } |