diff options
author | Sven Gothel <[email protected]> | 2014-08-30 00:21:00 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-08-30 00:21:00 +0200 |
commit | 11347ad39059836f3e2a4f1fc592dc1e3fab6a09 (patch) | |
tree | df73acd41f7d0d8ae932cbd594336c98d388a113 | |
parent | dfb9ed47ac6d8e85f6ae5fe166e7a6e28ca8ff83 (diff) |
Bug 1054: GLContext: makeCurrent() needs a null-check of [mutable] drawable; Review null checks and synchronization/locking.
'drawable' field of GLContextImpl is mutable via setGLDrawable(..),
which requires high-level locking as documented.
The required high-level locking allows us to _not_ add special
synchronization to this field (and drawableRead).
A simple null-check in makeCurrent() shall be sufficient,
plus ensuring mentioned high-level locking is applied.
GLContextImpl 'drawable' and 'drawableRead' synchronization:
- commit ad79bd072b600a3f2416cc6f0c61e2925000069d check of null drawable is sufficient
- Add GLAutoDrawable upstream-lock locking to:
- AWT GLCanvas setupPrint/releasePrint
- AWT GLJPanel (was missing)
Misc:
- validate shared-context native-surface locking, throw exception if not successful
- pixelDataEvaluated does not need to be synchronized, since it's being called while context is current, locking
- GLDrawableHelper.recreateGLDrawable(..): Remove redundant glFinish() call
-rw-r--r-- | src/jogl/classes/javax/media/opengl/GLContext.java | 32 | ||||
-rw-r--r-- | src/jogl/classes/javax/media/opengl/awt/GLCanvas.java | 160 | ||||
-rw-r--r-- | src/jogl/classes/javax/media/opengl/awt/GLJPanel.java | 337 | ||||
-rw-r--r-- | src/jogl/classes/jogamp/opengl/GLContextImpl.java | 200 | ||||
-rw-r--r-- | src/jogl/classes/jogamp/opengl/GLDrawableHelper.java | 3 |
5 files changed, 406 insertions, 326 deletions
diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index e10579df1..9389ccabb 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -326,6 +326,9 @@ public abstract class GLContext { * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)}, * it equals to the write-drawable (default). * </p> + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> * @see #setGLDrawable(GLDrawable, boolean) * @see #setGLReadDrawable(GLDrawable) */ @@ -364,6 +367,9 @@ public abstract class GLContext { * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)}, * it equals to the write-drawable (default). * </p> + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> * @see #isGLReadDrawableAvailable() * @see #setGLReadDrawable(GLDrawable) * @see #getGLReadDrawable() @@ -1262,6 +1268,9 @@ public abstract class GLContext { /** * Return the framebuffer name bound to this context, * see {@link GL#glBindFramebuffer(int, int)}. + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> */ public abstract int getBoundFramebuffer(int target); @@ -1272,6 +1281,9 @@ public abstract class GLContext { * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable * is being used. * </p> + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> */ public abstract int getDefaultDrawFramebuffer(); @@ -1282,6 +1294,9 @@ public abstract class GLContext { * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable * is being used. * </p> + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> */ public abstract int getDefaultReadFramebuffer(); @@ -1306,13 +1321,26 @@ public abstract class GLContext { * Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead} * for read-pixels and swap-buffers implications. * </p> + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> */ public abstract int getDefaultReadBuffer(); - /** Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */ + /** + * Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> + */ public abstract int getDefaultPixelDataType(); - /** Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. */ + /** + * Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}. + * <p> + * Method is only thread-safe while context is {@link #makeCurrent() made current}. + * </p> + */ public abstract int getDefaultPixelDataFormat(); /** diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index b8e518ea5..563158a72 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -842,68 +842,74 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable setupPrintOnEDT = new Runnable() { @Override public void run() { - if( !validateGLDrawable() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet"); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( !validateGLDrawable() ) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet"); + } + printActive = false; + return; // not yet available .. } - printActive = false; - return; // not yet available .. - } - if( !isVisible() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible"); + if( !isVisible() ) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible"); + } + printActive = false; + return; // not yet available .. } - printActive = false; - return; // not yet available .. - } - sendReshape = false; // clear reshape flag - printAnimator = helper.getAnimator(); - if( null != printAnimator ) { - printAnimator.remove(GLCanvas.this); - } - printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD - final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); - final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); - GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); - final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); - final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || - printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); - final boolean reqNewGLADOnscrn = gladCaps.isOnscreen(); - - final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); - newGLADCaps.setDoubleBuffered(false); - newGLADCaps.setOnscreen(false); - if( printNumSamples != newGLADCaps.getNumSamples() ) { - newGLADCaps.setSampleBuffers(0 < printNumSamples); - newGLADCaps.setNumSamples(printNumSamples); - } - final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); + sendReshape = false; // clear reshape flag + printAnimator = helper.getAnimator(); + if( null != printAnimator ) { + printAnimator.remove(GLCanvas.this); + } + printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD + final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); + final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); + GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); + final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); + final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || + printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); + final boolean reqNewGLADOnscrn = gladCaps.isOnscreen(); + + final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); + newGLADCaps.setDoubleBuffered(false); + newGLADCaps.setOnscreen(false); + if( printNumSamples != newGLADCaps.getNumSamples() ) { + newGLADCaps.setSampleBuffers(0 < printNumSamples); + newGLADCaps.setNumSamples(printNumSamples); + } + final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); - final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; + final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; - if( DEBUG ) { - System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ - ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ - ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ - ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ - ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); - } - if( reqNewGLAD ) { - final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); - printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, - printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, - printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); - GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD); - printDrawable = printGLAD.getDelegatedDrawable(); - } - printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented()); - printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); - printAWTTiles.renderer.attachAutoDrawable(printGLAD); - if( DEBUG ) { - System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); - System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); - System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); + if( DEBUG ) { + System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ + ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ + ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ + ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ + ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); + } + if( reqNewGLAD ) { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); + printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, + printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, + printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); + GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD); + printDrawable = printGLAD.getDelegatedDrawable(); + } + printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented()); + printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); + printAWTTiles.renderer.attachAutoDrawable(printGLAD); + if( DEBUG ) { + System.err.println("AWT print.setup "+printAWTTiles); + System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); + System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); + System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); + } + } finally { + _lock.unlock(); } } }; @@ -919,23 +925,29 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final Runnable releasePrintOnEDT = new Runnable() { @Override public void run() { - if( DEBUG ) { - System.err.println("AWT print.release "+printAWTTiles); - } - printAWTTiles.dispose(); - printAWTTiles= null; - if( printGLAD != GLCanvas.this ) { - GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this); - printGLAD.destroy(); - } - printGLAD = null; - if( null != printAnimator ) { - printAnimator.add(GLCanvas.this); - printAnimator = null; + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( DEBUG ) { + System.err.println("AWT print.release "+printAWTTiles); + } + printAWTTiles.dispose(); + printAWTTiles= null; + if( printGLAD != GLCanvas.this ) { + GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this); + printGLAD.destroy(); + } + printGLAD = null; + if( null != printAnimator ) { + printAnimator.add(GLCanvas.this); + printAnimator = null; + } + sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! + printActive = false; + display(); + } finally { + _lock.unlock(); } - sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! - printActive = false; - display(); } }; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index a95681ee7..e2ccc1097 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -239,7 +239,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return singleAWTGLPixelBufferProvider; } - /** Currently not used internally, exist merely to satisfy {@link #getUpstreamLock()}. */ private final RecursiveLock lock = LockFactory.createRecursiveLock(); private final GLDrawableHelper helper; @@ -538,28 +537,34 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return; } - if( !isInitialized ) { - initializeBackendImpl(); - } - - if (!isInitialized || printActive) { - return; - } + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( !isInitialized ) { + initializeBackendImpl(); + } - // NOTE: must do this when the context is not current as it may - // involve destroying the pbuffer (current context) and - // re-creating it -- tricky to do properly while the context is - // current - if( !printActive ) { - if (handleReshape) { - handleReshape = false; - sendReshape = handleReshape(); + if (!isInitialized || printActive) { + return; } - if( isShowing ) { - updater.setGraphics(g); - backend.doPaintComponent(g); + // NOTE: must do this when the context is not current as it may + // involve destroying the pbuffer (current context) and + // re-creating it -- tricky to do properly while the context is + // current + if( !printActive ) { + if (handleReshape) { + handleReshape = false; + sendReshape = handleReshape(); + } + + if( isShowing ) { + updater.setGraphics(g); + backend.doPaintComponent(g); + } } + } finally { + _lock.unlock(); } } @@ -689,72 +694,78 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private final Runnable setupPrintOnEDT = new Runnable() { @Override public void run() { - if( !isInitialized ) { - initializeBackendImpl(); - } - if (!isInitialized) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet"); + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( !isInitialized ) { + initializeBackendImpl(); } - printActive = false; - return; // not yet available .. - } - if( !isVisible() ) { - if(DEBUG) { - System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible"); + if (!isInitialized) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet"); + } + printActive = false; + return; // not yet available .. + } + if( !isVisible() ) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible"); + } + printActive = false; + return; // not yet available .. + } + sendReshape = false; // clear reshape flag + handleReshape = false; // ditto + printAnimator = helper.getAnimator(); + if( null != printAnimator ) { + printAnimator.remove(GLJPanel.this); } - printActive = false; - return; // not yet available .. - } - sendReshape = false; // clear reshape flag - handleReshape = false; // ditto - printAnimator = helper.getAnimator(); - if( null != printAnimator ) { - printAnimator.remove(GLJPanel.this); - } - printGLAD = GLJPanel.this; // default: re-use - final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); - final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); - GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); - final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); - final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || - printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); - - final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); - newGLADCaps.setDoubleBuffered(false); - newGLADCaps.setOnscreen(false); - if( printNumSamples != newGLADCaps.getNumSamples() ) { - newGLADCaps.setSampleBuffers(0 < printNumSamples); - newGLADCaps.setNumSamples(printNumSamples); - } - final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); + printGLAD = GLJPanel.this; // default: re-use + final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities(); + final int printNumSamples = printAWTTiles.getNumSamples(gladCaps); + GLDrawable printDrawable = printGLAD.getDelegatedDrawable(); + final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples(); + final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() || + printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight(); + + final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable(); + newGLADCaps.setDoubleBuffered(false); + newGLADCaps.setOnscreen(false); + if( printNumSamples != newGLADCaps.getNumSamples() ) { + newGLADCaps.setSampleBuffers(0 < printNumSamples); + newGLADCaps.setNumSamples(printNumSamples); + } + final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps); - final boolean reqNewGLAD = ( reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; + final boolean reqNewGLAD = ( reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe; - if( DEBUG ) { - System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ - ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ - ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ - ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ - ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); - } - if( reqNewGLAD ) { - final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); - printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, - printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, - printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); - GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD); - printDrawable = printGLAD.getDelegatedDrawable(); - } - printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() ); - printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); - printAWTTiles.renderer.attachAutoDrawable(printGLAD); - if( DEBUG ) { - System.err.println("AWT print.setup "+printAWTTiles); - System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); - System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); - System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); + if( DEBUG ) { + System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+ + ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+ + ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+ + ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+ + ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator); + } + if( reqNewGLAD ) { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile()); + printGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null, + printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE, + printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE); + GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD); + printDrawable = printGLAD.getDelegatedDrawable(); + } + printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() ); + printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0); + printAWTTiles.renderer.attachAutoDrawable(printGLAD); + if( DEBUG ) { + System.err.println("AWT print.setup "+printAWTTiles); + System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps); + System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD); + System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable); + } + } finally { + _lock.unlock(); } } }; @@ -772,43 +783,49 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private final Runnable releasePrintOnEDT = new Runnable() { @Override public void run() { - if( DEBUG ) { - System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles); - } - printAWTTiles.dispose(); - printAWTTiles= null; - if( printGLAD != GLJPanel.this ) { - GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this); - printGLAD.destroy(); - } - printGLAD = null; - if( null != printAnimator ) { - printAnimator.add(GLJPanel.this); - printAnimator = null; - } + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if( DEBUG ) { + System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles); + } + printAWTTiles.dispose(); + printAWTTiles= null; + if( printGLAD != GLJPanel.this ) { + GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this); + printGLAD.destroy(); + } + printGLAD = null; + if( null != printAnimator ) { + printAnimator.add(GLJPanel.this); + printAnimator = null; + } - // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! - final int awtWidth = GLJPanel.this.getWidth(); - final int awtHeight= GLJPanel.this.getHeight(); - final int scaledAWTWidth = awtWidth * hasPixelScale[0]; - final int scaledAWTHeight= awtHeight * hasPixelScale[1]; - final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable(); - if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight || - drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) { - // -> !( awtSize == panelSize == drawableSize ) - if ( DEBUG ) { - System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resizeWithinPrint panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+ - ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+ - " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight); + // trigger reshape, i.e. gl-viewport and -listener - this component might got resized! + final int awtWidth = GLJPanel.this.getWidth(); + final int awtHeight= GLJPanel.this.getHeight(); + final int scaledAWTWidth = awtWidth * hasPixelScale[0]; + final int scaledAWTHeight= awtHeight * hasPixelScale[1]; + final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable(); + if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight || + drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) { + // -> !( awtSize == panelSize == drawableSize ) + if ( DEBUG ) { + System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resizeWithinPrint panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+ + ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+ + " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight); + } + reshapeWidth = scaledAWTWidth; + reshapeHeight = scaledAWTHeight; + sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape + } else { + sendReshape = true; // only GL reshape } - reshapeWidth = scaledAWTWidth; - reshapeHeight = scaledAWTHeight; - sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape - } else { - sendReshape = true; // only GL reshape + printActive = false; + display(); + } finally { + _lock.unlock(); } - printActive = false; - display(); } }; @@ -966,11 +983,17 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public GLContext createContext(final GLContext shareWith) { - final Backend b = backend; - if ( null == b ) { - return null; + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final Backend b = backend; + if ( null == b ) { + return null; + } + return b.createContext(shareWith); + } finally { + _lock.unlock(); } - return b.createContext(shareWith); } @Override @@ -984,14 +1007,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) { - final Backend b = backend; - if ( null == b ) { - return null; + final RecursiveLock _lock = lock; + _lock.lock(); + try { + final Backend b = backend; + if ( null == b ) { + return null; + } + final GLContext oldCtx = b.getContext(); + GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); + b.setContext(newCtx); + return oldCtx; + } finally { + _lock.unlock(); } - final GLContext oldCtx = b.getContext(); - GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags); - b.setContext(newCtx); - return oldCtx; } @@ -1342,36 +1371,42 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private final Runnable disposeAction = new Runnable() { @Override public void run() { - if ( null != backend ) { - final GLContext _context = backend.getContext(); - final boolean backendDestroy = !backend.isUsingOwnLifecycle(); - - GLException exceptionOnDisposeGL = null; - if( null != _context && _context.isCreated() ) { - try { - helper.disposeGL(GLJPanel.this, _context, !backendDestroy); - } catch (final GLException gle) { - exceptionOnDisposeGL = gle; + final RecursiveLock _lock = lock; + _lock.lock(); + try { + if ( null != backend ) { + final GLContext _context = backend.getContext(); + final boolean backendDestroy = !backend.isUsingOwnLifecycle(); + + GLException exceptionOnDisposeGL = null; + if( null != _context && _context.isCreated() ) { + try { + helper.disposeGL(GLJPanel.this, _context, !backendDestroy); + } catch (final GLException gle) { + exceptionOnDisposeGL = gle; + } } - } - Throwable exceptionBackendDestroy = null; - if ( backendDestroy ) { - try { - backend.destroy(); - } catch( final Throwable re ) { - exceptionBackendDestroy = re; + Throwable exceptionBackendDestroy = null; + if ( backendDestroy ) { + try { + backend.destroy(); + } catch( final Throwable re ) { + exceptionBackendDestroy = re; + } + backend = null; + isInitialized = false; } - backend = null; - isInitialized = false; - } - // throw exception in order of occurrence .. - if( null != exceptionOnDisposeGL ) { - throw exceptionOnDisposeGL; - } - if( null != exceptionBackendDestroy ) { - throw GLException.newGLException(exceptionBackendDestroy); + // throw exception in order of occurrence .. + if( null != exceptionOnDisposeGL ) { + throw exceptionOnDisposeGL; + } + if( null != exceptionBackendDestroy ) { + throw GLException.newGLException(exceptionBackendDestroy); + } } + } finally { + _lock.unlock(); } } }; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index c5a125a1e..e278afc92 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -108,10 +108,17 @@ public abstract class GLContextImpl extends GLContext { private final int[] boundFBOTarget = new int[] { 0, 0 }; // { draw, read } private int defaultVAO = 0; + /** + * <ul> + * <li>[GLAutoDrawable.upstreamLock].lock()</li> + * <li>drawable.surface.lock()</li> + * <li>contextLock.lock()</li> + * </ul> + */ protected GLDrawableImpl drawable; protected GLDrawableImpl drawableRead; - private volatile boolean pixelDataEvaluated; + private boolean pixelDataEvaluated; private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType; protected GL gl; @@ -192,28 +199,28 @@ public abstract class GLContextImpl extends GLContext { @Override public final GLDrawable setGLReadDrawable(final GLDrawable read) { - // Validate constraints first! - if(!isGLReadDrawableAvailable()) { - throw new GLException("Setting read drawable feature not available"); - } - final Thread currentThread = Thread.currentThread(); - if( contextLock.isLockedByOtherThread() ) { - throw new GLException("GLContext current by other thread "+contextLock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); - } - final boolean lockHeld = contextLock.isOwner(currentThread); - if( lockHeld && contextLock.getHoldCount() > 1 ) { - // would need to makeCurrent * holdCount - throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); - } - if(lockHeld) { - release(false); - } - final GLDrawable old = drawableRead; - drawableRead = ( null != read ) ? (GLDrawableImpl) read : drawable; - if(lockHeld) { - makeCurrent(); - } - return old; + // Validate constraints first! + if(!isGLReadDrawableAvailable()) { + throw new GLException("Setting read drawable feature not available"); + } + final Thread currentThread = Thread.currentThread(); + if( contextLock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+contextLock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } + final boolean lockHeld = contextLock.isOwner(currentThread); + if( lockHeld && contextLock.getHoldCount() > 1 ) { + // would need to makeCurrent * holdCount + throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); + } + if(lockHeld) { + release(false); + } + final GLDrawable old = drawableRead; + drawableRead = ( null != read ) ? (GLDrawableImpl) read : drawable; + if(lockHeld) { + makeCurrent(); + } + return old; } @Override @@ -223,46 +230,46 @@ public abstract class GLContextImpl extends GLContext { @Override public final GLDrawable setGLDrawable(final GLDrawable readWrite, final boolean setWriteOnly) { - // Validate constraints first! - final Thread currentThread = Thread.currentThread(); - if( contextLock.isLockedByOtherThread() ) { - throw new GLException("GLContext current by other thread "+contextLock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); - } - final boolean lockHeld = contextLock.isOwner(currentThread); - if( lockHeld && contextLock.getHoldCount() > 1 ) { - // would need to makeCurrent * holdCount - throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); - } - if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) { - return drawable; // no change. - } - final GLDrawableImpl old = drawable; - if( isCreated() && null != old && old.isRealized() ) { - if(!lockHeld) { - makeCurrent(); - } - // sync GL ctx w/ drawable's framebuffer before de-association - gl.glFinish(); - associateDrawable(false); - if(!lockHeld) { - release(false); - } - } - if(lockHeld) { - release(false); - } - if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable - drawableRead = (GLDrawableImpl) readWrite; - } - drawableRetargeted |= null != drawable && readWrite != drawable; - drawable = (GLDrawableImpl) readWrite ; - if( isCreated() && null != drawable && drawable.isRealized() ) { - makeCurrent(true); // implicit: associateDrawable(true) - if( !lockHeld ) { - release(false); - } - } - return old; + // Validate constraints first! + final Thread currentThread = Thread.currentThread(); + if( contextLock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+contextLock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } + final boolean lockHeld = contextLock.isOwner(currentThread); + if( lockHeld && contextLock.getHoldCount() > 1 ) { + // would need to makeCurrent * holdCount + throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); + } + if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) { + return drawable; // no change. + } + final GLDrawableImpl old = drawable; + if( isCreated() && null != old && old.isRealized() ) { + if(!lockHeld) { + makeCurrent(); + } + // sync GL ctx w/ drawable's framebuffer before de-association + gl.glFinish(); + associateDrawable(false); + if(!lockHeld) { + release(false); + } + } + if(lockHeld) { + release(false); + } + if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable + drawableRead = (GLDrawableImpl) readWrite; + } + drawableRetargeted |= null != drawable && readWrite != drawable; + drawable = (GLDrawableImpl) readWrite ; + if( isCreated() && null != drawable && drawable.isRealized() ) { + makeCurrent(true); // implicit: associateDrawable(true) + if( !lockHeld ) { + release(false); + } + } + return old; } @Override @@ -365,8 +372,8 @@ public abstract class GLContextImpl extends GLContext { if( actualRelease ) { setCurrent(null); } - drawable.unlockSurface(); contextLock.unlock(); + drawable.unlockSurface(); if( DEBUG_TRACE_SWITCH ) { final String msg = getThreadName() +": GLContext.ContextSwitch[release.X]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+(actualRelease?"switch":"keep ")+" - "+contextLock; lastCtxReleaseStack = new Throwable(msg); @@ -544,6 +551,7 @@ public abstract class GLContextImpl extends GLContext { } return CONTEXT_NOT_CURRENT; } + // Note: the surface is locked within [makeCurrent .. swap .. release] final int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { @@ -670,7 +678,9 @@ public abstract class GLContextImpl extends GLContext { final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getCreatedShare(this); final long shareWithHandle; if (null != shareWith) { - shareWith.getDrawableImpl().lockSurface(); + 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); @@ -693,7 +703,7 @@ public abstract class GLContextImpl extends GLContext { } } finally { if (null != shareWith) { - shareWith.getDrawableImpl().unlockSurface(); + shareWith.drawable.unlockSurface(); } } if ( DEBUG_TRACE_SWITCH ) { @@ -789,8 +799,8 @@ public abstract class GLContextImpl extends GLContext { * * The implementation <b>must</b> leave the context current.<br> * - * @param share the shared context or null - * @return the valid and current context if successful, or null + * @param sharedWithHandle the shared context handle or 0 + * @return true if successful, or false * @throws GLException */ protected abstract boolean createImpl(long sharedWithHandle) throws GLException ; @@ -2151,35 +2161,31 @@ public abstract class GLContextImpl extends GLContext { } private final void evalPixelDataType() { - if(!pixelDataEvaluated) { - synchronized(this) { - if(!pixelDataEvaluated) { - boolean ok = false; - /* if(isGL2GL3() && 3 == components) { - pixelDataInternalFormat=GL.GL_RGB; - pixelDataFormat=GL.GL_RGB; - pixelDataType = GL.GL_UNSIGNED_BYTE; - ok = true; - } else */ if( isGLES2Compatible() || isExtensionAvailable(GLExtensions.OES_read_format) ) { - final int[] glImplColorReadVals = new int[] { 0, 0 }; - gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_FORMAT, glImplColorReadVals, 0); - gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_TYPE, glImplColorReadVals, 1); - // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB; - pixelDataFormat = glImplColorReadVals[0]; - pixelDataType = glImplColorReadVals[1]; - ok = 0 != pixelDataFormat && 0 != pixelDataType; - } - if( !ok ) { - // RGBA read is safe for all GL profiles - // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB; - pixelDataFormat=GL.GL_RGBA; - pixelDataType = GL.GL_UNSIGNED_BYTE; - } - // TODO: Consider: - // return gl.isGL2GL3()?GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:GL.GL_UNSIGNED_SHORT_5_5_5_1; - pixelDataEvaluated = true; - } - } + if(!pixelDataEvaluated) { // only valid while context is made current + boolean ok = false; + /* if(isGL2GL3() && 3 == components) { + pixelDataInternalFormat=GL.GL_RGB; + pixelDataFormat=GL.GL_RGB; + pixelDataType = GL.GL_UNSIGNED_BYTE; + ok = true; + } else */ if( isGLES2Compatible() || isExtensionAvailable(GLExtensions.OES_read_format) ) { + final int[] glImplColorReadVals = new int[] { 0, 0 }; + gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_FORMAT, glImplColorReadVals, 0); + gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_TYPE, glImplColorReadVals, 1); + // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB; + pixelDataFormat = glImplColorReadVals[0]; + pixelDataType = glImplColorReadVals[1]; + ok = 0 != pixelDataFormat && 0 != pixelDataType; + } + if( !ok ) { + // RGBA read is safe for all GL profiles + // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB; + pixelDataFormat=GL.GL_RGBA; + pixelDataType = GL.GL_UNSIGNED_BYTE; + } + // TODO: Consider: + // return gl.isGL2GL3()?GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:GL.GL_UNSIGNED_SHORT_5_5_5_1; + pixelDataEvaluated = true; } } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index f91e1bdba..25ff83fc0 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -282,7 +282,6 @@ public class GLDrawableHelper { if( currentContext != context ) { context.makeCurrent(); } - context.getGL().glFinish(); context.setGLDrawable(null, true); // dis-associate } @@ -300,7 +299,7 @@ public class GLDrawableHelper { } if(null != context) { - context.setGLDrawable(drawable, true); // re-association + context.setGLDrawable(drawable, true); // re-association, implicit glFinish() ctx/drawable sync } if( null != currentContext ) { |