From eb6ed9455e33975a9933b6ccf98ac9810a63683a Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Mon, 31 Jan 2005 01:09:48 +0000 Subject: Fixed Issue 118: EXCEPTION_ACCESS_VIOLATION on show of 2nd canvas (ATI-specific) The root cause of this bug was not the new DummyGL code, but severe bugs in ATI's OpenGL drivers where it appears that if an OpenGL context is ever made current on more than one thread during the lifetime of an application, problems begin to occur such as the SetPixelFormat call failing on the just the next newly-created HDC, or all subsequent SetPixelFormat calls failing on all subsequently-created HDCs. This was occurring because the single-threaded ATI workaround's automatic detection mechanism was not being enabled until the first time a context was made current, but by then it was typically too late; the context was made current on the end user's thread during e.g. Frame.show(), and if it was ever made current on another thread (like the AWT event queue thread, which is where all OpenGL operations are performed when the single-threaded workaround is enabled) then the problems would begin. The failure has only been seen on Windows so far; ATI's drivers on X11 seem to be better behaved. The workaround is to check for the presence of ATI's drivers very early during JOGL's initialization, by looking in the system directory for atioglxx.dll, and enabling the single-threaded workaround if it was found. This workaround causes the attached test case to work properly. Also added some more debugging code to make diagnosing problems like these easier in the future. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@196 232f8b59-042b-4e1e-8c03-345bb8c30851 --- src/net/java/games/jogl/impl/GLContext.java | 3 ++ .../games/jogl/impl/windows/WindowsGLContext.java | 19 +++++++- .../jogl/impl/windows/WindowsGLContextFactory.java | 51 ++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) (limited to 'src/net/java/games/jogl/impl') diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java index 2aa8e9640..4fd00dcd5 100644 --- a/src/net/java/games/jogl/impl/GLContext.java +++ b/src/net/java/games/jogl/impl/GLContext.java @@ -620,6 +620,9 @@ public abstract class GLContext { from within the destroy() implementation. */ protected synchronized void setRealized(boolean realized) { this.realized = realized; + if (DEBUG) { + System.err.println("GLContext.setRealized(" + realized + ") for context " + this); + } } /** Indicates whether the component associated with this context has diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java index 86f6debfb..f80b2a107 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java @@ -141,6 +141,11 @@ public abstract class WindowsGLContext extends GLContext { if (!WGL.wglMakeCurrent(hdc, hglrc)) { throw new GLException("Error making context current: " + WGL.GetLastError()); + } else { + if (DEBUG) { + System.err.println("wglMakeCurrent(hdc " + hdcToString(hdc) + + ", hglrc " + hdcToString(hglrc) + ") succeeded"); + } } if (created) { @@ -501,11 +506,17 @@ public abstract class WindowsGLContext extends GLContext { pixelFormat = WGL.ChoosePixelFormat(hdc, pfd); } if (!WGL.SetPixelFormat(hdc, pixelFormat, pfd)) { - throw new GLException("Unable to set pixel format"); + int lastError = WGL.GetLastError(); + if (DEBUG) { + System.err.println("SetPixelFormat failed: current context = " + WGL.wglGetCurrentContext() + + ", current DC = " + WGL.wglGetCurrentDC()); + System.err.println("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("!!! Created OpenGL context " + hglrc); + System.err.println("!!! Created OpenGL context " + hglrc + " for device context " + hdcToString(hdc) + " using pixel format " + pixelFormat); } if (hglrc == 0) { throw new GLException("Unable to create OpenGL context"); @@ -665,4 +676,8 @@ public abstract class WindowsGLContext extends GLContext { } return res; } + + protected static String hdcToString(long hdc) { + return "0x" + Long.toHexString(hdc); + } } diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java index 726091bf1..1c976c355 100644 --- a/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java +++ b/src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java @@ -43,6 +43,7 @@ import java.awt.Component; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Rectangle; +import java.io.File; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; @@ -74,6 +75,56 @@ public class WindowsGLContextFactory extends GLContextFactory { AccessController.doPrivileged( new PrivilegedAction() { public Object run() { Runtime.getRuntime().addShutdownHook( new ShutdownHook() ); + + // Test for whether we should enable the single-threaded + // workaround for ATI cards. It appears that if we make any + // OpenGL context current on more than one thread on ATI cards + // on Windows then we see random failures like the inability + // to create more OpenGL contexts, or having just the next + // OpenGL SetPixelFormat operation fail with a GetNextError() + // code of 0 (but subsequent ones on subsequently-created + // windows succeed). These kinds of failures are obviously due + // to bugs in ATI's OpenGL drivers. Through trial and error it + // was found that specifying + // -DJOGL_SINGLE_THREADED_WORKAROUND=true on the command line + // caused these problems to completely disappear. Therefore at + // least on Windows we try to enable the single-threaded + // workaround before creating any OpenGL contexts. In the + // future, if problems are encountered on other platforms and + // -DJOGL_SINGLE_THREADED_WORKAROUND=true works around them, + // we may want to implement a workaround like this on other + // platforms. + + // The algorithm here is to try to find the system directory + // (assuming it is on the same drive as TMPDIR, exposed + // through the system property java.io.tmpdir) and see whether + // a known file in the ATI drivers is present; if it is, we + // enable the single-threaded workaround. + + // If any path down this code fails, we simply bail out -- we + // don't go to great lengths to figure out if the ATI drivers + // are present. We could add more checks here in the future if + // these appear to be insufficient. + + String tmpDirProp = System.getProperty("java.io.tmpdir"); + if (tmpDirProp != null) { + File file = new File(tmpDirProp); + if (file.isAbsolute()) { + File parent = null; + do { + parent = file.getParentFile(); + if (parent != null) { + file = parent; + } + } while (parent != null); + // Now the file contains just the drive letter + file = new File(new File(new File(file, "windows"), "system32"), "atioglxx.dll"); + if (file.exists()) { + SingleThreadedWorkaround.shouldDoWorkaround(); + } + } + } + return( null ); } }); -- cgit v1.2.3