diff options
Diffstat (limited to 'src/jogl/classes/jogamp')
6 files changed, 218 insertions, 83 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index bb2983399..42d0a2ec4 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -45,8 +45,10 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; +import javax.media.opengl.GLOffscreenAutoDrawable; import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; +import javax.media.opengl.GLSharedContextSetter; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.opengl.GLAutoDrawableDelegate; @@ -59,17 +61,18 @@ import com.jogamp.opengl.GLStateKeeper; * * @see GLAutoDrawable * @see GLAutoDrawableDelegate + * @see GLOffscreenAutoDrawable + * @see GLOffscreenAutoDrawableImpl * @see GLPBufferImpl - * @see GLWindow + * @see com.jogamp.newt.opengl.GLWindow */ -public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeeper, FPSCounter { +public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeeper, FPSCounter, GLSharedContextSetter { public static final boolean DEBUG = GLDrawableImpl.DEBUG; - protected final GLDrawableHelper helper = new GLDrawableHelper(); protected final FPSCounterImpl fpsCounter = new FPSCounterImpl(); protected volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access - protected GLContextImpl context; + protected volatile GLContextImpl context; protected boolean preserveGLELSAtDestroy; protected GLEventListenerState glels; protected GLStateKeeper.Listener glStateKeeperListener; @@ -79,12 +82,19 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking /** + * <p> + * The {@link GLContext} can be assigned later manually via {@link GLAutoDrawable#setContext(GLContext, boolean) setContext(ctx)} + * <i>or</i> it will be created <i>lazily</i> at the 1st {@link GLAutoDrawable#display() display()} method call.<br> + * <i>Lazy</i> {@link GLContext} creation will take a shared {@link GLContext} into account + * which has been set {@link #setSharedContext(GLContext) directly} + * or {@link #setSharedAutoDrawable(GLAutoDrawable) via another GLAutoDrawable}. + * </p> * @param drawable upstream {@link GLDrawableImpl} instance, * may be <code>null</code> for lazy initialization * @param context upstream {@link GLContextImpl} instance, * may not have been made current (created) yet, * may not be associated w/ <code>drawable<code> yet, - * may be <code>null</code> for lazy initialization + * may be <code>null</code> for lazy initialization at 1st {@link #display()}. * @param ownsDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued, * otherwise pass <code>false</code>. Closing the device is required in case * the drawable is created w/ it's own new instance, e.g. offscreen drawables, @@ -103,6 +113,16 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe resetFPSCounter(); } + @Override + public final void setSharedContext(GLContext sharedContext) throws IllegalStateException { + helper.setSharedContext(this.context, sharedContext); + } + + @Override + public final void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { + helper.setSharedAutoDrawable(this, sharedAutoDrawable); + } + /** Returns the recursive lock object of the upstream implementation, which synchronizes multithreaded access on top of {@link NativeSurface#lockSurface()}. */ protected abstract RecursiveLock getLock(); @@ -142,16 +162,16 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe } /** - * Pulls the {@link GLEventListenerState} from this {@link GLAutoDrawable}. + * Preserves the {@link GLEventListenerState} from this {@link GLAutoDrawable}. * - * @return <code>true</code> if the {@link GLEventListenerState} is pulled successfully from this {@link GLAutoDrawable}, + * @return <code>true</code> if the {@link GLEventListenerState} is preserved successfully from this {@link GLAutoDrawable}, * otherwise <code>false</code>. * - * @throws IllegalStateException if the {@link GLEventListenerState} is already pulled + * @throws IllegalStateException if the {@link GLEventListenerState} is already preserved * - * @see #pushGLEventListenerState() + * @see #restoreGLEventListenerState() */ - protected final boolean pullGLEventListenerState() throws IllegalStateException { + protected final boolean preserveGLEventListenerState() throws IllegalStateException { if( null != glels ) { throw new IllegalStateException("GLEventListenerState already pulled"); } @@ -166,15 +186,15 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe } /** - * Pushes a previously {@link #pullGLEventListenerState() pulled} {@link GLEventListenerState} to this {@link GLAutoDrawable}. + * Restores a previously {@link #preserveGLEventListenerState() preserved} {@link GLEventListenerState} to this {@link GLAutoDrawable}. * - * @return <code>true</code> if the {@link GLEventListenerState} was previously {@link #pullGLEventListenerState() pulled} - * and is pushed successfully to this {@link GLAutoDrawable}, + * @return <code>true</code> if the {@link GLEventListenerState} was previously {@link #preserveGLEventListenerState() preserved} + * and is moved successfully to this {@link GLAutoDrawable}, * otherwise <code>false</code>. * - * @see #pullGLEventListenerState() + * @see #preserveGLEventListenerState() */ - protected final boolean pushGLEventListenerState() { + protected final boolean restoreGLEventListenerState() { if( null != glels ) { glels.moveTo(this); glels = null; @@ -320,7 +340,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe protected void destroyImplInLock() { if( preserveGLELSAtDestroy ) { preserveGLStateAtDestroy(false); - pullGLEventListenerState(); + preserveGLEventListenerState(); } if( null != context ) { if( context.isCreated() ) { @@ -389,7 +409,25 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe final RecursiveLock _lock = getLock(); _lock.lock(); try { - if( null != context ) { + if( null == context ) { + boolean contextCreated = false; + final GLDrawableImpl _drawable = drawable; + if ( null != _drawable && _drawable.isRealized() && 0<_drawable.getWidth()*_drawable.getHeight() ) { + final GLContext[] shareWith = { null }; + if( !helper.isSharedGLContextPending(shareWith) ) { + if( !restoreGLEventListenerState() ) { + context = (GLContextImpl) _drawable.createContext(shareWith[0]); + context.setContextCreationFlags(additionalCtxCreationFlags); + contextCreated = true; + // surface is locked/unlocked implicit by context's makeCurrent/release + helper.invokeGL(_drawable, context, defaultDisplayAction, defaultInitAction); + } + } + } + if(DEBUG) { + System.err.println("GLAutoDrawableBase.defaultDisplay: contextCreated "+contextCreated); + } + } else { // surface is locked/unlocked implicit by context's makeCurrent/release helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction); } diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index dff55488d..377ebd9f5 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -429,7 +429,7 @@ public abstract class GLContextImpl extends GLContext { contextHandle = 0; glDebugHandler = null; // this maybe impl. in a platform specific way to release remaining shared ctx. - if(GLContextShareSet.contextDestroyed(this) && !GLContextShareSet.hasCreatedSharedLeft(this)) { + if( GLContextShareSet.contextDestroyed(this) && !GLContextShareSet.hasCreatedSharedLeft(this) ) { GLContextShareSet.unregisterSharing(this); } resetStates(false); @@ -647,7 +647,7 @@ public abstract class GLContextImpl extends GLContext { additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ; } - final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getShareContext(this); + final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getCreatedShare(this); if (null != shareWith) { shareWith.getDrawableImpl().lockSurface(); } diff --git a/src/jogl/classes/jogamp/opengl/GLContextShareSet.java b/src/jogl/classes/jogamp/opengl/GLContextShareSet.java index 70ade34b7..483767b44 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextShareSet.java +++ b/src/jogl/classes/jogamp/opengl/GLContextShareSet.java @@ -40,7 +40,8 @@ package jogamp.opengl; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -59,15 +60,15 @@ public class GLContextShareSet { // This class is implemented using a HashMap which maps from all shared contexts // to a share set, containing all shared contexts itself. - private static final Map<GLContext, ShareSet> shareMap = new HashMap<GLContext, ShareSet>(); + private static final Map<GLContext, ShareSet> shareMap = new IdentityHashMap<GLContext, ShareSet>(); private static final Object dummyValue = new Object(); private static class ShareSet { - private Map<GLContext, Object> allShares = new HashMap<GLContext, Object>(); - private Map<GLContext, Object> createdShares = new HashMap<GLContext, Object>(); - private Map<GLContext, Object> destroyedShares = new HashMap<GLContext, Object>(); + private final Map<GLContext, Object> allShares = new IdentityHashMap<GLContext, Object>(); + private final Map<GLContext, Object> createdShares = new IdentityHashMap<GLContext, Object>(); + private final Map<GLContext, Object> destroyedShares = new IdentityHashMap<GLContext, Object>(); - public void add(GLContext ctx) { + public void add(final GLContext ctx) { if (allShares.put(ctx, dummyValue) == null) { if (ctx.isCreated()) { createdShares.put(ctx, dummyValue); @@ -85,9 +86,9 @@ public class GLContextShareSet { return destroyedShares.keySet(); } - public GLContext getCreatedShare(GLContext ignore) { - for (Iterator<GLContext> iter = createdShares.keySet().iterator(); iter.hasNext(); ) { - GLContext ctx = iter.next(); + public GLContext getCreatedShare(final GLContext ignore) { + for (final Iterator<GLContext> iter = createdShares.keySet().iterator(); iter.hasNext(); ) { + final GLContext ctx = iter.next(); if (ctx != ignore) { return ctx; } @@ -95,21 +96,21 @@ public class GLContextShareSet { return null; } - public void contextCreated(GLContext ctx) { - Object res = destroyedShares.remove(ctx); + 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"; - res = createdShares.put(ctx, dummyValue); - assert res == null : "State of ShareSet corrupted; thought context " + + 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"; } - public void contextDestroyed(GLContext ctx) { - Object res = createdShares.remove(ctx); + 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"; - res = destroyedShares.put(ctx, dummyValue); - assert res == null : "State of ShareSet corrupted; thought context " + + 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"; } } @@ -117,7 +118,7 @@ public class GLContextShareSet { /** Indicate that contexts <code>share1</code> and <code>share2</code> will share textures and display lists. Both must be non-null. */ - public static synchronized void registerSharing(GLContext share1, GLContext share2) { + 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"); } @@ -138,7 +139,7 @@ public class GLContextShareSet { } } - public static synchronized void unregisterSharing(GLContext lastContext) { + public static synchronized void unregisterSharing(final GLContext lastContext) { if (lastContext == null) { throw new IllegalArgumentException("Last context is null"); } @@ -166,7 +167,25 @@ public class GLContextShareSet { } } - private static synchronized Set<GLContext> getCreatedSharedImpl(GLContext context) { + /** Returns true if the given GLContext is shared, otherwise false. */ + public static synchronized boolean isShared(final GLContext context) { + if (context == null) { + throw new IllegalArgumentException("context is null"); + } + final ShareSet share = entryFor(context); + return share != null; + } + + /** Returns one created GLContext shared with the given <code>context</code>, otherwise return <code>null</code>. */ + public static synchronized GLContext getCreatedShare(final GLContext context) { + final ShareSet share = entryFor(context); + if (share == null) { + return null; + } + return share.getCreatedShare(context); + } + + private static synchronized Set<GLContext> getCreatedSharesImpl(final GLContext context) { if (context == null) { throw new IllegalArgumentException("context is null"); } @@ -176,50 +195,56 @@ public class GLContextShareSet { } return null; } - - public static synchronized boolean isShared(GLContext context) { + private static synchronized Set<GLContext> getDestroyedSharesImpl(final GLContext context) { if (context == null) { throw new IllegalArgumentException("context is null"); } final ShareSet share = entryFor(context); - return share != null; + if (share != null) { + return share.getDestroyedShares(); + } + return null; } + /** Returns true if the given GLContext has shared and created GLContext left including itself, otherwise false. */ public static synchronized boolean hasCreatedSharedLeft(GLContext context) { - final Set<GLContext> s = getCreatedSharedImpl(context); - return null != s && s.size()>0 ; + final Set<GLContext> s = getCreatedSharesImpl(context); + return null != s && s.size() > 0; } - /** currently not used .. - public static synchronized Set<GLContext> getCreatedShared(GLContext context) { - final Set<GLContext> s = getCreatedSharedImpl(context); - if (s == null) { - throw new GLException("context is unknown: "+context); - } - return s; + /** Returns a new array-list of created GLContext shared with the given GLContext. */ + public static synchronized ArrayList<GLContext> getCreatedShares(final GLContext context) { + final ArrayList<GLContext> otherShares = new ArrayList<GLContext>(); + final Set<GLContext> createdShares = getCreatedSharesImpl(context); + if( null != createdShares ) { + for (final Iterator<GLContext> iter = createdShares.iterator(); iter.hasNext(); ) { + final GLContext ctx = iter.next(); + if (ctx != context) { + otherShares.add(ctx); + } + } + } + return otherShares; } - public static synchronized Set<GLContext> getDestroyedShared(GLContext context) { - if (context == null) { - throw new IllegalArgumentException("context is null"); - } - ShareSet share = entryFor(context); - if (share == null) { - throw new GLException("context is unknown: "+context); - } - return share.getDestroyedShares(); - } */ - - public static synchronized GLContext getShareContext(GLContext contextToCreate) { - ShareSet share = entryFor(contextToCreate); - if (share == null) { - return null; - } - return share.getCreatedShare(contextToCreate); + /** Returns a new array-list of destroyed GLContext shared with the given GLContext. */ + public static synchronized ArrayList<GLContext> getDestroyedShares(final GLContext context) { + final ArrayList<GLContext> otherShares = new ArrayList<GLContext>(); + final Set<GLContext> destroyedShares = getDestroyedSharesImpl(context); + if( null != destroyedShares ) { + for (final Iterator<GLContext> iter = destroyedShares.iterator(); iter.hasNext(); ) { + final GLContext ctx = iter.next(); + if (ctx != context) { + otherShares.add(ctx); + } + } + } + return otherShares; } - public static synchronized boolean contextCreated(GLContext context) { - ShareSet share = entryFor(context); + /** Mark the given GLContext as being created. */ + public static synchronized boolean contextCreated(final GLContext context) { + final ShareSet share = entryFor(context); if (share != null) { share.contextCreated(context); return true; @@ -227,8 +252,9 @@ public class GLContextShareSet { return false; } - public static synchronized boolean contextDestroyed(GLContext context) { - ShareSet share = entryFor(context); + /** Mark the given GLContext as being destroyed. */ + public static synchronized boolean contextDestroyed(final GLContext context) { + final ShareSet share = entryFor(context); if (share != null) { share.contextDestroyed(context); return true; @@ -245,9 +271,9 @@ public class GLContextShareSet { currently only needed in a fairly esoteric case, when the Java2D/JOGL bridge is active, but the GLBufferSizeTracker mechanism is now always required.) */ - public static void synchronizeBufferObjectSharing(GLContext olderContextOrNull, GLContext newContext) { - GLContextImpl older = (GLContextImpl) olderContextOrNull; - GLContextImpl newer = (GLContextImpl) newContext; + public static void synchronizeBufferObjectSharing(final GLContext olderContextOrNull, final GLContext newContext) { + final GLContextImpl older = (GLContextImpl) olderContextOrNull; + final GLContextImpl newer = (GLContextImpl) newContext; GLBufferSizeTracker tracker = null; if (older != null) { tracker = older.getBufferSizeTracker(); @@ -264,20 +290,20 @@ public class GLContextShareSet { // Internals only below this point - private static ShareSet entryFor(GLContext context) { - return (ShareSet) shareMap.get(context); + private static ShareSet entryFor(final GLContext context) { + return shareMap.get(context); } - private static void addEntry(GLContext context, ShareSet share) { + private static void addEntry(final GLContext context, final ShareSet share) { if (shareMap.get(context) == null) { shareMap.put(context, share); } } - private static ShareSet removeEntry(GLContext context) { - return (ShareSet) shareMap.remove(context); + private static ShareSet removeEntry(final GLContext context) { + return shareMap.remove(context); } - protected static String toHexString(long hex) { + private static String toHexString(long hex) { return "0x" + Long.toHexString(hex); } } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 1e4cb38fa..ecb9f7dd1 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -313,6 +313,19 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } @Override + public final GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice deviceReq, + GLCapabilitiesImmutable capsRequested, + GLCapabilitiesChooser chooser, + int width, int height) { + final GLDrawable drawable = createOffscreenDrawable( deviceReq, capsRequested, chooser, width, height ); + drawable.setRealized(true); + if(drawable instanceof GLFBODrawableImpl) { + return new GLOffscreenAutoDrawableImpl.FBOImpl( (GLFBODrawableImpl)drawable, null, null, null ); + } + return new GLOffscreenAutoDrawableImpl( drawable, null, null, null); + } + + @Override public final GLDrawable createOffscreenDrawable(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 4ce6a7121..cf5d7a206 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -82,6 +82,10 @@ public class GLDrawableHelper { private GLAnimatorControl animatorCtrl; private static Runnable nop = new Runnable() { @Override public void run() {} }; + private GLContext sharedContext; + private GLAutoDrawable sharedAutoDrawable; + + public GLDrawableHelper() { reset(); } @@ -98,6 +102,60 @@ public class GLDrawableHelper { glRunnables.clear(); } animatorCtrl = null; + sharedContext = null; + sharedAutoDrawable = null; + } + + public final void setSharedContext(GLContext thisContext, GLContext sharedContext) throws IllegalStateException { + if( null == sharedContext ) { + throw new IllegalStateException("Null shared GLContext"); + } + if( thisContext == sharedContext ) { + throw new IllegalStateException("Shared GLContext same as local"); + } + if( null != this.sharedContext ) { + throw new IllegalStateException("Shared GLContext already set"); + } + if( null != this.sharedAutoDrawable ) { + throw new IllegalStateException("Shared GLAutoDrawable already set"); + } + this.sharedContext = sharedContext; + } + + public final void setSharedAutoDrawable(GLAutoDrawable thisAutoDrawable, GLAutoDrawable sharedAutoDrawable) throws IllegalStateException { + if( null == sharedAutoDrawable ) { + throw new IllegalStateException("Null shared GLAutoDrawable"); + } + if( thisAutoDrawable == sharedAutoDrawable ) { + throw new IllegalStateException("Shared GLAutoDrawable same as this"); + } + if( null != this.sharedContext ) { + throw new IllegalStateException("Shared GLContext already set"); + } + if( null != this.sharedAutoDrawable ) { + throw new IllegalStateException("Shared GLAutoDrawable already set"); + } + this.sharedAutoDrawable = sharedAutoDrawable; + } + + /** + * @param shared returns the shared GLContext, based on set shared GLAutoDrawable + * or GLContext. Maybe null if none is set. + * @return true if initialization is pending due to a set shared GLAutoDrawable or GLContext + * which is not ready yet. Otherwise false. + */ + public boolean isSharedGLContextPending(GLContext[] shared) { + final GLContext shareWith; + final boolean pending; + if ( null != sharedAutoDrawable ) { + shareWith = sharedAutoDrawable.getContext(); + pending = null == shareWith || !shareWith.isCreated(); + } else { + shareWith = sharedContext; + pending = null != shareWith && !shareWith.isCreated(); + } + shared[0] = shareWith; + return pending; } @Override @@ -612,7 +670,7 @@ public class GLDrawableHelper { public final void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { synchronized(listenersLock) { for (int i=0; i < listeners.size(); i++) { - reshape((GLEventListener) listeners.get(i), drawable, x, y, width, height, 0==i /* setViewport */, true /* checkInit */); + reshape(listeners.get(i), drawable, x, y, width, height, 0==i /* setViewport */, true /* checkInit */); } } } diff --git a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java index f175acf28..345f08e4c 100644 --- a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java @@ -48,7 +48,7 @@ public class GLOffscreenAutoDrawableImpl extends GLAutoDrawableDelegate implemen * @param context a valid {@link GLContext}, * may not have been made current (created) yet, * may not be associated w/ <code>drawable<code> yet, - * may be <code>null</code> for lazy initialization + * may be <code>null</code> for lazy initialization at 1st {@link #display()}. * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}. * @param lock optional upstream lock, may be null */ |