summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/classes/com/sun/opengl/impl/GLDrawableHelper.java123
-rw-r--r--src/classes/com/sun/opengl/impl/GLPbufferImpl.java20
-rwxr-xr-xsrc/classes/com/sun/opengl/impl/GLWorkerThread.java57
-rw-r--r--src/classes/javax/media/opengl/GLCanvas.java29
-rwxr-xr-xsrc/classes/javax/media/opengl/Threading.java12
5 files changed, 202 insertions, 39 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLDrawableHelper.java b/src/classes/com/sun/opengl/impl/GLDrawableHelper.java
index 614b26096..920fac624 100644
--- a/src/classes/com/sun/opengl/impl/GLDrawableHelper.java
+++ b/src/classes/com/sun/opengl/impl/GLDrawableHelper.java
@@ -49,6 +49,7 @@ public class GLDrawableHelper {
private volatile List listeners = new ArrayList();
private static final boolean DEBUG = Debug.debug("GLDrawableHelper");
private static final boolean VERBOSE = Debug.verbose();
+ private static final boolean NVIDIA_CRASH_WORKAROUND = Debug.isPropertyDefined("jogl.nvidia.crash.workaround");
private boolean autoSwapBufferMode = true;
public GLDrawableHelper() {
@@ -104,46 +105,106 @@ public class GLDrawableHelper {
GLContext context,
Runnable runnable,
Runnable initAction) {
- // Support for recursive makeCurrent() calls as well as calling
- // other drawables' display() methods from within another one's
- GLContext lastContext = GLContext.getCurrent();
- Runnable lastInitAction = (Runnable) perThreadInitAction.get();
- if (lastContext != null) {
- lastContext.release();
- }
-
- int res = 0;
- try {
- res = context.makeCurrent();
- if (res != GLContext.CONTEXT_NOT_CURRENT) {
- perThreadInitAction.set(initAction);
- if (res == GLContext.CONTEXT_CURRENT_NEW) {
- if (DEBUG) {
- System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction");
+ if (GLWorkerThread.isStarted() &&
+ GLWorkerThread.isWorkerThread()) {
+ // We're going to allow a context to be left current on the
+ // GLWorkerThread for optimization purposes
+ GLContext lastContext = GLContext.getCurrent();
+ Runnable lastInitAction = (Runnable) perThreadInitAction.get();
+ if (lastContext != null && lastContext != context) {
+ lastContext.release();
+ } else {
+ lastContext = null;
+ }
+
+ // FIXME: probably need to handle the case where the user is
+ // waiting for this context to be released; need to periodically
+ // release the context? See if anybody is waiting to make it
+ // current on another thread? (The latter would require the use
+ // of internal APIs...)
+
+ int res = 0;
+ try {
+ res = context.makeCurrent();
+ if (res != GLContext.CONTEXT_NOT_CURRENT) {
+ perThreadInitAction.set(initAction);
+ if (res == GLContext.CONTEXT_CURRENT_NEW) {
+ if (DEBUG) {
+ System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction");
+ }
+ initAction.run();
+ }
+ if (DEBUG && VERBOSE) {
+ System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running runnable");
+ }
+ runnable.run();
+ if (autoSwapBufferMode) {
+ if (drawable != null) {
+ drawable.swapBuffers();
+ }
}
- initAction.run();
}
- if (DEBUG && VERBOSE) {
- System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running runnable");
+ } finally {
+
+ // FIXME: take this out as soon as possible
+ if (NVIDIA_CRASH_WORKAROUND) {
+ try {
+ if (res != GLContext.CONTEXT_NOT_CURRENT) {
+ context.release();
+ }
+ } catch (Exception e) {
+ }
}
- runnable.run();
- if (autoSwapBufferMode) {
- if (drawable != null) {
- drawable.swapBuffers();
+
+ if (lastContext != null) {
+ int res2 = lastContext.makeCurrent();
+ if (res2 == GLContext.CONTEXT_CURRENT_NEW) {
+ lastInitAction.run();
}
}
}
- } finally {
+ } else {
+ // Support for recursive makeCurrent() calls as well as calling
+ // other drawables' display() methods from within another one's
+ GLContext lastContext = GLContext.getCurrent();
+ Runnable lastInitAction = (Runnable) perThreadInitAction.get();
+ if (lastContext != null) {
+ lastContext.release();
+ }
+
+ int res = 0;
try {
+ res = context.makeCurrent();
if (res != GLContext.CONTEXT_NOT_CURRENT) {
- context.release();
+ perThreadInitAction.set(initAction);
+ if (res == GLContext.CONTEXT_CURRENT_NEW) {
+ if (DEBUG) {
+ System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction");
+ }
+ initAction.run();
+ }
+ if (DEBUG && VERBOSE) {
+ System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running runnable");
+ }
+ runnable.run();
+ if (autoSwapBufferMode) {
+ if (drawable != null) {
+ drawable.swapBuffers();
+ }
+ }
}
- } catch (Exception e) {
- }
- if (lastContext != null) {
- int res2 = lastContext.makeCurrent();
- if (res2 == GLContext.CONTEXT_CURRENT_NEW) {
- lastInitAction.run();
+ } finally {
+ try {
+ if (res != GLContext.CONTEXT_NOT_CURRENT) {
+ context.release();
+ }
+ } catch (Exception e) {
+ }
+ if (lastContext != null) {
+ int res2 = lastContext.makeCurrent();
+ if (res2 == GLContext.CONTEXT_CURRENT_NEW) {
+ lastInitAction.run();
+ }
}
}
}
diff --git a/src/classes/com/sun/opengl/impl/GLPbufferImpl.java b/src/classes/com/sun/opengl/impl/GLPbufferImpl.java
index 196ea7223..feb9d3512 100644
--- a/src/classes/com/sun/opengl/impl/GLPbufferImpl.java
+++ b/src/classes/com/sun/opengl/impl/GLPbufferImpl.java
@@ -172,8 +172,12 @@ public class GLPbufferImpl implements GLPbuffer {
PropertyChangeListener listener) {}
public void destroy() {
- context.destroy();
- pbufferDrawable.destroy();
+ if (Threading.isSingleThreaded() &&
+ !Threading.isOpenGLThread()) {
+ Threading.invokeOnOpenGLThread(destroyAction);
+ } else {
+ destroyAction.run();
+ }
}
public int getFloatingPointMode() {
@@ -238,4 +242,16 @@ public class GLPbufferImpl implements GLPbuffer {
}
private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction =
new SwapBuffersOnEventDispatchThreadAction();
+
+ class DestroyAction implements Runnable {
+ public void run() {
+ GLContext current = GLContext.getCurrent();
+ if (current == context) {
+ context.release();
+ }
+ context.destroy();
+ pbufferDrawable.destroy();
+ }
+ }
+ private DestroyAction destroyAction = new DestroyAction();
}
diff --git a/src/classes/com/sun/opengl/impl/GLWorkerThread.java b/src/classes/com/sun/opengl/impl/GLWorkerThread.java
index 52ada9bac..4091d1a77 100755
--- a/src/classes/com/sun/opengl/impl/GLWorkerThread.java
+++ b/src/classes/com/sun/opengl/impl/GLWorkerThread.java
@@ -40,6 +40,8 @@
package com.sun.opengl.impl;
import java.lang.reflect.InvocationTargetException;
+import java.security.*;
+import javax.media.opengl.*;
/** Singleton thread upon which all OpenGL work is performed by
default. Unfortunately many vendors' OpenGL drivers are not really
@@ -73,6 +75,7 @@ public class GLWorkerThread {
lock = new Object();
thread = new Thread(new WorkerRunnable(),
"JOGL GLWorkerThread");
+ thread.setDaemon(true);
started = true;
synchronized (lock) {
thread.start();
@@ -81,6 +84,59 @@ public class GLWorkerThread {
} catch (InterruptedException e) {
}
}
+
+ /*
+
+ // Note: it appears that there is a bug in NVidia's current
+ // drivers where if a context was ever made current on a
+ // given thread and that thread has exited before program
+ // exit, a crash occurs in the drivers. Releasing the
+ // context from the given thread does not work around the
+ // problem.
+ //
+ // For the time being, we're going to work around this
+ // problem by not terminating the GLWorkerThread. In theory,
+ // shutting down the GLWorkerThread cleanly could be a good
+ // general solution to the problem of needing to
+ // cooperatively terminate all Animators at program exit.
+ //
+ // It appears that this doesn't even work around all of the
+ // kinds of crashes. Causing the context to be unilaterally
+ // released from the GLWorkerThread after each invocation
+ // seems to work around all of the kinds of crashes seen.
+ //
+ // These appear to be similar to the kinds of crashes seen
+ // when the Java2D/OpenGL pipeline terminates, and those are
+ // a known issue being fixed, so presumably these will be
+ // fixed in NVidia's next driver set.
+
+ // Install shutdown hook to terminate daemon thread more or
+ // less cooperatively
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ Object lockTemp = lock;
+ if (lockTemp == null) {
+ // Already terminating (?)
+ return;
+ }
+ synchronized (lockTemp) {
+ shouldTerminate = true;
+ lockTemp.notifyAll();
+ try {
+ lockTemp.wait(500);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ });
+ return null;
+ }
+ });
+
+ */
+
} else {
throw new RuntimeException("Should not start GLWorkerThread twice");
}
@@ -143,6 +199,7 @@ public class GLWorkerThread {
}
if (shouldTerminate) {
+ lock.notifyAll();
thread = null;
lock = null;
return;
diff --git a/src/classes/javax/media/opengl/GLCanvas.java b/src/classes/javax/media/opengl/GLCanvas.java
index 0329e4017..d555a1df0 100644
--- a/src/classes/javax/media/opengl/GLCanvas.java
+++ b/src/classes/javax/media/opengl/GLCanvas.java
@@ -166,11 +166,19 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
<B>Overrides:</B>
<DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
public void removeNotify() {
- context.destroy();
- drawable.setRealized(false);
- super.removeNotify();
- if (DEBUG) {
- System.err.println("GLCanvas.removeNotify()");
+ try {
+ if (Threading.isSingleThreaded() &&
+ !Threading.isOpenGLThread()) {
+ Threading.invokeOnOpenGLThread(destroyAction);
+ } else {
+ context.destroy();
+ }
+ } finally {
+ drawable.setRealized(false);
+ super.removeNotify();
+ if (DEBUG) {
+ System.err.println("GLCanvas.removeNotify()");
+ }
}
}
@@ -289,6 +297,17 @@ public class GLCanvas extends Canvas implements GLAutoDrawable {
private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction =
new SwapBuffersOnEventDispatchThreadAction();
+ class DestroyAction implements Runnable {
+ public void run() {
+ GLContext current = GLContext.getCurrent();
+ if (current == context) {
+ context.release();
+ }
+ context.destroy();
+ }
+ }
+ private DestroyAction destroyAction = new DestroyAction();
+
// Disables the AWT's erasing of this Canvas's background on Windows
// in Java SE 6. This internal API is not available in previous
// releases, but the system property
diff --git a/src/classes/javax/media/opengl/Threading.java b/src/classes/javax/media/opengl/Threading.java
index 7aa57def5..f8d54d95d 100755
--- a/src/classes/javax/media/opengl/Threading.java
+++ b/src/classes/javax/media/opengl/Threading.java
@@ -197,7 +197,17 @@ public class Threading {
return EventQueue.isDispatchThread();
}
case WORKER:
- return GLWorkerThread.isWorkerThread();
+ if (Java2D.isOGLPipelineActive()) {
+ // FIXME: ideally only the QFT would be considered to be the
+ // "OpenGL thread", but we can not currently run all of JOGL's
+ // OpenGL work on that thread. For now, run the GLJPanel's
+ // Java2D/JOGL bridge on the QFT but everything else on the
+ // worker thread, except when we're already on the QFT.
+ return (Java2D.isQueueFlusherThread() ||
+ GLWorkerThread.isWorkerThread());
+ } else {
+ return GLWorkerThread.isWorkerThread();
+ }
default:
throw new InternalError("Illegal single-threading mode " + mode);
}