From 5fbc462246a5d40833697902e84f2b2076e735a2 Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Thu, 23 Feb 2006 08:02:08 +0000 Subject: Added mechanism for kicking the current context off the GLWorkerThread. Tested with modified version of demos.texture.TestTexture doing the loading in another thread with manual makeCurrent()/release() calls (not recommended style). git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@634 232f8b59-042b-4e1e-8c03-345bb8c30851 --- src/classes/com/sun/opengl/impl/GLContextImpl.java | 10 +++ src/classes/com/sun/opengl/impl/GLContextLock.java | 8 +++ .../com/sun/opengl/impl/GLWorkerThread.java | 79 ++++++++++++++++++---- 3 files changed, 84 insertions(+), 13 deletions(-) (limited to 'src/classes') diff --git a/src/classes/com/sun/opengl/impl/GLContextImpl.java b/src/classes/com/sun/opengl/impl/GLContextImpl.java index a4eee6652..4a6885f45 100644 --- a/src/classes/com/sun/opengl/impl/GLContextImpl.java +++ b/src/classes/com/sun/opengl/impl/GLContextImpl.java @@ -96,6 +96,12 @@ public abstract class GLContextImpl extends GLContext { } } + if (GLWorkerThread.isStarted() && + !GLWorkerThread.isWorkerThread()) { + // Kick the GLWorkerThread off its current context + GLWorkerThread.invokeLater(new Runnable() { public void run() {} }); + } + lock.lock(); int res = 0; try { @@ -345,4 +351,8 @@ public abstract class GLContextImpl extends GLContext { public GLObjectTracker getObjectTracker() { return tracker; } + + public boolean hasWaiters() { + return lock.hasWaiters(); + } } diff --git a/src/classes/com/sun/opengl/impl/GLContextLock.java b/src/classes/com/sun/opengl/impl/GLContextLock.java index 9fb4d66e5..753ef14f8 100644 --- a/src/classes/com/sun/opengl/impl/GLContextLock.java +++ b/src/classes/com/sun/opengl/impl/GLContextLock.java @@ -52,6 +52,7 @@ public class GLContextLock { private Object lock = new Object(); private Thread owner; private boolean failFastMode = true; + private volatile int waiters; /** Locks this GLContextLock on the current thread. If fail fast mode is enabled and the GLContextLock is already owned by @@ -68,9 +69,12 @@ public class GLContextLock { " which is already current on thread " + owner); } else { try { + ++waiters; lock.wait(); } catch (InterruptedException e) { throw new GLException(e); + } finally { + --waiters; } } } @@ -115,4 +119,8 @@ public class GLContextLock { public boolean getFailFastMode() { return failFastMode; } + + public boolean hasWaiters() { + return (waiters != 0); + } } diff --git a/src/classes/com/sun/opengl/impl/GLWorkerThread.java b/src/classes/com/sun/opengl/impl/GLWorkerThread.java index 4091d1a77..57938c8bc 100755 --- a/src/classes/com/sun/opengl/impl/GLWorkerThread.java +++ b/src/classes/com/sun/opengl/impl/GLWorkerThread.java @@ -41,6 +41,7 @@ package com.sun.opengl.impl; import java.lang.reflect.InvocationTargetException; import java.security.*; +import java.util.*; import javax.media.opengl.*; /** Singleton thread upon which all OpenGL work is performed by @@ -61,9 +62,10 @@ public class GLWorkerThread { private static volatile boolean shouldTerminate; private static volatile Throwable exception; - // The Runnable to execute on the worker thread -- no need for a - // queue since we don't have an invokeLater() primitive + // The Runnable to execute immediately on the worker thread private static volatile Runnable work; + // Queue of Runnables to be asynchronously invoked + private static List queue = new LinkedList(); /** Should only be called by Threading class if creation of the GLWorkerThread was requested via the opengl.1thread system @@ -162,14 +164,35 @@ public class GLWorkerThread { } work = runnable; - lock.notifyAll(); - lock.wait(); + lockTemp.notifyAll(); + lockTemp.wait(); if (exception != null) { throw new InvocationTargetException(exception); } } } + public static void invokeLater(Runnable runnable) { + if (!started) { + throw new RuntimeException("May not invokeLater on worker thread without starting it first"); + } + + Object lockTemp = lock; + if (lockTemp == null) { + return; // Terminating + } + + synchronized (lockTemp) { + if (thread == null) { + // Terminating + return; + } + + queue.add(runnable); + lockTemp.notifyAll(); + } + } + /** Indicates whether the OpenGL worker thread was started, i.e., whether it is currently in use. */ public static boolean isStarted() { @@ -191,11 +214,19 @@ public class GLWorkerThread { while (!shouldTerminate) { synchronized (lock) { - while ((work == null) && !shouldTerminate) { + while (!shouldTerminate && + (work == null) && + queue.isEmpty()) { try { - lock.wait(); + // Avoid race conditions with wanting to release contexts on this thread + lock.wait(1000); } catch (InterruptedException e) { } + + if (GLContext.getCurrent() != null) { + // Test later to see whether we need to release this context + break; + } } if (shouldTerminate) { @@ -205,13 +236,35 @@ public class GLWorkerThread { return; } - try { - work.run(); - } catch (Throwable t) { - exception = t; - } finally { - work = null; - lock.notifyAll(); + if (work != null) { + try { + work.run(); + } catch (Throwable t) { + exception = t; + } finally { + work = null; + lock.notifyAll(); + } + } + + while (!queue.isEmpty()) { + try { + Runnable curAsync = (Runnable) queue.remove(0); + curAsync.run(); + } catch (Throwable t) { + System.out.println("Exception occurred on JOGL OpenGL worker thread:"); + t.printStackTrace(); + } + } + + // See about releasing current context + GLContext curContext = GLContext.getCurrent(); + if (curContext != null && + (curContext instanceof GLContextImpl)) { + GLContextImpl impl = (GLContextImpl) curContext; + if (impl.hasWaiters()) { + impl.release(); + } } } } -- cgit v1.2.3