From 011e13e22fd52d2e82697ffee6b4c9ca8f3d549a Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 30 Aug 2014 11:59:13 +0200 Subject: Bug 1055 - Access and query shared master GLContext in a deterministic fashion ; Don't use arbitrary shared context as 'master'. GLContext* passes the shared-master to GLContextShareSet, which only creates a sets of shared contexts without differentiating the master context. GLContext*'s shared-slave attempts to lock the realized shared-master's surface at creation. Currently only an arbitrary shared context is selected due to the missing 'master' identity. The arbitrary shared context's surface is locked and its shared context handle used to create the slave context. Lacking of using the user given shared-master can lead to deadlock situations - and locking a 'wrong' surface. +++ The patch: - Allows query the user given shared-master! - Use the user given shared-master for locking and it's context handle for the slave's creation. - The shared-context mapping maps each shared-master to a shared-slave within one shared-context-set, allowing deterministic and individual shared-master queries. --- src/jogl/classes/javax/media/opengl/GLContext.java | 10 ++ src/jogl/classes/jogamp/opengl/GLContextImpl.java | 39 ++++--- .../classes/jogamp/opengl/GLContextShareSet.java | 129 ++++++++++++--------- 3 files changed, 105 insertions(+), 73 deletions(-) (limited to 'src/jogl/classes') diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 9389ccabb..f4ba3c0b7 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -250,6 +250,16 @@ public abstract class GLContext { return GLContextShareSet.isShared(this); } + /** + * Returns the shared master GLContext of this GLContext if shared, otherwise return null. + *

+ * Returns this GLContext, if it is a shared master. + *

+ */ + public final GLContext getSharedMaster() { + return GLContextShareSet.getSharedMaster(this); + } + /** Returns a new list of created GLContext shared with this GLContext. */ public final List getCreatedShares() { return GLContextShareSet.getCreatedShares(this); diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index e278afc92..9280d9830 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -151,7 +151,9 @@ public abstract class GLContextImpl extends GLContext { if ( null != shareWith ) { GLContextShareSet.registerSharing(this, shareWith); bufferObjectTracker = ((GLContextImpl)shareWith).getBufferObjectTracker(); - assert (bufferObjectTracker != null) : "shared context hash null GLBufferObjectTracker: "+shareWith; + if( null == bufferObjectTracker ) { + throw new InternalError("shared-master context hash null GLBufferObjectTracker: "+toHexString(shareWith.hashCode())); + } } else { bufferObjectTracker = new GLBufferObjectTracker(); } @@ -661,6 +663,10 @@ public abstract class GLContextImpl extends GLContext { return res; } + private final GLContextImpl getOtherSharedMaster() { + final GLContextImpl sharedMaster = (GLContextImpl) GLContextShareSet.getSharedMaster(this); + return this != sharedMaster ? sharedMaster : null; + } private final int makeCurrentWithinLock(final int surfaceLockRes) throws GLException { if (!isCreated()) { if( 0 >= drawable.getSurfaceWidth() || 0 >= drawable.getSurfaceHeight() ) { @@ -675,22 +681,23 @@ public abstract class GLContextImpl extends GLContext { additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ; } - final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getCreatedShare(this); - final long shareWithHandle; - if (null != shareWith) { - if ( NativeSurface.LOCK_SURFACE_NOT_READY >= shareWith.drawable.lockSurface() ) { - throw new GLException("GLContextShareSet could not lock surface: "+shareWith.drawable); - } - shareWithHandle = shareWith.getHandle(); - if (0 == shareWithHandle) { - throw new GLException("GLContextShareSet returned an invalid OpenGL context: "+this); + final boolean created; + final GLContextImpl sharedMaster = getOtherSharedMaster(); + if ( null != sharedMaster ) { + if ( NativeSurface.LOCK_SURFACE_NOT_READY >= sharedMaster.drawable.lockSurface() ) { + throw new GLException("GLContextShareSet could not lock sharedMaster surface: "+sharedMaster.drawable); } - } else { - shareWithHandle = 0; } - final boolean created; try { - created = createImpl(shareWithHandle); // may throws exception if fails + if ( null != sharedMaster ) { + final long sharedMasterHandle = sharedMaster.getHandle(); + if ( 0 == sharedMasterHandle ) { + throw new GLException("GLContextShareSet returned an invalid sharedMaster context: "+sharedMaster); + } + created = createImpl(sharedMasterHandle); // may throws exception if fails + } else { + created = createImpl(0); // may throws exception if fails + } if( created && hasNoDefaultVAO() ) { final int[] tmp = new int[1]; final GL rootGL = gl.getRootGL(); @@ -702,8 +709,8 @@ public abstract class GLContextImpl extends GLContext { } } } finally { - if (null != shareWith) { - shareWith.drawable.unlockSurface(); + if ( null != sharedMaster ) { + sharedMaster.drawable.unlockSurface(); } } if ( DEBUG_TRACE_SWITCH ) { diff --git a/src/jogl/classes/jogamp/opengl/GLContextShareSet.java b/src/jogl/classes/jogamp/opengl/GLContextShareSet.java index 209707f33..aed611edd 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextShareSet.java +++ b/src/jogl/classes/jogamp/opengl/GLContextShareSet.java @@ -61,21 +61,33 @@ public class GLContextShareSet { // to a share set, containing all shared contexts itself. private static final Map shareMap = new IdentityHashMap(); - private static final Object dummyValue = new Object(); private static class ShareSet { - private final Map allShares = new IdentityHashMap(); - private final Map createdShares = new IdentityHashMap(); - private final Map destroyedShares = new IdentityHashMap(); + private final Map createdShares = new IdentityHashMap(); + private final Map destroyedShares = new IdentityHashMap(); - public void add(final GLContext ctx) { - if (allShares.put(ctx, dummyValue) == null) { - if (ctx.isCreated()) { - createdShares.put(ctx, dummyValue); + public final void addNew(final GLContext slave, final GLContext master) { + final GLContext preMaster; + if ( slave.isCreated() ) { + preMaster = createdShares.put(slave, master); } else { - destroyedShares.put(ctx, dummyValue); + preMaster= destroyedShares.put(slave, master); + } + if( null != preMaster ) { + throw new InternalError("State of ShareSet corrupted: Slave "+toHexString(slave.hashCode())+ + " is not new w/ master "+toHexString(preMaster.hashCode())); + } + } + public final void addIfNew(final GLContext slave, final GLContext master) { + final GLContext preMaster = getMaster(master); + if( null == preMaster ) { + addNew(slave, master); } - } + } + + public final GLContext getMaster(final GLContext ctx) { + final GLContext c = createdShares.get(ctx); + return null != c ? c : destroyedShares.get(ctx); } public Set getCreatedShares() { @@ -86,57 +98,55 @@ public class GLContextShareSet { return destroyedShares.keySet(); } - public GLContext getCreatedShare(final GLContext ignore) { - for (final Iterator iter = createdShares.keySet().iterator(); iter.hasNext(); ) { - final GLContext ctx = iter.next(); - if (ctx != ignore) { - return ctx; - } - } - return null; - } - public void contextCreated(final GLContext ctx) { - final Object res = destroyedShares.remove(ctx); - assert res != null : "State of ShareSet corrupted; thought context " + - ctx + " should have been in destroyed set but wasn't"; - final Object res2 = createdShares.put(ctx, dummyValue); - assert res2 == null : "State of ShareSet corrupted; thought context " + - ctx + " shouldn't have been in created set but was"; + final GLContext ctxMaster = destroyedShares.remove(ctx); + if( null == ctxMaster ) { + throw new InternalError("State of ShareSet corrupted: Context "+toHexString(ctx.hashCode())+ + " should have been in destroyed-set"); + } + final GLContext delMaster = createdShares.put(ctx, ctxMaster); + if( null != delMaster ) { + throw new InternalError("State of ShareSet corrupted: Context "+toHexString(ctx.hashCode())+ + " shouldn't have been in created-set"); + } } public void contextDestroyed(final GLContext ctx) { - final Object res = createdShares.remove(ctx); - assert res != null : "State of ShareSet corrupted; thought context " + - ctx + " should have been in created set but wasn't"; - final Object res2 = destroyedShares.put(ctx, dummyValue); - assert res2 == null : "State of ShareSet corrupted; thought context " + - ctx + " shouldn't have been in destroyed set but was"; + final GLContext ctxMaster = createdShares.remove(ctx); + if( null == ctxMaster ) { + throw new InternalError("State of ShareSet corrupted: Context "+toHexString(ctx.hashCode())+ + " should have been in created-set"); + } + final GLContext delMaster = destroyedShares.put(ctx, ctxMaster); + if( null != delMaster ) { + throw new InternalError("State of ShareSet corrupted: Context "+toHexString(ctx.hashCode())+ + " shouldn't have been in destroyed-set"); + } } } - /** Indicate that contexts share1 and - share2 will share textures and display lists. Both + /** Indicate that contexts slave and + master will share textures and display lists. Both must be non-null. */ - public static synchronized void registerSharing(final GLContext share1, final GLContext share2) { - if (share1 == null || share2 == null) { - throw new IllegalArgumentException("Both share1 and share2 must be non-null"); - } - ShareSet share = entryFor(share1); - if (share == null) { - share = entryFor(share2); - } - if (share == null) { - share = new ShareSet(); - } - share.add(share1); - share.add(share2); - addEntry(share1, share); - addEntry(share2, share); - if (DEBUG) { - System.err.println("GLContextShareSet: registereSharing: 1: " + - toHexString(share1.getHandle()) + ", 2: " + toHexString(share2.getHandle())); - } + public static synchronized void registerSharing(final GLContext slave, final GLContext master) { + if (slave == null || master == null) { + throw new IllegalArgumentException("Both slave and master must be non-null"); + } + ShareSet share = entryFor(slave); + if ( null == share ) { + share = entryFor(master); + } + if ( null == share ) { + share = new ShareSet(); + } + share.addNew(slave, master); + share.addIfNew(master, master); // this master could have a different master shared registered earlier! + addEntry(slave, share); + addEntry(master, share); + if (DEBUG) { + System.err.println("GLContextShareSet: registereSharing: 1: " + + toHexString(slave.hashCode()) + ", 2: " + toHexString(master.hashCode())); + } } public static synchronized void unregisterSharing(final GLContext lastContext) { @@ -157,7 +167,7 @@ public class GLContextShareSet { } if (DEBUG) { System.err.println("GLContextShareSet: unregisterSharing: " + - toHexString(lastContext.getHandle())+", entries: "+s.size()); + toHexString(lastContext.hashCode())+", entries: "+s.size()); } for(final Iterator iter = s.iterator() ; iter.hasNext() ; ) { final GLContext ctx = iter.next(); @@ -176,13 +186,18 @@ public class GLContextShareSet { return share != null; } - /** Returns one created GLContext shared with the given context, otherwise return null. */ - public static synchronized GLContext getCreatedShare(final GLContext context) { + /** + * Returns the shared master GLContext of the given context if shared, otherwise return null. + *

+ * Returns the given context, if it is a shared master. + *

+ */ + public static synchronized GLContext getSharedMaster(final GLContext context) { final ShareSet share = entryFor(context); if (share == null) { return null; } - return share.getCreatedShare(context); + return share.getMaster(context); } private static synchronized Set getCreatedSharesImpl(final GLContext context) { -- cgit v1.2.3