diff options
author | Kenneth Russel <kbrussel@alum.mit.edu> | 2006-02-21 08:06:07 +0000 |
---|---|---|
committer | Kenneth Russel <kbrussel@alum.mit.edu> | 2006-02-21 08:06:07 +0000 |
commit | c9faf1391d8ab972fb0f1b231c33a5bf02be5051 (patch) | |
tree | db5a8266349cd6f730c0cc22e826b04014c40960 /src | |
parent | c15bfa2dce50ae132736dd678192f819d5ba2404 (diff) |
Added GLWorkerThread for moving OpenGL-related work onto a different
thread than the EDT. Added option for it in Threading; needs testing
on more platforms.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@625 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src')
-rwxr-xr-x | src/classes/com/sun/opengl/impl/GLWorkerThread.java | 155 | ||||
-rwxr-xr-x | src/classes/javax/media/opengl/Threading.java | 98 |
2 files changed, 224 insertions, 29 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLWorkerThread.java b/src/classes/com/sun/opengl/impl/GLWorkerThread.java new file mode 100755 index 000000000..7c1d7413b --- /dev/null +++ b/src/classes/com/sun/opengl/impl/GLWorkerThread.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.sun.opengl.impl; + +/** Singleton thread upon which all OpenGL work is performed by + default. Unfortunately many vendors' OpenGL drivers are not really + thread-safe and stability is much improved by performing OpenGL + work on at most one thread. This is the default behavior of the + GLAutoDrawable implementations according to the {@link + javax.media.opengl.Threading Threading} class. The GLWorkerThread + replaces the original AWT event queue thread-based mechanism for + two reasons: first, more than one AWT event queue thread may be + spawned, for example if a dialog is being shown; second, it avoids + blocking the AWT event queue thread during OpenGL rendering. */ + +public class GLWorkerThread { + private static volatile boolean started; + private static volatile Thread thread; + private static Object lock; + private static volatile boolean shouldTerminate; + + // The Runnable to execute on the worker thread -- no need for a + // queue since we don't have an invokeLater() primitive + private static volatile Runnable work; + + /** Should only be called by Threading class if creation of the + GLWorkerThread was requested via the opengl.1thread system + property. */ + public static void start() { + if (!started) { + synchronized (GLWorkerThread.class) { + if (!started) { + lock = new Object(); + thread = new Thread(new WorkerRunnable(), + "JOGL GLWorkerThread"); + started = true; + synchronized (lock) { + thread.start(); + try { + lock.wait(); + } catch (InterruptedException e) { + } + } + } else { + throw new RuntimeException("Should not start GLWorkerThread twice"); + } + } + } + } + + public static void invokeAndWait(Runnable runnable) { + if (!started) { + throw new RuntimeException("May not invokeAndWait on worker thread without starting it first"); + } + + Object lockTemp = lock; + if (lockTemp == null) { + return; // Terminating + } + + synchronized (lockTemp) { + if (thread == null) { + // Terminating + return; + } + + work = runnable; + lock.notifyAll(); + try { + lock.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + /** Indicates whether the OpenGL worker thread was started, i.e., + whether it is currently in use. */ + public static boolean isStarted() { + return started; + } + + /** Indicates whether the current thread is the OpenGL worker + thread. */ + public static boolean isWorkerThread() { + return (Thread.currentThread() == thread); + } + + static class WorkerRunnable implements Runnable { + public void run() { + // Notify starting thread that we're ready + synchronized (lock) { + lock.notifyAll(); + } + + while (!shouldTerminate) { + synchronized (lock) { + while ((work == null) && !shouldTerminate) { + try { + lock.wait(); + } catch (InterruptedException e) { + } + } + + if (shouldTerminate) { + thread = null; + lock = null; + return; + } + + work.run(); + work = null; + lock.notifyAll(); + } + } + } + } +} diff --git a/src/classes/javax/media/opengl/Threading.java b/src/classes/javax/media/opengl/Threading.java index 2799edc58..2f1aa4fb7 100755 --- a/src/classes/javax/media/opengl/Threading.java +++ b/src/classes/javax/media/opengl/Threading.java @@ -118,13 +118,26 @@ import com.sun.opengl.impl.*; public class Threading { private static boolean singleThreaded = true; + private static final int AWT = 1; + private static final int WORKER = 2; + private static int mode = AWT; static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { String workaround = System.getProperty("opengl.1thread"); - if (workaround != null && (!workaround.equals("auto"))) { - singleThreaded = Boolean.valueOf(workaround).booleanValue(); + if (workaround != null) { + workaround = workaround.toLowerCase(); + if (workaround.equals("true") || + workaround.equals("auto") || + workaround.equals("awt")) { + // Nothing to do; default = singleThreaded, mode = AWT + } else if (workaround.equals("worker")) { + singleThreaded = true; + mode = WORKER; + } else { + singleThreaded = false; + } } printWorkaroundNotice(); return null; @@ -170,16 +183,23 @@ public class Threading { throw new GLException("Should only call this in single-threaded mode"); } - 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 - // EDT, except when we're already on the QFT. - return (Java2D.isQueueFlusherThread() || - EventQueue.isDispatchThread()); - } else { - return EventQueue.isDispatchThread(); + switch (mode) { + case AWT: + 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 + // EDT, except when we're already on the QFT. + return (Java2D.isQueueFlusherThread() || + EventQueue.isDispatchThread()); + } else { + return EventQueue.isDispatchThread(); + } + case WORKER: + return GLWorkerThread.isWorkerThread(); + default: + throw new InternalError("Illegal single-threading mode " + mode); } } @@ -201,28 +221,48 @@ public class Threading { throw new GLException ("Should only call this from other threads than the OpenGL thread"); } - // FIXME: ideally should run all OpenGL work on the Java2D QFT - // thread when it's enabled, but there are issues with this when - // the GLJPanel is not using the Java2D bridge; would like to run - // its OpenGL work on the QFT, but do the image drawing from the - // EDT. Other issues still remain with the GLCanvas as well. - - // if (Java2D.isOGLPipelineActive()) { - // Java2D.invokeWithOGLContextCurrent(null, r); - // } else { - try { - EventQueue.invokeAndWait(r); - } catch (InvocationTargetException e) { - throw new GLException(e.getTargetException()); - } catch (InterruptedException e) { - throw new GLException(e); + switch (mode) { + case AWT: + // FIXME: ideally should run all OpenGL work on the Java2D QFT + // thread when it's enabled, but there are issues with this when + // the GLJPanel is not using the Java2D bridge; would like to run + // its OpenGL work on the QFT, but do the image drawing from the + // EDT. Other issues still remain with the GLCanvas as well. + + // if (Java2D.isOGLPipelineActive()) { + // Java2D.invokeWithOGLContextCurrent(null, r); + // } else { + try { + EventQueue.invokeAndWait(r); + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (InterruptedException e) { + throw new GLException(e); + } + // } + break; + + case WORKER: + if (!GLWorkerThread.isStarted()) { + synchronized (GLWorkerThread.class) { + if (!GLWorkerThread.isStarted()) { + GLWorkerThread.start(); + } + } + } + GLWorkerThread.invokeAndWait(r); + break; + + default: + throw new InternalError("Illegal single-threading mode " + mode); } - // } } private static void printWorkaroundNotice() { if (singleThreaded && Debug.verbose()) { - System.err.println("Using single thread for performing OpenGL work in javax.media.opengl implementation"); + System.err.println("Using " + + (mode == AWT ? "AWT" : "OpenGL worker") + + " thread for performing OpenGL work in javax.media.opengl implementation"); } } } |