diff options
author | Kenneth Russel <[email protected]> | 2004-08-03 17:50:18 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2004-08-03 17:50:18 +0000 |
commit | 05ad8604b58f355890f0e3804906c7e8d598edfa (patch) | |
tree | 946bfc071f06e4b537afa052232d7ea5463ca669 | |
parent | d803c81ff894edcb3569f22c2e2822e1237b7456 (diff) |
Bug fix from user GKW on the JOGL forums for problems reported by
users in JOGL 1.1 betas where the code path for
wglChoosePixelFormatARB (supporting full-scene antialiasing) was
failing on older cards. The old drivers expect an OpenGL context to be
current while the wglChoosePixelFormatARB and associated calls are
being made, even though the documentation explicitly states that this
is not necessary. GKW's fix creates a native window synchronously
(independent of the AWT) and associates an OpenGL context with it
which is used to choose pixel formats for other windows on the same
GraphicsDevice. Upon VM shutdown, a native message pump is started
which causes proper disposal of the native window and its OpenGL
contexts.
There is currently no bug ID associated with this fix, although it may
be a component of completely addressing several open bugs.
Also includes a bug fix from GKW and kbr for:
Issue 98: Just 1st frame rendering on ATI Radeon
This was a race condition between JOGL's automatic discovery that the
ATI_WORKAROUND was needed and the creation of the first GLCanvas and
associated Animator. The need for disabling the setRenderingThread
optimization was computed too late, incorrectly locking out other
threads (in particular, the AWT event queue thread) from performing
rendering of the component.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@144 232f8b59-042b-4e1e-8c03-345bb8c30851
-rw-r--r-- | doc/userguide/index.html | 11 | ||||
-rw-r--r-- | make/build.xml | 4 | ||||
-rw-r--r-- | make/stub_includes/win32/wingdi.h | 40 | ||||
-rwxr-xr-x | make/wgl-CustomCCode.c | 99 | ||||
-rw-r--r-- | make/wingdi-win32.cfg | 2 | ||||
-rw-r--r-- | src/net/java/games/jogl/Animator.java | 2 | ||||
-rw-r--r-- | src/net/java/games/jogl/impl/GLContext.java | 20 | ||||
-rw-r--r-- | src/net/java/games/jogl/impl/windows/WindowsGLContext.java | 36 | ||||
-rw-r--r-- | src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java | 261 | ||||
-rw-r--r-- | src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java | 2 |
10 files changed, 389 insertions, 88 deletions
diff --git a/doc/userguide/index.html b/doc/userguide/index.html index f05a6a9b9..b3253d5f8 100644 --- a/doc/userguide/index.html +++ b/doc/userguide/index.html @@ -62,11 +62,12 @@ ported from C/C++ to Jogl without needing direct access to any of these APIs. However, all of these classes and concepts are accessible at the Java programming language level in implementation packages, and in fact the Jogl binding is itself written almost completely in the -Java programming language. There are only about fifty lines of -handwritten C code in the entire Jogl source base; the rest of the -native code is autogenerated during the build process by a new tool -called GlueGen, the source code of which is in the Jogl source -tree. Documentation for GlueGen is forthcoming. +Java programming language. There are roughly 150 lines of handwritten +C code in the entire Jogl source base (100 of which work around bugs +in older OpenGL drivers on Windows); the rest of the native code is +autogenerated during the build process by a new tool called GlueGen, +the source code of which is in the Jogl source tree. Documentation for +GlueGen is forthcoming. </P> diff --git a/make/build.xml b/make/build.xml index 41536e8b4..80adba7f0 100644 --- a/make/build.xml +++ b/make/build.xml @@ -265,7 +265,7 @@ <property name="c.compiler.includes" value="/I"make/stub_includes/opengl" /I"${c.compiler.include.root}/PlatformSDK/Include" /I"${c.compiler.include.root}/include" /I"${java.includes.dir}" /I"${java.includes.dir.platform}" /I"make/stub_includes/cg"" /> <property name="c.linker" value="link.exe" /> <property name="c.linker.flags" value="/DLL /LIBPATH:"${c.linker.lib.root}/PlatformSDK/lib" /LIBPATH:"${c.linker.lib.root}/lib" /LIBPATH:"${java.lib.dir.platform}" /INCREMENTAL:NO /NOLOGO /MACHINE:IX86 /OPT:REF /OPT:ICF /SUBSYSTEM:WINDOWS" /> - <property name="c.linker.jogl.libs" value="opengl32.lib glu32.lib jawt.lib gdi32.lib kernel32.lib" /> + <property name="c.linker.jogl.libs" value="opengl32.lib glu32.lib jawt.lib gdi32.lib user32.lib kernel32.lib" /> <property name="rootrel.c.linker.jogl.dso" value="${rootrel.obj}/jogl.dll" /> <property name="c.linker.jogl.dso" value="${project.root}/${rootrel.c.linker.jogl.dso}" /> <property name="c.linker.jogl.flags" value="/OUT:"${c.linker.jogl.dso}"" /> @@ -315,7 +315,7 @@ <property name="c.compiler.includes" value="-I"make/stub_includes/opengl" -I"${java.includes.dir}" -I"${java.includes.dir.platform}" -I"make/stub_includes/cg"" /> <property name="c.linker" value="gcc.exe" /> <property name="c.linker.flags" value="-shared" /> - <property name="c.linker.jogl.libs" value="-Wl,--kill-at -L"${java.lib.dir.platform}" -lopengl32 -lglu32 -ljawt -lgdi32" /> + <property name="c.linker.jogl.libs" value="-Wl,--kill-at -L"${java.lib.dir.platform}" -lopengl32 -lglu32 -ljawt -lgdi32 -luser32" /> <property name="rootrel.c.linker.jogl.dso" value="${rootrel.obj}/jogl.dll" /> <property name="c.linker.jogl.dso" value="${project.root}/${rootrel.c.linker.jogl.dso}" /> <property name="c.linker.jogl.flags" value="-o ${c.linker.jogl.dso}" /> diff --git a/make/stub_includes/win32/wingdi.h b/make/stub_includes/win32/wingdi.h index 3cb6f8568..2141135e7 100644 --- a/make/stub_includes/win32/wingdi.h +++ b/make/stub_includes/win32/wingdi.h @@ -83,6 +83,37 @@ typedef struct tagPIXELFORMATDESCRIPTOR #define PFD_MAIN_PLANE 0 #define PFD_OVERLAY_PLANE 1 #define PFD_UNDERLAY_PLANE (-1) +#define WGL_SWAP_MAIN_PLANE 1 +#define WGL_SWAP_OVERLAY1 2 +#define WGL_SWAP_OVERLAY2 4 +#define WGL_SWAP_OVERLAY3 8 +#define WGL_SWAP_OVERLAY4 16 +#define WGL_SWAP_OVERLAY5 32 +#define WGL_SWAP_OVERLAY6 64 +#define WGL_SWAP_OVERLAY7 128 +#define WGL_SWAP_OVERLAY8 256 +#define WGL_SWAP_OVERLAY9 512 +#define WGL_SWAP_OVERLAY10 1024 +#define WGL_SWAP_OVERLAY11 2048 +#define WGL_SWAP_OVERLAY12 4096 +#define WGL_SWAP_OVERLAY13 8192 +#define WGL_SWAP_OVERLAY14 16384 +#define WGL_SWAP_OVERLAY15 32768 +#define WGL_SWAP_UNDERLAY1 65536 +#define WGL_SWAP_UNDERLAY2 0x20000 +#define WGL_SWAP_UNDERLAY3 0x40000 +#define WGL_SWAP_UNDERLAY4 0x80000 +#define WGL_SWAP_UNDERLAY5 0x100000 +#define WGL_SWAP_UNDERLAY6 0x200000 +#define WGL_SWAP_UNDERLAY7 0x400000 +#define WGL_SWAP_UNDERLAY8 0x800000 +#define WGL_SWAP_UNDERLAY9 0x1000000 +#define WGL_SWAP_UNDERLAY10 0x2000000 +#define WGL_SWAP_UNDERLAY11 0x4000000 +#define WGL_SWAP_UNDERLAY12 0x8000000 +#define WGL_SWAP_UNDERLAY13 0x10000000 +#define WGL_SWAP_UNDERLAY14 0x20000000 +#define WGL_SWAP_UNDERLAY15 0x40000000 /* PIXELFORMATDESCRIPTOR flags */ #define PFD_DOUBLEBUFFER 0x00000001 @@ -132,6 +163,7 @@ WINGDIAPI BOOL WINAPI wglMakeCurrent(HDC, HGLRC); WINGDIAPI BOOL WINAPI wglShareLists(HGLRC, HGLRC); WINGDIAPI BOOL WINAPI SwapBuffers(HDC); WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); +WINGDIAPI BOOL WINAPI wglSwapLayerBuffers(HDC,UINT); /* --- FIXME: need to handle these entry points! WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC, int); @@ -150,3 +182,11 @@ WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC, CONST BITMAPINFO *, UINT, VOID ** WINGDIAPI BOOL WINAPI DeleteDC(HDC); WINGDIAPI BOOL WINAPI DeleteObject(HGDIOBJ); WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC, HGDIOBJ); + +// Routines for creation of a dummy device context and OpenGL context +// for the purposes of getting wglChoosePixelFormatARB and associated +// routines +WINGDIAPI HDC WINAPI GetDC(HDC); +WINGDIAPI HDC WINAPI CreateDummyWindow(int,int,int,int); +WINGDIAPI VOID WINAPI DestroyDummyWindow(HWND,HDC); +WINGDIAPI VOID WINAPI NativeEventLoop(); diff --git a/make/wgl-CustomCCode.c b/make/wgl-CustomCCode.c new file mode 100755 index 000000000..be233fd9a --- /dev/null +++ b/make/wgl-CustomCCode.c @@ -0,0 +1,99 @@ +#include <stdio.h> + +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +ATOM oglClass = 0; + +HWND CreateDummyWindow( int x, int y, int width, int height ) { + RECT rect; + HINSTANCE hInstance; + DWORD dwExStyle; + DWORD dwStyle; + HWND hWnd; + ZeroMemory( &rect, sizeof( rect ) ); + // I don't know if we need this but it can't hurt + if( width < 0 ) { + rect.left = x + width; + rect.right = x; + } else { + rect.left = x; + rect.right = x + width; + } + if( height < 0 ) { + rect.top = y + height; + rect.bottom = y; + } else { + rect.top = y; + rect.bottom = y + height; + } + hInstance = GetModuleHandle(NULL); + + if( !oglClass ) { + WNDCLASS wc; + ZeroMemory( &wc, sizeof( wc ) ); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "OpenGL"; + if( !(oglClass = RegisterClass( &wc )) ) { + printf( "RegisterClass Failed: %d\n", GetLastError() ); + return( 0 ); + } + } + + dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwStyle = WS_OVERLAPPEDWINDOW; + if( !(hWnd=CreateWindowEx( dwExStyle, "OpenGL", "OpenGL", + dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + NULL, NULL, hInstance, NULL ) ) ) { + return( 0 ); + } + return( hWnd ); +} + +void NativeEventLoop() { + MSG msg; + BOOL ret; + // Grab windows system messages from queue + while( ( ret = GetMessage( &msg, NULL, 0, 0 ) ) != 0 ) { + if( ret == -1 ) { + printf( "Error GetMessage: %d", GetLastError() ); + } else { + DispatchMessage( &msg ); + } + } +} + +void DestroyDummyWindow(HWND handle, HDC hdc) { + // Post a close window message from shutdown hook thread to + // window message pump thread + if( !PostMessage( handle, WM_CLOSE, 0, (LPARAM) hdc ) ) { + printf( "PostMessage Failed: %d\n", GetLastError() ); + } +} + +LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch( uMsg ) { + case WM_CLOSE: + // Destroy HDC + if( ReleaseDC( hWnd, (HDC) lParam ) != 1 ) { + printf( "Error Releasing DC: %d\n", GetLastError() ); + } + // Destroy HWND + if( DestroyWindow( hWnd ) == 0 ) { + printf( "Error Destroying Window: %d\n", GetLastError() ); + } + break; + case WM_DESTROY: + // Terminate Dummy Window + PostQuitMessage(0); + return(0); + } + return DefWindowProc(hWnd,uMsg,wParam,lParam); +} diff --git a/make/wingdi-win32.cfg b/make/wingdi-win32.cfg index 622cef25d..a3c5a5ebb 100644 --- a/make/wingdi-win32.cfg +++ b/make/wingdi-win32.cfg @@ -24,3 +24,5 @@ CustomCCode /* This typedef is only needed for VC6 */ CustomCCode #if _MSC_VER <= 1200 CustomCCode typedef int intptr_t; CustomCCode #endif + +IncludeAs CustomCCode wgl-CustomCCode.c diff --git a/src/net/java/games/jogl/Animator.java b/src/net/java/games/jogl/Animator.java index e844c1501..3f5bfdeb2 100644 --- a/src/net/java/games/jogl/Animator.java +++ b/src/net/java/games/jogl/Animator.java @@ -152,7 +152,7 @@ public class Animator { while (shouldStop && thread != null) { try { wait(); - } catch (InterruptedException e) { + } catch (InterruptedException ie) { } } } diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java index 5260bda6a..7ae7b1342 100644 --- a/src/net/java/games/jogl/impl/GLContext.java +++ b/src/net/java/games/jogl/impl/GLContext.java @@ -691,17 +691,15 @@ public abstract class GLContext { their makeCurrent() implementation once the context is current. */ private void recomputeSingleThreadedWorkaround() { - if (!SingleThreadedWorkaround.doWorkaround()) { - GL gl = getGL(); - String str = gl.glGetString(GL.GL_VENDOR); - if (str != null && str.indexOf("ATI") >= 0) { - // Doing this instead of calling setRenderingThread(null) should - // be OK since we are doing this very early in the maintenance - // of the per-thread context stack, before we are actually - // pushing any GLContext objects on it - renderingThread = null; - SingleThreadedWorkaround.shouldDoWorkaround(); - } + GL gl = getGL(); + String str = gl.glGetString(GL.GL_VENDOR); + if (str != null && str.indexOf("ATI") >= 0) { + // Doing this instead of calling setRenderingThread(null) should + // be OK since we are doing this very early in the maintenance + // of the per-thread context stack, before we are actually + // pushing any GLContext objects on it + renderingThread = null; + SingleThreadedWorkaround.shouldDoWorkaround(); } } } 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"); } } |