diff options
-rw-r--r-- | src/classes/com/sun/opengl/impl/GLContextImpl.java | 45 | ||||
-rw-r--r-- | src/classes/com/sun/opengl/impl/GLContextShareSet.java | 34 | ||||
-rwxr-xr-x | src/classes/com/sun/opengl/impl/GLObjectTracker.java | 127 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLJPanel.java | 3 |
4 files changed, 175 insertions, 34 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLContextImpl.java b/src/classes/com/sun/opengl/impl/GLContextImpl.java index 4a6885f45..8e38ec276 100644 --- a/src/classes/com/sun/opengl/impl/GLContextImpl.java +++ b/src/classes/com/sun/opengl/impl/GLContextImpl.java @@ -61,6 +61,9 @@ public abstract class GLContextImpl extends GLContext { // Tracks creation and deletion of server-side OpenGL objects when // the Java2D/OpenGL pipeline is active and using FBOs to render private GLObjectTracker tracker; + // Supports deletion of these objects when no other context is + // current which can support immediate deletion of them + private GLObjectTracker deletedObjectTracker; protected GL gl; public GLContextImpl(GLContext shareWith) { @@ -77,7 +80,11 @@ public abstract class GLContextImpl extends GLContext { if (shareContext != null) { GLContextShareSet.registerSharing(this, shareContext); } - GLContextShareSet.registerForObjectTracking(shareWith, this); + // Always indicate real behind-the-scenes sharing to track deleted objects + if (shareContext == null) { + shareContext = Java2D.filterShareContext(shareWith); + } + GLContextShareSet.registerForObjectTracking(shareWith, this, shareContext); } public int makeCurrent() throws GLException { @@ -119,6 +126,12 @@ public abstract class GLContextImpl extends GLContext { lock.unlock(); } else { setCurrent(this); + + // Try cleaning up any stale server-side OpenGL objects + // FIXME: not sure what to do here if this throws + if (deletedObjectTracker != null) { + deletedObjectTracker.clean(getGL()); + } } return res; } @@ -151,23 +164,11 @@ public abstract class GLContextImpl extends GLContext { // If we are tracking creation and destruction of server-side // OpenGL objects, we must decrement the reference count of the // GLObjectTracker upon context destruction. - try { - int res = makeCurrent(); - if (res != CONTEXT_CURRENT) { - // FIXME: we really need to behave better than this - throw new GLException("Unable to make context current to destroy tracked server-side OpenGL objects"); - } - try { - tracker.unref(getGL()); - } finally { - release(); - } - } catch (GLException e) { - // FIXME: should probably do something more intelligent here - if (DEBUG) { - e.printStackTrace(); - } - } + // + // Note that we can only eagerly delete these server-side + // objects if there is another context currrent right now + // which shares textures and display lists with this one. + tracker.unref(deletedObjectTracker); } } @@ -352,6 +353,14 @@ public abstract class GLContextImpl extends GLContext { return tracker; } + public void setDeletedObjectTracker(GLObjectTracker deletedObjectTracker) { + this.deletedObjectTracker = deletedObjectTracker; + } + + public GLObjectTracker getDeletedObjectTracker() { + return deletedObjectTracker; + } + public boolean hasWaiters() { return lock.hasWaiters(); } diff --git a/src/classes/com/sun/opengl/impl/GLContextShareSet.java b/src/classes/com/sun/opengl/impl/GLContextShareSet.java index 20a9364fb..293402899 100644 --- a/src/classes/com/sun/opengl/impl/GLContextShareSet.java +++ b/src/classes/com/sun/opengl/impl/GLContextShareSet.java @@ -52,6 +52,7 @@ import javax.media.opengl.*; public class GLContextShareSet { private static boolean forceTracking = Debug.isPropertyDefined("jogl.glcontext.forcetracking"); + private static final boolean DEBUG = Debug.debug("GLContextShareSet"); // This class is implemented with a WeakHashMap that goes from the // contexts as keys to a complex data structure as value that tracks @@ -157,7 +158,8 @@ public class GLContextShareSet { before any server-side OpenGL objects have been created in that context. */ public static synchronized void registerForObjectTracking(GLContext olderContextOrNull, - GLContext newContext) { + GLContext newContext, + GLContext realShareContext) { if (isObjectTrackingEnabled() || isObjectTrackingDebuggingEnabled()) { if (olderContextOrNull != null && newContext != null) { @@ -170,6 +172,36 @@ public class GLContextShareSet { GLContextImpl impl1 = (GLContextImpl) olderContextOrNull; GLContextImpl impl2 = (GLContextImpl) newContext; GLObjectTracker tracker = null; + + GLObjectTracker deletedObjectTracker = null; + GLContextImpl shareImpl = (GLContextImpl) realShareContext; + // Before we zap the "user-level" object trackers, make sure + // that all contexts in the share set share the destroyed object + // tracker + if (shareImpl != null) { + deletedObjectTracker = shareImpl.getDeletedObjectTracker(); + } + if (deletedObjectTracker == null) { + // Must create one and possibly set it up in the older context + deletedObjectTracker = new GLObjectTracker(); + if (DEBUG) { + System.err.println("Created deletedObjectTracker " + deletedObjectTracker + " because " + + ((shareImpl == null) ? "shareImpl was null" : "shareImpl's (" + shareImpl + ") deletedObjectTracker was null")); + } + + if (shareImpl != null) { + // FIXME: think should really assert in this case + shareImpl.setDeletedObjectTracker(deletedObjectTracker); + if (DEBUG) { + System.err.println("Set deletedObjectTracker " + deletedObjectTracker + " in shareImpl context " + shareImpl); + } + } + } + impl2.setDeletedObjectTracker(deletedObjectTracker); + if (DEBUG) { + System.err.println("Set deletedObjectTracker " + deletedObjectTracker + " in impl2 context " + impl2); + } + // Don't share object trackers with the primordial share context from Java2D if (Java2D.isOGLPipelineActive()) { // FIXME: probably need to do something different here diff --git a/src/classes/com/sun/opengl/impl/GLObjectTracker.java b/src/classes/com/sun/opengl/impl/GLObjectTracker.java index 663a7df70..dec7892de 100755 --- a/src/classes/com/sun/opengl/impl/GLObjectTracker.java +++ b/src/classes/com/sun/opengl/impl/GLObjectTracker.java @@ -402,22 +402,96 @@ public class GLObjectTracker { remove(getList(VERTEX_SHADERS_EXT), obj, 1); } + //---------------------------------------------------------------------- + // Reference count maintenance and manual deletion + // + + public synchronized void transferAll(GLObjectTracker other) { + for (int i = 0; i < lists.length; i++) { + getList(i).addAll(other.lists[i]); + if (other.lists[i] != null) { + other.lists[i].clear(); + } + } + dirty = true; + } + public synchronized void ref() { ++refCount; } - public synchronized void unref(GL gl) { - if (--refCount == 0) { - for (int i = 0; i < lists.length; i++) { - ObjectList list = lists[i]; - if (list != null) { - list.delete(gl); - lists[i] = null; + public void unref(GLObjectTracker deletedObjectPool) { + boolean tryDelete = false; + synchronized (this) { + if (--refCount == 0) { + tryDelete = true; + } + } + if (tryDelete) { + // See whether we should try to do the work now or whether we + // have to postpone + GLContext cur = GLContext.getCurrent(); + if ((cur != null) && + (cur instanceof GLContextImpl)) { + GLContextImpl curImpl = (GLContextImpl) cur; + if (deletedObjectPool != null && + deletedObjectPool == curImpl.getDeletedObjectTracker()) { + // Should be safe to delete these objects now + try { + delete(curImpl.getGL()); + return; + } catch (GLException e) { + // Shouldn't happen, but if it does, transfer all objects + // to the deleted object pool hoping we can later clean + // them up + deletedObjectPool.transferAll(this); + throw(e); + } + } + } + // If we get here, we couldn't attempt to delete the objects + // right now; instead try to transfer them to the + // deletedObjectPool for later cleanup (FIXME: should consider + // throwing an exception if deletedObjectPool is null, since + // that shouldn't happen) + if (DEBUG) { + String s = null; + if (cur == null) { + s = "current context was null"; + } else if (!(cur instanceof GLContextImpl)) { + s = "current context was not a GLContextImpl"; + } else if (deletedObjectPool == null) { + s = "no current deletedObjectPool"; + } else if (deletedObjectPool != ((GLContextImpl) cur).getDeletedObjectTracker()) { + s = "deletedObjectTracker didn't match"; + if (((GLContextImpl) cur).getDeletedObjectTracker() == null) { + s += " (other was null)"; + } + } else { + s = "unknown reason"; } + System.err.println("Deferred destruction of server-side OpenGL objects into " + deletedObjectPool + ": " + s); + } + + if (deletedObjectPool != null) { + deletedObjectPool.transferAll(this); + } + } + } + + public void clean(GL gl) { + if (dirty) { + try { + delete(gl); + dirty = false; + } catch (GLException e) { + // FIXME: not sure what to do here; probably a bad idea to be + // throwing exceptions during an otherwise-successful makeCurrent } } } + //---------------------------------------------------------------------- // Internals only below this point // @@ -459,8 +533,7 @@ public class GLObjectTracker { public ObjectList(Deleter deleter) { this.deleter = deleter; - capacity = MIN_CAPACITY; - data = new int[capacity]; + clear(); } public void add(int obj) { @@ -475,6 +548,15 @@ public class GLObjectTracker { data[size++] = obj; } + public void addAll(ObjectList other) { + if (other == null) { + return; + } + for (int i = 0; i < other.size; i++) { + add(other.data[i]); + } + } + public boolean remove(int value) { for (int i = 0; i < size; i++) { if (data[i] == value) { @@ -506,19 +588,30 @@ public class GLObjectTracker { } public void delete(GL gl) { - for (int i = 0; i < size; i++) { + // Just in case we start throwing exceptions during deletion, + // make sure we make progress rather than going into an infinite + // loop + while (size > 0) { + int obj = data[size - 1]; + --size; if (DEBUG) { - System.err.println("Deleting server-side OpenGL object " + data[i] + + System.err.println("Deleting server-side OpenGL object " + obj + ((name != null) ? (" (" + name + ")") : "")); } - deleter.delete(gl, data[i]); + deleter.delete(gl, obj); } + } + + public void clear() { size = 0; + capacity = MIN_CAPACITY; + data = new int[capacity]; } } private ObjectList[] lists = new ObjectList[NUM_OBJECT_TYPES]; private int refCount; + private boolean dirty; private void add(ObjectList list, int n, IntBuffer ids) { int pos = ids.position(); @@ -727,4 +820,14 @@ public class GLObjectTracker { } return list; } + + private void delete(GL gl) { + for (int i = 0; i < lists.length; i++) { + ObjectList list = lists[i]; + if (list != null) { + list.delete(gl); + lists[i] = null; + } + } + } } diff --git a/src/classes/javax/media/opengl/GLJPanel.java b/src/classes/javax/media/opengl/GLJPanel.java index 8d9b3c851..445ea3c4d 100644 --- a/src/classes/javax/media/opengl/GLJPanel.java +++ b/src/classes/javax/media/opengl/GLJPanel.java @@ -506,13 +506,10 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { if (curSurface != null) { if (j2dSurface != curSurface) { if (joglContext != null) { - // Note that the following operation may make the - // joglContext current briefly joglContext.destroy(); joglContext = null; joglDrawable = null; sendReshape = true; - j2dContext.makeCurrent(); if (DEBUG) { System.err.println("Sending reshape because surface changed"); System.err.println("New surface = " + curSurface); |