aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/games/jogl/impl
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/games/jogl/impl')
-rw-r--r--src/net/java/games/jogl/impl/FunctionAvailabilityCache.java6
-rw-r--r--src/net/java/games/jogl/impl/GLContext.java20
-rw-r--r--src/net/java/games/jogl/impl/GLPbufferImpl.java59
-rw-r--r--src/net/java/games/jogl/impl/NativeLibLoader.java61
-rwxr-xr-xsrc/net/java/games/jogl/impl/SingleThreadedWorkaround.java38
-rw-r--r--src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java1
-rw-r--r--src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java7
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsGLContext.java114
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsGLContextFactory.java51
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java3
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java21
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java94
-rw-r--r--src/net/java/games/jogl/impl/x11/X11GLContext.java60
-rw-r--r--src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java2
-rw-r--r--src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java33
15 files changed, 436 insertions, 134 deletions
diff --git a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
index bceb66f9b..a4b67b5e8 100644
--- a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
+++ b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
@@ -52,7 +52,7 @@ import java.lang.reflect.*;
* and display.
*/
public final class FunctionAvailabilityCache {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("FunctionAvailabilityCache");
FunctionAvailabilityCache(GLContext context)
{
@@ -114,6 +114,10 @@ public final class FunctionAvailabilityCache {
}
String allAvailableExtensions =
gl.glGetString(GL.GL_EXTENSIONS) + " " + context.getPlatformExtensionsString();
+ if (DEBUG) {
+ System.err.println("!!! Available extensions: " + allAvailableExtensions);
+ System.err.println("!!! GL vendor: " + gl.glGetString(GL.GL_VENDOR));
+ }
StringTokenizer tok = new StringTokenizer(allAvailableExtensions);
while (tok.hasMoreTokens()) {
String availableExt = tok.nextToken().trim();
diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java
index 2aa8e9640..17667fbce 100644
--- a/src/net/java/games/jogl/impl/GLContext.java
+++ b/src/net/java/games/jogl/impl/GLContext.java
@@ -44,7 +44,7 @@ import net.java.games.jogl.*;
import net.java.games.gluegen.runtime.*;
public abstract class GLContext {
- protected static final boolean DEBUG = false;
+ protected static final boolean DEBUG = Debug.debug("GLContext");
static {
NativeLibLoader.load();
@@ -145,11 +145,7 @@ public abstract class GLContext {
GLCapabilitiesChooser chooser,
GLContext shareWith) {
this.component = component;
- try {
- this.capabilities = (GLCapabilities) capabilities.clone();
- } catch (CloneNotSupportedException e) {
- throw new GLException(e);
- }
+ this.capabilities = (GLCapabilities) capabilities.clone();
this.chooser = chooser;
setGL(createGL());
functionAvailability = new FunctionAvailabilityCache(this);
@@ -255,6 +251,15 @@ public abstract class GLContext {
if (isReshape) {
deferredReshapeAction = runnable;
}
+
+ // Clean up after ourselves on the way out.
+ // NOTE that this is an abbreviated version of the code below
+ // and should probably be refactored/cleaned up -- this bug
+ // fix was done without a lot of intense thought about the
+ // situation
+ if (curContext != null) {
+ curContext.makeCurrent(curInitAction);
+ }
return;
}
if (DEBUG) {
@@ -620,6 +625,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/GLPbufferImpl.java b/src/net/java/games/jogl/impl/GLPbufferImpl.java
index 2fb927c92..be0f23398 100644
--- a/src/net/java/games/jogl/impl/GLPbufferImpl.java
+++ b/src/net/java/games/jogl/impl/GLPbufferImpl.java
@@ -40,6 +40,7 @@
package net.java.games.jogl.impl;
import java.awt.Dimension;
+import java.awt.EventQueue;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
@@ -61,7 +62,9 @@ public class GLPbufferImpl implements GLPbuffer {
}
public void display() {
- context.invokeGL(displayAction, false, initAction);
+ maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction,
+ displayAction,
+ false);
}
public void setSize(int width, int height) {
@@ -107,7 +110,7 @@ public class GLPbufferImpl implements GLPbuffer {
}
void willSetRenderingThread() {
- context.willSetRenderingThread();
+ // Not supported for pbuffers
}
public void setRenderingThread(Thread currentThreadOrNull) throws GLException {
@@ -135,7 +138,7 @@ public class GLPbufferImpl implements GLPbuffer {
}
public void swapBuffers() {
- context.invokeGL(swapBuffersAction, false, initAction);
+ maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction, false);
}
public boolean canCreateOffscreenDrawable() {
@@ -149,10 +152,14 @@ public class GLPbufferImpl implements GLPbuffer {
}
public void bindTexture() {
+ // Doesn't make much sense to try to do this on the event dispatch
+ // thread given that it has to be called while the context is current
context.bindPbufferToTexture();
}
public void releaseTexture() {
+ // Doesn't make much sense to try to do this on the event dispatch
+ // thread given that it has to be called while the context is current
context.releasePbufferFromTexture();
}
@@ -196,10 +203,38 @@ public class GLPbufferImpl implements GLPbuffer {
return isInitialized;
}
+ public void destroy() {
+ context.destroy();
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
+ private void maybeDoSingleThreadedWorkaround(Runnable eventDispatchThreadAction,
+ Runnable invokeGLAction,
+ boolean isReshape) {
+ if (SingleThreadedWorkaround.doWorkaround() && !EventQueue.isDispatchThread()) {
+ try {
+ // Reshape events must not block on the event queue due to the
+ // possibility of deadlocks during initial component creation.
+ // This solution is not optimal, because it changes the
+ // semantics of reshape() to have some of the processing being
+ // done asynchronously, but at least it preserves the
+ // semantics of the single-threaded workaround.
+ if (!isReshape) {
+ EventQueue.invokeAndWait(eventDispatchThreadAction);
+ } else {
+ EventQueue.invokeLater(eventDispatchThreadAction);
+ }
+ } catch (Exception e) {
+ throw new GLException(e);
+ }
+ } else {
+ context.invokeGL(invokeGLAction, isReshape, initAction);
+ }
+ }
+
class InitAction implements Runnable {
public void run() {
drawableHelper.init(GLPbufferImpl.this);
@@ -221,4 +256,22 @@ public class GLPbufferImpl implements GLPbuffer {
}
}
private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
+
+ // Workaround for ATI driver bugs related to multithreading issues
+ // like simultaneous rendering via Animators to canvases that are
+ // being resized on the AWT event dispatch thread
+ class DisplayOnEventDispatchThreadAction implements Runnable {
+ public void run() {
+ context.invokeGL(displayAction, false, initAction);
+ }
+ }
+ private DisplayOnEventDispatchThreadAction displayOnEventDispatchThreadAction =
+ new DisplayOnEventDispatchThreadAction();
+ class SwapBuffersOnEventDispatchThreadAction implements Runnable {
+ public void run() {
+ context.invokeGL(swapBuffersAction, false, initAction);
+ }
+ }
+ private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction =
+ new SwapBuffersOnEventDispatchThreadAction();
}
diff --git a/src/net/java/games/jogl/impl/NativeLibLoader.java b/src/net/java/games/jogl/impl/NativeLibLoader.java
index cf2b06939..0c2420955 100644
--- a/src/net/java/games/jogl/impl/NativeLibLoader.java
+++ b/src/net/java/games/jogl/impl/NativeLibLoader.java
@@ -42,34 +42,45 @@ package net.java.games.jogl.impl;
import java.security.*;
public class NativeLibLoader {
- static {
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- boolean isOSX = System.getProperty("os.name").equals("Mac OS X");
- if (!isOSX) {
- try {
- System.loadLibrary("jawt");
- } catch (UnsatisfiedLinkError e) {
- // Accessibility technologies load JAWT themselves; safe to continue
- // as long as JAWT is loaded by any loader
- if (e.getMessage().indexOf("already loaded") == -1) {
- throw e;
- }
- }
- }
- System.loadLibrary("jogl");
+ private static volatile boolean doLoading = true;
+ private static volatile boolean doneLoading = false;
- // Workaround for 4845371.
- // Make sure the first reference to the JNI GetDirectBufferAddress is done
- // from a privileged context so the VM's internal class lookups will succeed.
- JAWT jawt = new JAWT();
- JAWTFactory.JAWT_GetAWT(jawt);
+ public static void disableLoading() {
+ doLoading = false;
+ }
- return null;
- }
- });
+ public static void enableLoading() {
+ doLoading = true;
}
- public static void load() {
+ public static synchronized void load() {
+ if (doLoading && !doneLoading) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ boolean isOSX = System.getProperty("os.name").equals("Mac OS X");
+ if (!isOSX) {
+ try {
+ System.loadLibrary("jawt");
+ } catch (UnsatisfiedLinkError e) {
+ // Accessibility technologies load JAWT themselves; safe to continue
+ // as long as JAWT is loaded by any loader
+ if (e.getMessage().indexOf("already loaded") == -1) {
+ throw e;
+ }
+ }
+ }
+ System.loadLibrary("jogl");
+
+ // Workaround for 4845371.
+ // Make sure the first reference to the JNI GetDirectBufferAddress is done
+ // from a privileged context so the VM's internal class lookups will succeed.
+ JAWT jawt = new JAWT();
+ JAWTFactory.JAWT_GetAWT(jawt);
+
+ return null;
+ }
+ });
+ doneLoading = true;
+ }
}
}
diff --git a/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java b/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
index 9dbed9e43..7b9fa46c4 100755
--- a/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
+++ b/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
@@ -45,24 +45,40 @@ import java.security.PrivilegedAction;
/** Encapsulates the workaround of running all display operations on
the AWT event queue thread for the purposes of working around
problems seen primarily on ATI cards when rendering into a surface
- that is simultaneously being resized by the event queue thread */
+ that is simultaneously being resized by the event queue thread.
+ <p>
+
+ As of JOGL 1.1 b10, this property defaults to true. Problems have
+ been seen on Windows, Linux and Mac OS X platforms that are solved
+ by switching all OpenGL work to a single thread, which this
+ workaround provides. The forthcoming JSR-231 work will rethink how
+ such a mechanism is implemented, but the core result of needing to
+ perform all OpenGL work on a single thread for best compatibility
+ will remain.
+*/
public class SingleThreadedWorkaround {
- private static boolean ATI_WORKAROUND = false;
+ private static boolean singleThreadedWorkaround = true;
// If the user specified the workaround's system property (either
// true or false), don't let the automatic detection have any effect
private static boolean systemPropertySpecified = false;
- private static boolean verbose = false;
static {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
- String workaround = System.getProperty("ATI_WORKAROUND");
- if (workaround != null) {
+ String workaround = System.getProperty("jogl.1thread");
+ if (workaround == null) {
+ // Old system property (for compatibility)
+ workaround = System.getProperty("JOGL_SINGLE_THREADED_WORKAROUND");
+ }
+ if (workaround == null) {
+ // Older system property (for compatibility)
+ workaround = System.getProperty("ATI_WORKAROUND");
+ }
+ if (workaround != null && (!workaround.equals("auto"))) {
systemPropertySpecified = true;
- ATI_WORKAROUND = Boolean.valueOf(workaround).booleanValue();
+ singleThreadedWorkaround = Boolean.valueOf(workaround).booleanValue();
}
- verbose = (System.getProperty("jogl.verbose") != null);
printWorkaroundNotice();
return null;
}
@@ -71,18 +87,18 @@ public class SingleThreadedWorkaround {
public static void shouldDoWorkaround() {
if (!systemPropertySpecified) {
- ATI_WORKAROUND = true;
+ singleThreadedWorkaround = true;
printWorkaroundNotice();
}
}
public static boolean doWorkaround() {
- return ATI_WORKAROUND;
+ return singleThreadedWorkaround;
}
private static void printWorkaroundNotice() {
- if (ATI_WORKAROUND && verbose) {
- System.err.println("Using ATI workaround of dispatching display() on event thread");
+ if (singleThreadedWorkaround && Debug.verbose()) {
+ System.err.println("Using single-threaded workaround of dispatching display() on event thread");
}
}
}
diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java
index f8af120da..3c8027e7c 100644
--- a/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java
+++ b/src/net/java/games/jogl/impl/macosx/MacOSXGLContext.java
@@ -132,6 +132,7 @@ public abstract class MacOSXGLContext extends GLContext
}
nsContext = CGL.createContext(share,
nsView,
+ capabilities.getDoubleBuffered() ? 1 : 0,
capabilities.getRedBits(),
capabilities.getGreenBits(),
capabilities.getBlueBits(),
diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
index 6ac854090..8e65ce1f3 100644
--- a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
@@ -4,8 +4,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class MacOSXPbufferGLContext extends MacOSXGLContext {
-
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("MacOSXPbufferGLContext");
protected int initWidth;
protected int initHeight;
@@ -131,6 +130,10 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
return false;
}
+ protected void destroyImpl() throws GLException {
+ destroyPBuffer();
+ }
+
public void swapBuffers() throws GLException {
// FIXME: do we need to do anything if the pbuffer is double-buffered?
}
diff --git a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java
index eed383794..37a3f5359 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsGLContext.java
@@ -61,6 +61,7 @@ public abstract class WindowsGLContext extends GLContext {
private GLProcAddressTable glProcAddressTable;
// Handle to GLU32.dll
private long hglu32;
+ private boolean haveWGLARBPbuffer = true;
private static final int MAX_PFORMATS = 256;
private static final int MAX_ATTRIBS = 256;
@@ -141,10 +142,17 @@ 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) {
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) {
@@ -154,7 +162,8 @@ public abstract class WindowsGLContext extends GLContext {
}
if (!WGL.wglShareLists(hglrc2, hglrc)) {
throw new GLException("wglShareLists(0x" + Long.toHexString(hglrc2) +
- ", 0x" + Long.toHexString(hglrc) + ") failed");
+ ", 0x" + Long.toHexString(hglrc) + ") failed: error code " +
+ WGL.GetLastError());
}
}
GLContextShareSet.contextCreated(this);
@@ -302,6 +311,8 @@ public abstract class WindowsGLContext extends GLContext {
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];
@@ -408,46 +419,54 @@ public abstract class WindowsGLContext extends GLContext {
// 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, iresults)) {
- 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
- // 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;
- }
+ if (dummyGL.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, iresults)) {
+ 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, iresults)) {
- throw new GLException("Error getting pixel format attributes for pixel format " + (i + 1) + " of device context");
+ availableCaps = new GLCapabilities[numFormats];
+ for (int i = 0; i < numFormats; i++) {
+ if (!dummyGL.wglGetPixelFormatAttribivARB(hdc, i+1, 0, niattribs, iattributes, iresults)) {
+ 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());
}
- availableCaps[i] = iattributes2GLCapabilities(iattributes, iresults, niattribs, true);
- }
- if( freeWGLC ) {
- WGL.wglMakeCurrent( 0, 0 );
}
- } else {
+ }
+
+ if (!gotAvailableCaps) {
if (DEBUG) {
System.err.println("Using ChoosePixelFormat because no wglChoosePixelFormatARB: dummyGL = " + dummyGL);
}
@@ -467,6 +486,7 @@ public abstract class WindowsGLContext extends GLContext {
availableCaps[i] = pfd2GLCapabilities(pfd);
}
}
+
// Supply information to chooser
pixelFormat = chooser.chooseCapabilities(capabilities, availableCaps, recommendedPixelFormat);
if ((pixelFormat < 0) || (pixelFormat >= numFormats)) {
@@ -490,11 +510,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");
@@ -654,4 +680,12 @@ public abstract class WindowsGLContext extends GLContext {
}
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 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 );
}
});
diff --git a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
index 9e871caba..5743253a0 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
@@ -172,7 +172,8 @@ public class WindowsOffscreenGLContext extends WindowsGLContext {
}
hbitmap = WGL.CreateDIBSection(hdc, info, WGL.DIB_RGB_COLORS, 0, 0, 0);
if (hbitmap == 0) {
- throw new GLException("Error creating offscreen bitmap");
+ 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");
diff --git a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java
index 3bfdee5d1..de13be0a1 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsOnscreenGLContext.java
@@ -61,6 +61,25 @@ public class WindowsOnscreenGLContext extends WindowsGLContext {
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);
@@ -83,7 +102,7 @@ public class WindowsOnscreenGLContext extends WindowsGLContext {
}
public boolean canCreatePbufferContext() {
- return true;
+ return haveWGLARBPbuffer();
}
public synchronized GLContext createPbufferContext(GLCapabilities capabilities,
diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
index d3795905f..f0ce74d9d 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
@@ -43,7 +43,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class WindowsPbufferGLContext extends WindowsGLContext {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("WindowsPbufferGLContext");
private int initWidth;
private int initHeight;
@@ -75,6 +75,13 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
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 boolean canCreatePbufferContext() {
@@ -128,6 +135,13 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
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();
@@ -228,9 +242,10 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
iattributes[5] = GL.WGL_FLOAT_COMPONENTS_NV;
iattributes[6] = GL.WGL_SAMPLE_BUFFERS_EXT;
iattributes[7] = GL.WGL_SAMPLES_EXT;
- int[] ivalues = new int[8];
+ 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, 8, iattributes, ivalues)) {
+ if (!gl.wglGetPixelFormatAttribivARB(parentHdc, pformats[i], 0, 9, iattributes, ivalues)) {
throw new GLException("Error while querying pixel format " + pformats[i] +
"'s (index " + i + "'s) capabilities for debugging");
}
@@ -245,38 +260,49 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
if (ivalues[5] != 0) {
System.err.print(" [float]");
}
+ if (ivalues[8] != 0) {
+ System.err.print(" [pbuffer]");
+ }
System.err.println();
}
}
- int format = pformats[0];
+ 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;
+ // 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;
- }
+ 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_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_MIPMAP_TEXTURE_ARB;
+ iattributes[niattribs++] = GL.GL_FALSE;
- iattributes[niattribs++] = GL.WGL_PBUFFER_LARGEST_ARB;
- iattributes[niattribs++] = GL.GL_FALSE;
- }
+ iattributes[niattribs++] = GL.WGL_PBUFFER_LARGEST_ARB;
+ iattributes[niattribs++] = GL.GL_FALSE;
+ }
+
+ iattributes[niattribs++] = 0;
- iattributes[niattribs++] = 0;
+ tmpBuffer = gl.wglCreatePbufferARB(parentHdc, format, initWidth, initHeight, iattributes);
+ ++whichFormat;
+ } while ((tmpBuffer == 0) && (whichFormat < nformats));
- long tmpBuffer = gl.wglCreatePbufferARB(parentHdc, format, initWidth, initHeight, iattributes);
if (tmpBuffer == 0) {
- throw new GLException("pbuffer creation error: wglCreatePbufferARB() failed: " + wglGetLastError());
+ throw new GLException("pbuffer creation error: wglCreatePbufferARB() failed: tried " + nformats +
+ " pixel formats, last error was: " + wglGetLastError());
}
// Get the device context.
@@ -308,10 +334,16 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
if (buffer == 0) {
// pbuffer not instantiated yet
+ if (DEBUG) {
+ System.err.println("pbuffer not instantiated yet");
+ }
return false;
}
boolean res = super.makeCurrent(initAction);
+ if (DEBUG) {
+ System.err.println("super.makeCurrent() = " + res + ", created = " + created);
+ }
if (created) {
// Initialize render-to-texture support if requested
rtt = capabilities.getOffscreenRenderToTexture();
@@ -396,6 +428,22 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
}
}
+ protected void destroyImpl() throws GLException {
+ if (hglrc != 0) {
+ super.destroyImpl();
+ // Must release DC and pbuffer
+ GL gl = getGL();
+ 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.
diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java
index 359d0c95c..4709691f8 100644
--- a/src/net/java/games/jogl/impl/x11/X11GLContext.java
+++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java
@@ -40,6 +40,7 @@
package net.java.games.jogl.impl.x11;
import java.awt.Component;
+import java.security.*;
import java.util.*;
import net.java.games.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX
import net.java.games.jogl.*;
@@ -64,11 +65,24 @@ public abstract class X11GLContext extends GLContext {
// so that we can implement displayImpl() (which must be done when
// the context is not current)
protected long mostRecentDisplay;
+ // There is currently a bug on Linux/AMD64 distributions in glXGetProcAddressARB
+ protected static boolean isLinuxAMD64;
static {
functionNameMap = new HashMap();
functionNameMap.put("glAllocateMemoryNV", "glXAllocateMemoryNV");
functionNameMap.put("glFreeMemoryNV", "glXFreeMemoryNV");
+
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ String os = System.getProperty("os.name").toLowerCase();
+ String arch = System.getProperty("os.arch").toLowerCase();
+ if (os.startsWith("linux") && arch.equals("amd64")) {
+ isLinuxAMD64 = true;
+ }
+ return null;
+ }
+ });
}
public X11GLContext(Component component,
@@ -173,6 +187,7 @@ public abstract class X11GLContext extends GLContext {
}
protected void destroyImpl() throws GLException {
+ lockAWT();
if (context != 0) {
GLX.glXDestroyContext(mostRecentDisplay, context);
if (DEBUG) {
@@ -180,12 +195,16 @@ public abstract class X11GLContext extends GLContext {
}
context = 0;
}
+ unlockAWT();
}
public abstract void swapBuffers() throws GLException;
protected long dynamicLookupFunction(String glFuncName) {
- long res = GLX.glXGetProcAddressARB(glFuncName);
+ long res = 0;
+ if (!isLinuxAMD64) {
+ res = GLX.glXGetProcAddressARB(glFuncName);
+ }
if (res == 0) {
// GLU routines aren't known to the OpenGL function lookup
res = GLX.dlsym(glFuncName);
@@ -218,6 +237,22 @@ public abstract class X11GLContext extends GLContext {
if (!GLX.glXQueryVersion(display, major, minor)) {
throw new GLException("glXQueryVersion failed");
}
+ if (DEBUG) {
+ System.err.println("!!! GLX version: major " + major[0] +
+ ", minor " + minor[0]);
+ }
+
+ // Work around bugs in ATI's Linux drivers where they report they
+ // only implement GLX version 1.2 but actually do support pbuffers
+ if (major[0] == 1 && minor[0] == 2) {
+ GL gl = getGL();
+ String str = gl.glGetString(GL.GL_VENDOR);
+ if (str != null && str.indexOf("ATI") >= 0) {
+ isGLX13 = true;
+ return;
+ }
+ }
+
isGLX13 = ((major[0] > 1) || (minor[0] > 2));
}
@@ -235,11 +270,20 @@ public abstract class X11GLContext extends GLContext {
throw new GLException("Context not current");
}
if (!glXQueryExtensionsStringInitialized) {
- glXQueryExtensionsStringAvailable = (GLX.glXGetProcAddressARB("glXQueryExtensionsString") != 0);
+ glXQueryExtensionsStringAvailable = (dynamicLookupFunction("glXQueryExtensionsString") != 0);
glXQueryExtensionsStringInitialized = true;
}
if (glXQueryExtensionsStringAvailable) {
- return GLX.glXQueryExtensionsString(display, GLX.DefaultScreen(display));
+ lockAWT();
+ try {
+ String ret = GLX.glXQueryExtensionsString(display, GLX.DefaultScreen(display));
+ if (DEBUG) {
+ System.err.println("!!! GLX extensions: " + ret);
+ }
+ return ret;
+ } finally {
+ unlockAWT();
+ }
} else {
return "";
}
@@ -364,4 +408,14 @@ public abstract class X11GLContext extends GLContext {
protected long getContext() {
return context;
}
+
+ // These synchronization primitives prevent the AWT from making
+ // requests from the X server asynchronously to this code.
+ protected void lockAWT() {
+ getJAWT().Lock();
+ }
+
+ protected void unlockAWT() {
+ getJAWT().Unlock();
+ }
}
diff --git a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java
index 2aa85e9f8..a22367091 100644
--- a/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java
+++ b/src/net/java/games/jogl/impl/x11/X11OffscreenGLContext.java
@@ -44,7 +44,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class X11OffscreenGLContext extends X11GLContext {
- private int pixmap;
+ private long pixmap;
private boolean isDoubleBuffered;
// Width and height of the underlying bitmap
private int width;
diff --git a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
index 5ab976870..5b6df1843 100644
--- a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
@@ -43,7 +43,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class X11PbufferGLContext extends X11GLContext {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("X11PbufferGLContext");
private int initWidth;
private int initHeight;
@@ -209,7 +209,7 @@ public class X11PbufferGLContext extends X11GLContext {
iattributes[niattribs++] = 0;
- int tmpBuffer = GLX.glXCreatePbuffer(display, fbConfig, iattributes);
+ long tmpBuffer = GLX.glXCreatePbuffer(display, fbConfig, iattributes);
if (tmpBuffer == 0) {
// FIXME: query X error code for detail error message
throw new GLException("pbuffer creation error: glXCreatePbuffer() failed");
@@ -251,10 +251,7 @@ public class X11PbufferGLContext extends X11GLContext {
created = true;
}
- // FIXME: this cast to int would be wrong on 64-bit platforms
- // where the argument type to glXMakeCurrent would change (should
- // probably make GLXDrawable, and maybe XID, Opaque as long)
- if (!GLX.glXMakeContextCurrent(display, (int) buffer, (int) buffer, context)) {
+ if (!GLX.glXMakeContextCurrent(display, buffer, buffer, context)) {
throw new GLException("Error making context current");
}
@@ -318,6 +315,19 @@ public class X11PbufferGLContext extends X11GLContext {
}
}
+ protected void destroyImpl() throws GLException {
+ lockAWT();
+ try {
+ if (context != 0) {
+ super.destroyImpl();
+ GLX.glXDestroyPbuffer(display, buffer);
+ buffer = 0;
+ }
+ } finally {
+ unlockAWT();
+ }
+ }
+
public void swapBuffers() throws GLException {
// FIXME: do we need to do anything if the pbuffer is double-buffered?
}
@@ -329,15 +339,4 @@ public class X11PbufferGLContext extends X11GLContext {
}
return tmp[0];
}
-
- // These synchronization primitives, which prevent the AWT from
- // making requests from the X server asynchronously to this code,
- // are required for pbuffers to work properly on X11.
- private void lockAWT() {
- getJAWT().Lock();
- }
-
- private void unlockAWT() {
- getJAWT().Unlock();
- }
}