diff options
Diffstat (limited to 'src/jogl/classes/jogamp')
31 files changed, 1519 insertions, 784 deletions
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java index fa81e2a3f..fbd40ebdd 100644 --- a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java +++ b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java @@ -427,7 +427,7 @@ public class VBORegion2PMSAAES2 extends GLRegion { gl.glActiveTexture(GL.GL_TEXTURE0 + gcu_FboTexUnit.intValue()); - fbo.use(gl, fbo.getSamplingSink()); + fbo.use(gl, fbo.getSamplingSink().getTextureAttachment()); gca_FboVerticesAttr.enableBuffer(gl, true); gca_FboTexCoordsAttr.enableBuffer(gl, true); indicesFbo.bindBuffer(gl, true); // keeps VBO binding @@ -454,19 +454,22 @@ public class VBORegion2PMSAAES2 extends GLRegion { fboWidth = targetFboWidth; fboHeight = targetFboHeight; fbo = new FBObject(); - fbo.reset(gl, fboWidth, fboHeight, sampleCount[0], false); + fbo.init(gl, fboWidth, fboHeight, sampleCount[0]); sampleCount[0] = fbo.getNumSamples(); fbo.attachColorbuffer(gl, 0, true); - fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + if( !blendingEnabled ) { + // no depth-buffer w/ blending + fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, FBObject.DEFAULT_BITS); + } final FBObject ssink = new FBObject(); { - ssink.reset(gl, fboWidth, fboHeight); + ssink.init(gl, fboWidth, fboHeight, 0); // FIXME: shall not use bilinear (GL_LINEAR), due to MSAA ??? // ssink.attachTexture2D(gl, 0, true, GL2ES2.GL_LINEAR, GL2ES2.GL_LINEAR, GL2ES2.GL_CLAMP_TO_EDGE, GL2ES2.GL_CLAMP_TO_EDGE); ssink.attachTexture2D(gl, 0, true, GL.GL_NEAREST, GL.GL_NEAREST, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE); if( !blendingEnabled ) { // no depth-buffer w/ blending - ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, FBObject.DEFAULT_BITS); } } fbo.setSamplingSink(ssink); @@ -475,7 +478,7 @@ public class VBORegion2PMSAAES2 extends GLRegion { System.err.printf("XXX.createFBO: blending %b, %dx%d%n%s%n", blendingEnabled, fboWidth, fboHeight, fbo.toString()); } } else if( targetFboWidth != fboWidth || targetFboHeight != fboHeight || fbo.getNumSamples() != sampleCount[0] ) { - fbo.reset(gl, targetFboWidth, targetFboHeight, sampleCount[0], true /* resetSamplingSink */); + fbo.reset(gl, targetFboWidth, targetFboHeight, sampleCount[0]); sampleCount[0] = fbo.getNumSamples(); if( DEBUG_FBO_1 ) { System.err.printf("XXX.resetFBO: %dx%d -> %dx%d%n%s%n", fboWidth, fboHeight, targetFboWidth, targetFboHeight, fbo ); diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PVBAAES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PVBAAES2.java index 24fa09058..8f1de9157 100644 --- a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PVBAAES2.java +++ b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PVBAAES2.java @@ -573,20 +573,20 @@ public class VBORegion2PVBAAES2 extends GLRegion { fboTexSize.put(1, fboHeight); } fbo = new FBObject(); - fbo.reset(gl, fboWidth, fboHeight); + fbo.init(gl, fboWidth, fboHeight, 0); // Shall not use bilinear (GL_LINEAR), due to own VBAA. Result is smooth w/o it now! // FIXME: FXAA requires bilinear filtering! // texA = fbo.attachTexture2D(gl, 0, true, GL.GL_LINEAR, GL.GL_LINEAR, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE); texA = fbo.attachTexture2D(gl, 0, true, GL.GL_NEAREST, GL.GL_NEAREST, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE); if( !blendingEnabled ) { // no depth-buffer w/ blending - fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, FBObject.DEFAULT_BITS); } if( DEBUG_FBO_1 ) { System.err.printf("XXX.createFBO: %dx%d%n%s%n", fboWidth, fboHeight, fbo.toString()); } } else if( newFboWidth != fboWidth || newFboHeight != fboHeight ) { - fbo.reset(gl, newFboWidth, newFboHeight); + fbo.reset(gl, newFboWidth, newFboHeight, 0); fbo.bind(gl); if( DEBUG_FBO_1 ) { System.err.printf("XXX.resetFBO: %dx%d -> %dx%d, target %dx%d%n", fboWidth, fboHeight, newFboWidth, newFboHeight, targetFboWidth, targetFboHeight); diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java index 5bd49dce9..97570d605 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java @@ -32,8 +32,8 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.font.Font; import com.jogamp.opengl.math.geom.AABBox; -public class TypecastGlyph implements Font.Glyph { - public static class Advance +public final class TypecastGlyph implements Font.Glyph { + public static final class Advance { private final Font font; private final float advance; @@ -46,40 +46,42 @@ public class TypecastGlyph implements Font.Glyph { size2advanceI.setKeyNotFoundValue(0); } - public void reset() { + public final void reset() { size2advanceI.clear(); } - public float getScale(final float pixelSize) + public final Font getFont() { return font; } + + public final float getScale(final float pixelSize) { return this.font.getMetrics().getScale(pixelSize); } - public void add(final float advance, final float size) + public final void add(final float advance, final float size) { size2advanceI.put(Float.floatToIntBits(size), Float.floatToIntBits(advance)); } - public float get(final float size, final boolean useFrationalMetrics) + public final float get(final float pixelSize, final boolean useFrationalMetrics) { - final int sI = Float.floatToIntBits(size); + final int sI = Float.floatToIntBits(pixelSize); final int aI = size2advanceI.get(sI); if( 0 != aI ) { return Float.intBitsToFloat(aI); } final float a; if ( useFrationalMetrics ) { - a = this.advance * getScale(size); + a = this.advance * getScale(pixelSize); } else { - // a = Math.ceil(this.advance * getScale(size)); - a = Math.round(this.advance * getScale(size)); // TODO: check whether ceil should be used instead? + // a = Math.ceil(this.advance * getScale(pixelSize)); + a = Math.round(this.advance * getScale(pixelSize)); // TODO: check whether ceil should be used instead? } size2advanceI.put(sI, Float.floatToIntBits(a)); return a; } @Override - public String toString() + public final String toString() { return "\nAdvance:"+ "\n advance: "+this.advance+ @@ -87,7 +89,7 @@ public class TypecastGlyph implements Font.Glyph { } } - public static class Metrics + public static final class Metrics { private final AABBox bbox; private final Advance advance; @@ -98,32 +100,34 @@ public class TypecastGlyph implements Font.Glyph { this.advance = new Advance(font, advance); } - public void reset() { + public final void reset() { advance.reset(); } - public float getScale(final float pixelSize) + public final Font getFont() { return advance.getFont(); } + + public final float getScale(final float pixelSize) { return this.advance.getScale(pixelSize); } - public AABBox getBBox() + public final AABBox getBBox() { return this.bbox; } - public void addAdvance(final float advance, final float size) + public final void addAdvance(final float advance, final float size) { this.advance.add(advance, size); } - public float getAdvance(final float size, final boolean useFrationalMetrics) + public final float getAdvance(final float pixelSize, final boolean useFrationalMetrics) { - return this.advance.get(size, useFrationalMetrics); + return this.advance.get(pixelSize, useFrationalMetrics); } @Override - public String toString() + public final String toString() { return "\nMetrics:"+ "\n bbox: "+this.bbox+ @@ -134,31 +138,21 @@ public class TypecastGlyph implements Font.Glyph { public static final short INVALID_ID = (short)((1 << 16) - 1); public static final short MAX_ID = (short)((1 << 16) - 2); - private final Font font; private final char symbol; private final OutlineShape shape; // in EM units private final short id; - private final int advance; private final Metrics metrics; protected TypecastGlyph(final Font font, final char symbol, final short id, final AABBox bbox, final int advance, final OutlineShape shape) { - this.font = font; this.symbol = symbol; this.shape = shape; this.id = id; - this.advance = advance; - this.metrics = new Metrics(this.font, bbox, this.advance); + this.metrics = new Metrics(font, bbox, advance); } - /** - public void reset(Path2D path) { - this.path = path; - this.metrics.reset(); - } */ - @Override public final Font getFont() { - return this.font; + return this.metrics.getFont(); } @Override @@ -211,7 +205,7 @@ public class TypecastGlyph implements Font.Glyph { @Override public final int hashCode() { // 31 * x == (x << 5) - x - final int hash = 31 + font.getName(Font.NAME_UNIQUNAME).hashCode(); + final int hash = 31 + getFont().getName(Font.NAME_UNIQUNAME).hashCode(); return ((hash << 5) - hash) + id; } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/OTGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/OTGlyph.java index 7bfffd58c..8ed450326 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/OTGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/OTGlyph.java @@ -65,10 +65,10 @@ import com.jogamp.opengl.math.geom.AABBox; * @version $Id: Glyph.java,v 1.3 2007-02-21 12:23:54 davidsch Exp $ * @author <a href="mailto:[email protected]">David Schweinsberg</a>, Sven Gothel */ -public class OTGlyph { +public final class OTGlyph { - protected short _leftSideBearing; - protected int _advanceWidth; + private final short _leftSideBearing; + private final int _advanceWidth; private Point[] _points; AABBox _bbox; @@ -102,33 +102,32 @@ public class OTGlyph { } } - public void clearPointData() { + public final void clearPointData() { _points = null; } - public AABBox getBBox() { + public final AABBox getBBox() { return _bbox; } - public int getAdvanceWidth() { + public final int getAdvanceWidth() { return _advanceWidth; } - public short getLeftSideBearing() { + public final short getLeftSideBearing() { return _leftSideBearing; } - public Point getPoint(final int i) { + public final Point getPoint(final int i) { return _points[i]; } - public int getPointCount() { + public final int getPointCount() { return null != _points ? _points.length : 0; } /** * @param factor a 16.16 fixed value - */ public void scale(final int factor) { for (int i = 0; i < _points.length; i++) { //points[i].x = ( points[i].x * factor ) >> 6; @@ -139,11 +138,12 @@ public class OTGlyph { _leftSideBearing = (short)(( _leftSideBearing * factor) >> 6); _advanceWidth = (_advanceWidth * factor) >> 6; } + */ /** * Set the points of a glyph from the GlyphDescription */ - private void describe(final GlyphDescription gd) { + private final void describe(final GlyphDescription gd) { int endPtIndex = 0; _points = new Point[gd.getPointCount() /* + 2 */ ]; for (int i = 0; i < gd.getPointCount(); i++) { diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index fce5c1fcc..6e6aaf58d 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -57,9 +57,11 @@ import com.jogamp.opengl.GLStateKeeper; /** - * Abstract common code for GLAutoDrawable implementations. + * Abstract common code for GLAutoDrawable implementations + * utilizing multithreading, i.e. {@link #isThreadGLCapable()} always returns <code>true</code>. * * @see GLAutoDrawable + * @see GLAutoDrawable#getThreadingMode() * @see GLAutoDrawableDelegate * @see GLOffscreenAutoDrawable * @see GLOffscreenAutoDrawableImpl @@ -123,9 +125,6 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe 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(); - @Override public final GLStateKeeper.Listener setGLStateKeeperListener(final Listener l) { final GLStateKeeper.Listener pre = glStateKeeperListener; @@ -240,7 +239,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe System.err.println("GLAutoDrawableBase.sizeChanged: ("+getThreadName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(surfaceHandle)); } if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getUpstreamLock(); _lock.lock(); try { final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, newWidth, newHeight); @@ -280,7 +279,13 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe shallClose = true; } if( shallClose ) { - destroyAvoidAwareOfLocking(); + try { + destroyAvoidAwareOfLocking(); + } catch( final Throwable t ) { + // Intentionally catch and ignore exception, + // so the destroy mechanism of the native windowing system is not corrupted! + GLException.dumpThrowable("ignored", t); + } } } @@ -332,7 +337,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe * Calls {@link #destroyImplInLock()} while claiming the lock. */ protected final void defaultDestroy() { - final RecursiveLock lock = getLock(); + final RecursiveLock lock = getUpstreamLock(); lock.lock(); try { destroyImplInLock(); @@ -357,30 +362,52 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe preserveGLStateAtDestroy(false); preserveGLEventListenerState(); } + + GLException exceptionOnDisposeGL = null; if( null != context ) { if( context.isCreated() ) { - // Catch dispose GLExceptions by GLEventListener, just 'print' them - // so we can continue with the destruction. try { helper.disposeGL(this, context, true); } catch (final GLException gle) { - gle.printStackTrace(); + exceptionOnDisposeGL = gle; } } context = null; } + + Throwable exceptionOnUnrealize = null; + Throwable exceptionOnDeviceClose = null; if( null != drawable ) { final AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); - drawable.setRealized(false); + try { + drawable.setRealized(false); + } catch( final Throwable re ) { + exceptionOnUnrealize = re; + } drawable = null; - if( ownsDevice ) { - device.close(); + try { + if( ownsDevice ) { + device.close(); + } + } catch (final Throwable re) { + exceptionOnDeviceClose = re; } } + + // throw exception in order of occurrence .. + if( null != exceptionOnDisposeGL ) { + throw exceptionOnDisposeGL; + } + if( null != exceptionOnUnrealize ) { + throw GLException.newGLException(exceptionOnUnrealize); + } + if( null != exceptionOnDeviceClose ) { + throw GLException.newGLException(exceptionOnDeviceClose); + } } public final void defaultSwapBuffers() throws GLException { - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getUpstreamLock(); _lock.lock(); try { if(null != drawable) { @@ -421,7 +448,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe destroy(); return; } - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getUpstreamLock(); _lock.lock(); try { if( null == context ) { @@ -452,7 +479,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe } protected final GLEventListener defaultDisposeGLEventListener(final GLEventListener listener, final boolean remove) { - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getUpstreamLock(); _lock.lock(); try { return helper.disposeGLEventListener(GLAutoDrawableBase.this, drawable, context, listener, remove); @@ -473,7 +500,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe @Override public final GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) { - final RecursiveLock lock = getLock(); + final RecursiveLock lock = getUpstreamLock(); lock.lock(); try { final GLContext oldCtx = context; @@ -571,16 +598,21 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe } @Override - public final boolean invoke(final boolean wait, final GLRunnable glRunnable) { + public final boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException { return helper.invoke(this, wait, glRunnable); } @Override - public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) { + public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException { return helper.invoke(this, wait, glRunnables); } @Override + public void flushGLRunnables() { + helper.flushGLRunnables(); + } + + @Override public final void setAutoSwapBufferMode(final boolean enable) { helper.setAutoSwapBufferMode(enable); } @@ -604,6 +636,15 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe return additionalCtxCreationFlags; } + /** + * {@inheritDoc} + * <p> + * Implementation always supports multithreading, hence method always returns <code>true</code>. + * </p> + */ + @Override + public final boolean isThreadGLCapable() { return true; } + // // FPSCounter // @@ -664,7 +705,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe @Override public final GLContext createContext(final GLContext shareWith) { - final RecursiveLock lock = getLock(); + final RecursiveLock lock = getUpstreamLock(); lock.lock(); try { if(drawable != null) { @@ -680,7 +721,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe @Override public final void setRealized(final boolean realized) { - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getUpstreamLock(); _lock.lock(); try { final GLDrawable _drawable = drawable; @@ -727,6 +768,12 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe } @Override + public final GLCapabilitiesImmutable getRequestedGLCapabilities() { + final GLDrawable _drawable = drawable; + return null != _drawable ? _drawable.getRequestedGLCapabilities() : null; + } + + @Override public final GLProfile getGLProfile() { final GLDrawable _drawable = drawable; return null != _drawable ? _drawable.getGLProfile() : null; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index c175243ae..01478a422 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; @@ -137,11 +144,16 @@ public abstract class GLContextImpl extends GLContext { public GLContextImpl(final GLDrawableImpl drawable, final GLContext shareWith) { super(); + if( null == drawable ) { + throw new IllegalArgumentException("Null drawable"); + } bufferStateTracker = new GLBufferStateTracker(); 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(); } @@ -189,21 +201,28 @@ public abstract class GLContextImpl extends GLContext { @Override public final GLDrawable setGLReadDrawable(final GLDrawable read) { - if(!isGLReadDrawableAvailable()) { - throw new GLException("Setting read drawable feature not available"); - } - final boolean lockHeld = lock.isOwner(Thread.currentThread()); - if(lockHeld) { - release(); - } else if(lock.isLockedByOtherThread()) { // still could glitch .. - throw new GLException("GLContext current by other thread ("+lock.getOwner()+"), operation not allowed."); - } - 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( lock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } + final boolean lockHeld = lock.isOwner(currentThread); + if( lockHeld && lock.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 @@ -213,43 +232,46 @@ public abstract class GLContextImpl extends GLContext { @Override public final GLDrawable setGLDrawable(final GLDrawable readWrite, final boolean setWriteOnly) { - if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) { - return drawable; // no change. - } - final Thread currentThread = Thread.currentThread(); - if( lock.isLockedByOtherThread() ) { - throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); - } - final boolean lockHeld = lock.isOwner(currentThread); - if( lockHeld && lock.getHoldCount() > 1 ) { - // would need to makeCurrent * holdCount - throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)"); - } - final GLDrawableImpl old = drawable; - if( isCreated() && null != old && old.isRealized() ) { - if(!lockHeld) { - makeCurrent(); - } - associateDrawable(false); - if(!lockHeld) { - release(); - } - } - if(lockHeld) { - release(); - } - 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(); - } - } - return old; + // Validate constraints first! + final Thread currentThread = Thread.currentThread(); + if( lock.isLockedByOtherThread() ) { + throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName()); + } + final boolean lockHeld = lock.isOwner(currentThread); + if( lockHeld && lock.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 @@ -258,7 +280,7 @@ public abstract class GLContextImpl extends GLContext { } public final GLDrawableImpl getDrawableImpl() { - return (GLDrawableImpl) getGLDrawable(); + return drawable; } @Override @@ -315,56 +337,57 @@ public abstract class GLContextImpl extends GLContext { release(false); } private void release(final boolean inDestruction) throws GLException { - if( TRACE_SWITCH ) { - System.err.println(getThreadName() +": GLContext.ContextSwitch[release.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock); - } - if ( !lock.isOwner(Thread.currentThread()) ) { - final String msg = getThreadName() +": Context not current on thread, obj " + toHexString(hashCode())+", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock; - if( DEBUG_TRACE_SWITCH ) { - System.err.println(msg); - if( null != lastCtxReleaseStack ) { - System.err.print("Last release call: "); - lastCtxReleaseStack.printStackTrace(); - } else { - System.err.println("Last release call: NONE"); - } - } - throw new GLException(msg); - } - - Throwable drawableContextMadeCurrentException = null; - final boolean actualRelease = ( inDestruction || lock.getHoldCount() == 1 ) && 0 != contextHandle; - try { - if( actualRelease ) { - if( !inDestruction ) { - try { - contextMadeCurrent(false); - } catch (final Throwable t) { - drawableContextMadeCurrentException = t; - } - } - releaseImpl(); - } - } finally { - // exception prone .. - if( actualRelease ) { - setCurrent(null); + if( TRACE_SWITCH ) { + final long drawH = null != drawable ? drawable.getHandle() : 0; + System.err.println(getThreadName() +": GLContext.ContextSwitch[release.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+(null!=drawable)+" "+toHexString(drawH)+", inDestruction: "+inDestruction+", "+lock); } - drawable.unlockSurface(); - lock.unlock(); - 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 ")+" - "+lock; - lastCtxReleaseStack = new Throwable(msg); - if( TRACE_SWITCH ) { + if ( !lock.isOwner(Thread.currentThread()) ) { + final long drawH = null != drawable ? drawable.getHandle() : 0; + final String msg = getThreadName() +": Context not current on thread, obj " + toHexString(hashCode())+", ctx "+toHexString(contextHandle)+", surf "+(null!=drawable)+" "+toHexString(drawH)+", inDestruction: "+inDestruction+", "+lock; + if( DEBUG_TRACE_SWITCH ) { System.err.println(msg); - // Thread.dumpStack(); + if( null != lastCtxReleaseStack ) { + System.err.print("Last release call: "); + lastCtxReleaseStack.printStackTrace(); + } else { + System.err.println("Last release call: NONE"); + } } + throw new GLException(msg); } - } - if(null != drawableContextMadeCurrentException) { - throw new GLException("GLContext.release(false) during GLDrawableImpl.contextMadeCurrent(this, false)", drawableContextMadeCurrentException); - } + Throwable drawableContextMadeCurrentException = null; + final boolean actualRelease = ( inDestruction || lock.getHoldCount() == 1 ) && 0 != contextHandle; + try { + if( actualRelease ) { + if( !inDestruction ) { + try { + contextMadeCurrent(false); + } catch (final Throwable t) { + drawableContextMadeCurrentException = t; + } + } + releaseImpl(); + } + } finally { + // exception prone .. + if( actualRelease ) { + setCurrent(null); + } + lock.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 ")+" - "+lock; + lastCtxReleaseStack = new Throwable(msg); + if( TRACE_SWITCH ) { + System.err.println(msg); + // Thread.dumpStack(); + } + } + } + if(null != drawableContextMadeCurrentException) { + throw new GLException("GLContext.release(false) during GLDrawableImpl.contextMadeCurrent(this, false)", drawableContextMadeCurrentException); + } } private Throwable lastCtxReleaseStack = null; protected abstract void releaseImpl() throws GLException; @@ -374,7 +397,7 @@ public abstract class GLContextImpl extends GLContext { if ( DEBUG_TRACE_SWITCH ) { final long drawH = null != drawable ? drawable.getHandle() : 0; System.err.println(getThreadName() + ": GLContextImpl.destroy.0: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + - ", surf "+toHexString(drawH)+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); + ", surf "+(null!=drawable)+" "+toHexString(drawH)+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); } if ( 0 != contextHandle ) { // isCreated() ? if ( null == drawable ) { @@ -393,9 +416,9 @@ public abstract class GLContextImpl extends GLContext { // Must hold the lock around the destroy operation to make sure we // don't destroy the context while another thread renders to it. lock.lock(); // holdCount++ -> 1 - n (1: not locked, 2-n: destroy while rendering) - if ( lock.getHoldCount() > 2 ) { - final String msg = getThreadName() + ": GLContextImpl.destroy: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle); - if ( DEBUG_TRACE_SWITCH ) { + if ( DEBUG_TRACE_SWITCH ) { + if ( lock.getHoldCount() > 2 ) { + final String msg = getThreadName() + ": GLContextImpl.destroy: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle); System.err.println(msg+" - Lock was hold more than once - makeCurrent/release imbalance: "+lock); Thread.dumpStack(); } @@ -519,8 +542,16 @@ public abstract class GLContextImpl extends GLContext { } protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException { + final boolean hasDrawable = null != drawable; if( TRACE_SWITCH ) { - System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock); + final long drawH = null != drawable ? drawable.getHandle() : 0; + System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+hasDrawable+" "+toHexString(drawH)+" - "+lock); + } + if( !hasDrawable ) { + if( DEBUG_TRACE_SWITCH ) { + System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - NULL Drawable - CONTEXT_NOT_CURRENT - "+lock); + } + return CONTEXT_NOT_CURRENT; } // Note: the surface is locked within [makeCurrent .. swap .. release] @@ -589,12 +620,12 @@ public abstract class GLContextImpl extends GLContext { } } - if (res != CONTEXT_NOT_CURRENT) { + if (res != CONTEXT_NOT_CURRENT) { // still locked! setCurrent(this); if(res == CONTEXT_CURRENT_NEW) { // check if the drawable's and the GL's GLProfile are equal // throws an GLException if not - getGLDrawable().getGLProfile().verifyEquality(gl.getGLProfile()); + drawable.getGLProfile().verifyEquality(gl.getGLProfile()); glDebugHandler.init( isGL2GL3() && isGLDebugEnabled() ); @@ -632,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() ) { @@ -646,20 +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) { - shareWith.getDrawableImpl().lockSurface(); - 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(); @@ -671,8 +709,8 @@ public abstract class GLContextImpl extends GLContext { } } } finally { - if (null != shareWith) { - shareWith.getDrawableImpl().unlockSurface(); + if ( null != sharedMaster ) { + sharedMaster.drawable.unlockSurface(); } } if ( DEBUG_TRACE_SWITCH ) { @@ -702,13 +740,32 @@ public abstract class GLContextImpl extends GLContext { } else { reqMajor = ctxVersion.getMajor(); } + final boolean isCompat; if( 0 != ( ctxOptions & GLContext.CTX_PROFILE_CORE) ) { reqProfile = GLContext.CTX_PROFILE_CORE; + isCompat = false; } else { reqProfile = GLContext.CTX_PROFILE_COMPAT; + isCompat = true; + } + GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + // Perform all required profile mappings + if( isCompat ) { + // COMPAT via non ARB + GLContext.mapAvailableGLVersion(device, reqMajor, GLContext.CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + if( reqMajor >= 4 ) { + GLContext.mapAvailableGLVersion(device, 3, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + GLContext.mapAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + } + if( reqMajor >= 3 ) { + GLContext.mapAvailableGLVersion(device, 2, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + } + } else { + // CORE via non ARB, unlikely, however .. + if( reqMajor >= 4 ) { + GLContext.mapAvailableGLVersion(device, 3, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + } } - GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, - ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); GLContext.setAvailableGLVersionsSet(device); if (DEBUG) { @@ -749,8 +806,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 ; @@ -818,6 +875,9 @@ public abstract class GLContextImpl extends GLContext { */ protected final long createContextARB(final long share, final boolean direct) { + if( GLProfile.disableOpenGLARBContext ) { + return 0; + } final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice device = config.getScreen().getDevice(); @@ -879,7 +939,7 @@ public abstract class GLContextImpl extends GLContext { /** * OSX 10.9 GLRendererQuirks.GL4NeedsGL3Request, quirk is added as usual @ setRendererQuirks(..) */ - if( !hasGL4 && !hasGL3 ) { + if( !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) { hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3 success |= hasGL3; if( hasGL3 ) { @@ -896,25 +956,27 @@ public abstract class GLContextImpl extends GLContext { } } } - if( !hasGL4 ) { - hasGL4 = createContextARBMapVersionsAvailable(4, CTX_PROFILE_CORE); // GL4 - success |= hasGL4; - if( hasGL4 ) { - if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { - // Map hw-accel GL4 to all lower core profiles: GL3 - GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - if( PROFILE_ALIASING ) { - hasGL3 = true; + if( !GLProfile.disableOpenGLCore ) { + if( !hasGL4 ) { + hasGL4 = createContextARBMapVersionsAvailable(4, CTX_PROFILE_CORE); // GL4 + success |= hasGL4; + if( hasGL4 ) { + if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { + // Map hw-accel GL4 to all lower core profiles: GL3 + GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + if( PROFILE_ALIASING ) { + hasGL3 = true; + } } + resetStates(false); // clean context states, since creation was temporary } - resetStates(false); // clean context states, since creation was temporary } - } - if( !hasGL3 ) { - hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3 - success |= hasGL3; - if( hasGL3 ) { - resetStates(false); // clean this context states, since creation was temporary + if( !hasGL3 ) { + hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3 + success |= hasGL3; + if( hasGL3 ) { + resetStates(false); // clean this context states, since creation was temporary + } } } if( !hasGL4bc ) { @@ -1372,7 +1434,7 @@ public abstract class GLContextImpl extends GLContext { } if(null==this.gl || !verifyInstance(gl.getGLProfile(), "Impl", this.gl)) { - setGL( createGL( getGLDrawable().getGLProfile() ) ); + setGL( createGL( drawable.getGLProfile() ) ); } updateGLXProcAddressTable(); @@ -1545,6 +1607,10 @@ public abstract class GLContextImpl extends GLContext { ctxProfileBits &= ~ ( GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_ES3_COMPAT ) ; } + if(!isCurrentContextHardwareRasterizer()) { + ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT; + } + final VersionNumberString vendorVersion = GLVersionNumber.createVendorVersion(glVersion); setRendererQuirks(adevice, getDrawableImpl().getFactoryImpl(), @@ -1558,10 +1624,6 @@ public abstract class GLContextImpl extends GLContext { return false; } - if(!isCurrentContextHardwareRasterizer()) { - ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT; - } - contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits); if (DEBUG) { System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)); @@ -1669,9 +1731,6 @@ public abstract class GLContextImpl extends GLContext { final int reqMajor, final int reqMinor, final int reqCTP, final int major, final int minor, final int ctp, final VersionNumberString vendorVersion, final boolean withinGLVersionsMapping) { - final int[] quirks = new int[GLRendererQuirks.COUNT + 1]; // + 1 ( NoFullFBOSupport ) - int i = 0; - final String MesaSP = "Mesa "; // final String MesaRendererAMDsp = " AMD "; final String MesaRendererIntelsp = "Intel(R)"; @@ -1684,6 +1743,8 @@ public abstract class GLContextImpl extends GLContext { final boolean isDriverATICatalyst = !isDriverMesa && ( glVendor.contains("ATI Technologies") || glRenderer.startsWith("ATI ") ); final boolean isDriverNVIDIAGeForce = !isDriverMesa && ( glVendor.contains("NVIDIA Corporation") || glRenderer.contains("NVIDIA ") ); + final GLRendererQuirks quirks = new GLRendererQuirks(); + // // General Quirks // @@ -1693,14 +1754,14 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); if( withinGLVersionsMapping ) { // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); } else { // FIXME: Remove when moving EGL/ES to ARB ctx creation synchronized(GLContextImpl.class) { - GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); } } } @@ -1718,17 +1779,17 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 && 3==reqMajor && 4==major ) { final int quirk = GLRendererQuirks.GL4NeedsGL3Request; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", req "+reqMajor+"."+reqMinor); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); if( withinGLVersionsMapping ) { // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); } } if( isDriverNVIDIAGeForce ) { @@ -1738,14 +1799,14 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Lion) < 0 ) { // < OSX 10.7.0 w/ NV has unstable GLSL final int quirk = GLRendererQuirks.GLSLNonCompliant; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } } } else if( isWindows ) { @@ -1757,7 +1818,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } if( isDriverATICatalyst ) { @@ -1769,7 +1830,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"], driverVersion "+vendorVersion); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } if( Platform.getOSVersionNumber().compareTo(winXPVersionNumber) <= 0 ) { @@ -1777,7 +1838,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS-Version "+Platform.getOSType()+" "+Platform.getOSVersionNumber()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"]"); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } } } else if( Platform.OSType.ANDROID == Platform.getOSType() ) { @@ -1790,14 +1851,14 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } if( glRenderer.contains("Immersion.16") ) { - final int quirk = GLRendererQuirks.GLSharedContextBuggy; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer); - } - quirks[i++] = quirk; + final int quirk = GLRendererQuirks.GLSharedContextBuggy; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer); + } + quirks.addQuirk( quirk ); } } @@ -1818,21 +1879,21 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer + ", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]"); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } } else if( isDriverATICatalyst ) { { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } } else if( jogamp.nativewindow.x11.X11Util.getMarkAllDisplaysUnclosable() ) { { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11Util Downstream"); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } } } @@ -1843,6 +1904,7 @@ public abstract class GLContextImpl extends GLContext { // RENDERER related quirks // if( isDriverMesa ) { + final VersionNumber mesaSafeFBOVersion = new VersionNumber(8, 0, 0); final VersionNumber mesaIntelBuggySharedCtx921 = new VersionNumber(9, 2, 1); { @@ -1850,88 +1912,103 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); } - if( hwAccel /* glRenderer.contains( MesaRendererIntelsp ) || glRenderer.contains( MesaRendererAMDsp ) */ ) - { + if( hwAccel ) { + // hardware-acceleration final int quirk = GLRendererQuirks.NoDoubleBufferedPBuffer; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); + } else { + // software + if( vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { // FIXME: Is it fixed in >= 8.0.0 ? + final int quirk = GLRendererQuirks.BuggyColorRenderbuffer; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer + " / Mesa-Version "+vendorVersion); + } + quirks.addQuirk( quirk ); + } } if (compatCtx && (major > 3 || (major == 3 && minor >= 1))) { - // FIXME: Apply vendor version constraints! - final int quirk = GLRendererQuirks.GLNonCompliant; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); - } - quirks[i++] = quirk; + // FIXME: Apply vendor version constraints! + final int quirk = GLRendererQuirks.GLNonCompliant; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); + } + quirks.addQuirk( quirk ); } if( glRenderer.contains( MesaRendererIntelsp ) && vendorVersion.compareTo(mesaIntelBuggySharedCtx921) >= 0 && isX11 ) { // FIXME: When is it fixed ? - final int quirk = GLRendererQuirks.GLSharedContextBuggy; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion); - } - quirks[i++] = quirk; + final int quirk = GLRendererQuirks.GLSharedContextBuggy; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion); + } + quirks.addQuirk( quirk ); } if( glVendor.contains( "nouveau" ) // FIXME: && vendorVersion.compareTo(nouveauBuggyMSAAFixed) < 0 ) { - final int quirk = GLRendererQuirks.NoMultiSamplingBuffers; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Vendor "+glVendor); - } - quirks[i++] = quirk; - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1); - } + final int quirk = GLRendererQuirks.NoMultiSamplingBuffers; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Vendor "+glVendor); + } + quirks.addQuirk( quirk ); + if( withinGLVersionsMapping ) { + // Thread safe due to single threaded initialization! + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } } - if( isWindows && glRenderer.contains("SVGA3D") ) { - final VersionNumber mesaSafeFBOVersion = new VersionNumber(8, 0, 0); - if ( vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { // includes: vendorVersion.isZero() - final int quirk = GLRendererQuirks.NoFullFBOSupport; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion); - } - quirks[i++] = quirk; + if( isWindows && glRenderer.contains("SVGA3D") && vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { + final int quirk = GLRendererQuirks.NoFullFBOSupport; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion); } + quirks.addQuirk( quirk ); } } // // Property related quirks // - if( FORCE_MIN_FBO_SUPPORT ) { - final int quirk = GLRendererQuirks.NoFullFBOSupport; + if( FORCE_NO_COLOR_RENDERBUFFER ) { + final int quirk = GLRendererQuirks.BuggyColorRenderbuffer; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: property"); } - quirks[i++] = quirk; + quirks.addQuirk( quirk ); + } + if( FORCE_MIN_FBO_SUPPORT || quirks.exist(GLRendererQuirks.BuggyColorRenderbuffer) ) { + final int quirk = GLRendererQuirks.NoFullFBOSupport; + if(DEBUG) { + final String causeProps = FORCE_MIN_FBO_SUPPORT ? "property, " : ""; + final String causeQuirk = quirks.exist(GLRendererQuirks.BuggyColorRenderbuffer) ? "BuggyColorRenderbuffer" : ""; + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: "+causeProps+causeQuirk); + } + quirks.addQuirk( quirk ); } - glRendererQuirks = new GLRendererQuirks(quirks, 0, i); if(DEBUG) { - System.err.println("Quirks local.0: "+glRendererQuirks); + System.err.println("Quirks local.0: "+quirks); } { // Merge sticky quirks, thread safe due to single threaded initialization! - GLRendererQuirks.pushStickyDeviceQuirks(adevice, glRendererQuirks); + GLRendererQuirks.pushStickyDeviceQuirks(adevice, quirks); final AbstractGraphicsDevice factoryDefaultDevice = factory.getDefaultDevice(); if( !GLRendererQuirks.areSameStickyDevice(factoryDefaultDevice, adevice) ) { - GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, glRendererQuirks); + GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, quirks); } if( esCtx ) { final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice(); if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) && !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) { - GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, glRendererQuirks); + GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, quirks); } } } + glRendererQuirks = quirks; if(DEBUG) { System.err.println("Quirks local.X: "+glRendererQuirks); System.err.println("Quirks sticky on "+adevice+": "+GLRendererQuirks.getStickyDeviceQuirks(adevice)); @@ -2106,35 +2183,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/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<GLContext, ShareSet> shareMap = new IdentityHashMap<GLContext, ShareSet>(); - private static final Object dummyValue = new Object(); private static class ShareSet { - 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>(); + private final Map<GLContext, GLContext> createdShares = new IdentityHashMap<GLContext, GLContext>(); + private final Map<GLContext, GLContext> destroyedShares = new IdentityHashMap<GLContext, GLContext>(); - 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<GLContext> getCreatedShares() { @@ -86,57 +98,55 @@ public class GLContextShareSet { return destroyedShares.keySet(); } - 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; - } - } - 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 <code>share1</code> and - <code>share2</code> will share textures and display lists. Both + /** Indicate that contexts <code>slave</code> and + <code>master</code> 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<GLContext> 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 <code>context</code>, otherwise return <code>null</code>. */ - public static synchronized GLContext getCreatedShare(final GLContext context) { + /** + * Returns the shared master GLContext of the given <code>context</code> if shared, otherwise return <code>null</code>. + * <p> + * Returns the given <code>context</code>, if it is a shared master. + * </p> + */ + 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<GLContext> getCreatedSharesImpl(final GLContext context) { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 0b119b50d..8d65f16d3 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -41,8 +41,14 @@ package jogamp.opengl; import java.nio.Buffer; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerSurface; @@ -516,64 +522,98 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /** - * Sets the gamma, brightness, and contrast of the current main - * display. Returns true if the settings were changed, false if - * not. If this method returns true, the display settings will - * automatically be reset upon JVM exit (assuming the JVM does not - * crash); if the user wishes to change the display settings back to - * normal ahead of time, use resetDisplayGamma(). Throws - * IllegalArgumentException if any of the parameters were - * out-of-bounds. - * - * @param gamma The gamma value, typically > 1.0 (default value is - * 1.0) - * @param brightness The brightness value between -1.0 and 1.0, - * inclusive (default value is 0) - * @param contrast The contrast, greater than 0.0 (default value is 1) - * @throws IllegalArgumentException if any of the parameters were - * out-of-bounds - */ - public boolean setDisplayGamma(final float gamma, final float brightness, final float contrast) throws IllegalArgumentException { + @Override + public synchronized final boolean setDisplayGamma(final NativeSurface surface, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException { if ((brightness < -1.0f) || (brightness > 1.0f)) { throw new IllegalArgumentException("Brightness must be between -1.0 and 1.0"); } if (contrast < 0) { throw new IllegalArgumentException("Contrast must be greater than 0.0"); } - // FIXME: ensure gamma is > 1.0? Are smaller / negative values legal? - final int rampLength = getGammaRampLength(); - if (rampLength == 0) { - return false; + if( NativeSurface.LOCK_SURFACE_NOT_READY >= surface.lockSurface() ) { + return false; + } + try { + // FIXME: ensure gamma is > 1.0? Are smaller / negative values legal? + final int rampLength = getGammaRampLength(surface); + if (rampLength == 0) { + return false; + } + final float[] gammaRamp = new float[rampLength]; + for (int i = 0; i < rampLength; i++) { + final float intensity = (float) i / (float) (rampLength - 1); + // apply gamma + float rampEntry = (float) java.lang.Math.pow(intensity, gamma); + // apply brightness + rampEntry += brightness; + // apply contrast + rampEntry = (rampEntry - 0.5f) * contrast + 0.5f; + // Clamp entry to [0, 1] + if (rampEntry > 1.0f) + rampEntry = 1.0f; + else if (rampEntry < 0.0f) + rampEntry = 0.0f; + gammaRamp[i] = rampEntry; + } + final AbstractGraphicsScreen screen = surface.getGraphicsConfiguration().getScreen(); + final DeviceScreenID deviceScreenID = new DeviceScreenID(screen.getDevice().getConnection(), screen.getIndex()); + if( null == screen2OrigGammaRamp.get(deviceScreenID) ) { + screen2OrigGammaRamp.put(deviceScreenID, getGammaRamp(surface)); // cache original gamma ramp once + if( DEBUG ) { + System.err.println("DisplayGamma: Stored: "+deviceScreenID); + dumpGammaStore(); + } + } + return setGammaRamp(surface, gammaRamp); + } finally { + surface.unlockSurface(); } - final float[] gammaRamp = new float[rampLength]; - for (int i = 0; i < rampLength; i++) { - final float intensity = (float) i / (float) (rampLength - 1); - // apply gamma - float rampEntry = (float) java.lang.Math.pow(intensity, gamma); - // apply brightness - rampEntry += brightness; - // apply contrast - rampEntry = (rampEntry - 0.5f) * contrast + 0.5f; - // Clamp entry to [0, 1] - if (rampEntry > 1.0f) - rampEntry = 1.0f; - else if (rampEntry < 0.0f) - rampEntry = 0.0f; - gammaRamp[i] = rampEntry; + } + + @Override + public synchronized final void resetDisplayGamma(final NativeSurface surface) { + if( NativeSurface.LOCK_SURFACE_NOT_READY >= surface.lockSurface() ) { + return; } - if( !needsGammaRampReset ) { - originalGammaRamp = getGammaRamp(); - needsGammaRampReset = true; + try { + final AbstractGraphicsScreen screen = surface.getGraphicsConfiguration().getScreen(); + final DeviceScreenID deviceScreenID = new DeviceScreenID(screen.getDevice().getConnection(), screen.getIndex()); + final Buffer originalGammaRamp = screen2OrigGammaRamp.remove(deviceScreenID); + if( null != originalGammaRamp ) { + resetGammaRamp(surface, originalGammaRamp); + } + } finally { + surface.unlockSurface(); } - return setGammaRamp(gammaRamp); } @Override - public synchronized void resetDisplayGamma() { - if( needsGammaRampReset ) { - resetGammaRamp(originalGammaRamp); - needsGammaRampReset = false; + public synchronized final void resetAllDisplayGamma() { + resetAllDisplayGammaNoSync(); + } + + @Override + protected final void resetAllDisplayGammaNoSync() { + if( DEBUG ) { + System.err.println("DisplayGamma: Reset"); + dumpGammaStore(); + } + final Set<DeviceScreenID> deviceScreenIDs = screen2OrigGammaRamp.keySet(); + for( final Iterator<DeviceScreenID> i = deviceScreenIDs.iterator(); i.hasNext(); ) { + final DeviceScreenID deviceScreenID = i.next(); + final Buffer originalGammaRamp = screen2OrigGammaRamp.remove(deviceScreenID); + if( null != originalGammaRamp ) { + resetGammaRamp(deviceScreenID, originalGammaRamp); + } + } + } + private void dumpGammaStore() { + final Set<DeviceScreenID> deviceScreenIDs = screen2OrigGammaRamp.keySet(); + int count = 0; + for( final Iterator<DeviceScreenID> i = deviceScreenIDs.iterator(); i.hasNext(); count++) { + final DeviceScreenID deviceScreenID = i.next(); + final Buffer originalGammaRamp = screen2OrigGammaRamp.get(deviceScreenID); + System.err.printf("%4d/%4d: %s -> %s%n", count, deviceScreenIDs.size(), deviceScreenID, originalGammaRamp); } } @@ -582,30 +622,64 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // /** Returns the length of the computed gamma ramp for this OS and - hardware. Returns 0 if gamma changes are not supported. */ - protected int getGammaRampLength() { + hardware. Returns 0 if gamma changes are not supported. + * @param surface TODO*/ + protected int getGammaRampLength(final NativeSurface surface) { return 0; } /** Sets the gamma ramp for the main screen. Returns false if gamma - ramp changes were not supported. */ - protected boolean setGammaRamp(final float[] ramp) { + ramp changes were not supported. + * @param surface TODO*/ + protected boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { return false; } /** Gets the current gamma ramp. This is basically an opaque value used only on some platforms to reset the gamma ramp to its - original settings. */ - protected Buffer getGammaRamp() { + original settings. + * @param surface TODO*/ + protected Buffer getGammaRamp(final NativeSurface surface) { return null; } /** Resets the gamma ramp, potentially using the specified Buffer as - data to restore the original values. */ - protected void resetGammaRamp(final Buffer originalGammaRamp) { + data to restore the original values. + * @param surface TODO*/ + protected void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { + } + protected void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { } // Shutdown hook mechanism for resetting gamma - private volatile Buffer originalGammaRamp; - private volatile boolean needsGammaRampReset = false; + public final class DeviceScreenID { + public final String deviceConnection; + public final int screenIdx; + DeviceScreenID(final String deviceConnection, final int screenIdx) { + this.deviceConnection = deviceConnection; + this.screenIdx = screenIdx; + } + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + deviceConnection.hashCode(); + hash = ((hash << 5) - hash) + screenIdx; + return hash; + } + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof DeviceScreenID) { + final DeviceScreenID other = (DeviceScreenID)obj; + return this.deviceConnection.equals(other.deviceConnection) && + this.screenIdx == other.screenIdx; + } + return false; + } + @Override + public String toString() { + return "DeviceScreenID[devCon "+deviceConnection+", screenIdx "+screenIdx+", hash 0x"+Integer.toHexString(hashCode())+"]"; + } + } + private final Map<DeviceScreenID, Buffer> screen2OrigGammaRamp = new HashMap<DeviceScreenID, Buffer>(); } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index eac14fdff..3deeafd27 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -40,6 +40,7 @@ package jogamp.opengl; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.HashSet; @@ -77,7 +78,8 @@ public class GLDrawableHelper { private final ArrayList<GLEventListener> listeners = new ArrayList<GLEventListener>(); private final HashSet<GLEventListener> listenersToBeInit = new HashSet<GLEventListener>(); private final Object glRunnablesLock = new Object(); - private volatile ArrayList<GLRunnableTask> glRunnables = new ArrayList<GLRunnableTask>(); + private ArrayList<GLRunnableTask> glRunnables = new ArrayList<GLRunnableTask>(); + private volatile int glRunnableCount = 0; private boolean autoSwapBufferMode; private volatile Thread exclusiveContextThread; /** -1 release, 0 nop, 1 claim */ @@ -102,6 +104,7 @@ public class GLDrawableHelper { exclusiveContextThread = null; exclusiveContextSwitch = 0; synchronized(glRunnablesLock) { + glRunnableCount = 0; glRunnables.clear(); } animatorCtrl = null; @@ -208,19 +211,23 @@ public class GLDrawableHelper { /** * Switch {@link GLContext} / {@link GLDrawable} association. * <p> - * The <code>oldCtx</code> will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>, - * otherwise dis-associate <code>oldCtx</code> from <code>drawable</code> - * via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);}. - * </p> - * <p> - * Re-associate <code>newCtx</code> with <code>drawable</code> - * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. - * </p> - * <p> - * If the old or new context was current on this thread, it is being released before switching the drawable. - * </p> - * <p> - * No locking is being performed on the drawable, caller is required to take care of it. + * Remarks: + * <ul> + * <li>The <code>oldCtx</code> will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>, + * otherwise disassociate <code>oldCtx</code> from <code>drawable</code> + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) oldCtx.setGLDrawable(null, true);} including {@link GL#glFinish() glFinish()}.</li> + * <li>Reassociate <code>newCtx</code> with <code>drawable</code> + * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.</li> + * <li>If the old context was current on this thread, it is being released after disassociating the drawable.</li> + * <li>If the new context was current on this thread, it is being released before associating the drawable + * and made current afterwards.</li> + * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li> + * <li>The user shall take extra care of thread synchronization, + * i.e. lock the involved {@link GLDrawable#getNativeSurface() drawable's} {@link NativeSurface}s + * to avoid a race condition. In case {@link GLAutoDrawable auto-drawable's} are used, + * their {@link GLAutoDrawable#getUpstreamLock() upstream-lock} must be locked beforehand + * see <a href="../../javax/media/opengl/GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.</li> + * </ul> * </p> * * @param drawable the drawable which context is changed @@ -277,7 +284,6 @@ public class GLDrawableHelper { if( currentContext != context ) { context.makeCurrent(); } - context.getGL().glFinish(); context.setGLDrawable(null, true); // dis-associate } @@ -295,7 +301,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 ) { @@ -506,15 +512,25 @@ public class GLDrawableHelper { * </p> * @param autoDrawable * @return the disposal count + * @throws GLException caused by {@link GLEventListener#dispose(GLAutoDrawable)} */ - public final int disposeAllGLEventListener(final GLAutoDrawable autoDrawable, final boolean remove) { + public final int disposeAllGLEventListener(final GLAutoDrawable autoDrawable, final boolean remove) throws GLException { + Throwable firstCaught = null; int disposeCount = 0; synchronized(listenersLock) { if( remove ) { for (int count = listeners.size(); 0 < count && 0 < listeners.size(); count--) { final GLEventListener listener = listeners.remove(0); if( !listenersToBeInit.remove(listener) ) { - listener.dispose(autoDrawable); + try { + listener.dispose(autoDrawable); + } catch (final Throwable t) { + if( null == firstCaught ) { + firstCaught = t; + } else { + GLException.dumpThrowable("subsequent", t); + } + } disposeCount++; } } @@ -522,13 +538,25 @@ public class GLDrawableHelper { for (int i = 0; i < listeners.size(); i++) { final GLEventListener listener = listeners.get(i); if( !listenersToBeInit.contains(listener) ) { - listener.dispose(autoDrawable); + try { + listener.dispose(autoDrawable); + } catch (final Throwable t) { + if( null == firstCaught ) { + firstCaught = t; + } else { + GLException.dumpThrowable("subsequent", t); + } + } listenersToBeInit.add(listener); disposeCount++; } } } } + if( null != firstCaught ) { + flushGLRunnables(); + throw GLException.newGLException(firstCaught); + } return disposeCount; } @@ -634,7 +662,7 @@ public class GLDrawableHelper { init( listener, drawable, sendReshape, 0==i /* setViewport */); } } else { - // Expose same GL initialization if not using GLEventListener + // Expose same GL initialization if not using any GLEventListener drawable.getGL().glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); } } @@ -643,7 +671,7 @@ public class GLDrawableHelper { public final void display(final GLAutoDrawable drawable) { displayImpl(drawable); // runForAllGLEventListener(drawable, displayAction); - if( glRunnables.size()>0 && !execGLRunnables(drawable) ) { // glRunnables volatile OK; execGL.. only executed if size > 0 + if( glRunnableCount > 0 && !execGLRunnables(drawable) ) { // glRunnableCount volatile OK; execGL.. only executed if size > 0 displayImpl(drawable); // runForAllGLEventListener(drawable, displayAction); } @@ -701,11 +729,10 @@ public class GLDrawableHelper { } } if(setViewport) { - final GL gl = drawable.getGL(); - final int glerr0 = gl.glGetError(); - if( GL.GL_NO_ERROR != glerr0 ) { - System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); - if(DEBUG) { + if( GLContext.DEBUG_GL || DEBUG ) { + final int glerr0 = drawable.getGL().glGetError(); + if( GL.GL_NO_ERROR != glerr0 ) { + System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); Thread.dumpStack(); } } @@ -723,43 +750,29 @@ public class GLDrawableHelper { } private final boolean execGLRunnables(final GLAutoDrawable drawable) { // glRunnables.size()>0 - boolean res = true; // swap one-shot list asap final ArrayList<GLRunnableTask> _glRunnables; synchronized(glRunnablesLock) { - if(glRunnables.size()>0) { + if( glRunnables.size() > 0 ) { + glRunnableCount = 0; _glRunnables = glRunnables; glRunnables = new ArrayList<GLRunnableTask>(); } else { - _glRunnables = null; + return true; } } - - if(null!=_glRunnables) { - for (int i=0; i < _glRunnables.size(); i++) { - res = _glRunnables.get(i).run(drawable) && res; - } + boolean res = true; + for (int i=0; i < _glRunnables.size(); i++) { + res = _glRunnables.get(i).run(drawable) && res; } return res; } public final void flushGLRunnables() { - if(glRunnables.size()>0) { // volatile OK - // swap one-shot list asap - final ArrayList<GLRunnableTask> _glRunnables; - synchronized(glRunnablesLock) { - if(glRunnables.size()>0) { - _glRunnables = glRunnables; - glRunnables = new ArrayList<GLRunnableTask>(); - } else { - _glRunnables = null; - } - } - - if(null!=_glRunnables) { - for (int i=0; i < _glRunnables.size(); i++) { - _glRunnables.get(i).flush(); - } + synchronized(glRunnablesLock) { + glRunnableCount = 0; + while( glRunnables.size() > 0 ) { + glRunnables.remove(0).flush(); } } } @@ -795,6 +808,30 @@ public class GLDrawableHelper { return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ; } + public static final boolean isLockedByOtherThread(final GLAutoDrawable d) { + final Thread currentThread = Thread.currentThread(); + final Thread upstreamLockOwner = d.getUpstreamLock().getOwner(); + if( null != upstreamLockOwner && currentThread != upstreamLockOwner ) { + return true; + } else { + final NativeSurface s = d.getNativeSurface(); + final Thread surfaceLockOwner = null != s ? s.getSurfaceLockOwner() : null; + return null != surfaceLockOwner && currentThread != surfaceLockOwner; + } + } + + public static final boolean isLockedByThisThread(final GLAutoDrawable d) { + final Thread currentThread = Thread.currentThread(); + final Thread upstreamLockOwner = d.getUpstreamLock().getOwner(); + if( currentThread == upstreamLockOwner ) { + return true; + } else { + final NativeSurface s = d.getNativeSurface(); + final Thread surfaceLockOwner = null != s ? s.getSurfaceLockOwner() : null; + return currentThread == surfaceLockOwner; + } + } + /** * <p> * If <code>wait</code> is <code>true</code> the call blocks until the <code>glRunnable</code> @@ -805,13 +842,32 @@ public class GLDrawableHelper { * the call is ignored and returns <code>false</code>.<br> * This helps avoiding deadlocking the caller. * </p> + * <p> + * <pre> + * 0 == deferredHere && 0 == isGLThread -> display() will issue on GL thread, blocking! + * + * deferredHere wait isGLThread lockedByThisThread Note + * OK 0 x 1 x + * OK 0 x 0 0 + * ERROR 0 x 0 1 Will be deferred on GL thread by display() (blocking), + * but locked by this thread -> ERROR + * + * 1 0 x x All good, due to no wait, non blocking + * + * 1 1 1 0 + * 1 1 0 0 + * SWITCH 1 1 1 1 Run immediately, don't defer since locked by this thread, but isGLThread + * ERROR 1 1 0 1 Locked by this thread, but _not_ isGLThread -> ERROR + * </pre> + * </p> * * @param drawable the {@link GLAutoDrawable} to be used * @param wait if <code>true</code> block until execution of <code>glRunnable</code> is finished, otherwise return immediatly w/o waiting * @param glRunnable the {@link GLRunnable} to execute within {@link #display()} * @return <code>true</code> if the {@link GLRunnable} has been processed or queued, otherwise <code>false</code>. + * @throws IllegalStateException in case the drawable is locked by this thread, no animator is running on another thread and <code>wait</code> is <code>true</code>. */ - public final boolean invoke(final GLAutoDrawable drawable, boolean wait, final GLRunnable glRunnable) { + public final boolean invoke(final GLAutoDrawable drawable, boolean wait, final GLRunnable glRunnable) throws IllegalStateException { if( null == glRunnable || null == drawable || wait && ( !drawable.isRealized() || null==drawable.getContext() ) ) { return false; @@ -821,18 +877,35 @@ public class GLDrawableHelper { final Object rTaskLock = new Object(); Throwable throwable = null; synchronized(rTaskLock) { - final boolean deferred; + boolean deferredHere; synchronized(glRunnablesLock) { - deferred = isAnimatorAnimatingOnOtherThread(); - if(!deferred) { - wait = false; // don't wait if exec immediatly + final boolean isGLThread = drawable.isThreadGLCapable(); + deferredHere = isAnimatorAnimatingOnOtherThread(); + if( deferredHere ) { + if( wait && isLockedByThisThread(drawable) ) { + if( isGLThread ) { + // Run immediately, don't defer since locked by this thread, but isGLThread + deferredHere = false; + wait = false; + } else { + // Locked by this thread, but _not_ isGLThread -> ERROR + throw new IllegalStateException("Deferred, wait, isLocked on current and not GL-Thread: thread "+Thread.currentThread()); + } + } + } else { + if( !isGLThread && isLockedByThisThread(drawable) ) { + // Will be deferred on GL thread by display() (blocking), but locked by this thread -> ERROR + throw new IllegalStateException("Not deferred, isLocked on current and not GL-Thread: thread "+Thread.currentThread()); + } + wait = false; // don't wait if exec immediately } rTask = new GLRunnableTask(glRunnable, wait ? rTaskLock : null, wait /* catch Exceptions if waiting for result */); + glRunnableCount++; glRunnables.add(rTask); } - if( !deferred ) { + if( !deferredHere ) { drawable.display(); } else if( wait ) { try { @@ -851,7 +924,16 @@ public class GLDrawableHelper { return true; } - public final boolean invoke(final GLAutoDrawable drawable, boolean wait, final List<GLRunnable> newGLRunnables) { + /** + * @see #invoke(GLAutoDrawable, boolean, GLRunnable) + * + * @param drawable + * @param wait + * @param newGLRunnables + * @return + * @throws IllegalStateException + */ + public final boolean invoke(final GLAutoDrawable drawable, boolean wait, final List<GLRunnable> newGLRunnables) throws IllegalStateException { if( null == newGLRunnables || newGLRunnables.size() == 0 || null == drawable || wait && ( !drawable.isRealized() || null==drawable.getContext() ) ) { return false; @@ -862,21 +944,39 @@ public class GLDrawableHelper { final Object rTaskLock = new Object(); Throwable throwable = null; synchronized(rTaskLock) { - final boolean deferred; + boolean deferredHere; synchronized(glRunnablesLock) { - deferred = isAnimatorAnimatingOnOtherThread() || !drawable.isRealized(); - if(!deferred) { + final boolean isGLThread = drawable.isThreadGLCapable(); + deferredHere = isAnimatorAnimatingOnOtherThread(); + if( deferredHere ) { + if( wait && isLockedByThisThread(drawable) ) { + if( isGLThread ) { + // Run immediately, don't defer since locked by this thread, but isGLThread + deferredHere = false; + wait = false; + } else { + // Locked by this thread, but _not_ isGLThread -> ERROR + throw new IllegalStateException("Deferred, wait, isLocked on current and not GL-Thread: thread "+Thread.currentThread()); + } + } + } else { + if( !isGLThread && isLockedByThisThread(drawable) ) { + // Will be deferred on GL thread by display() (blocking), but locked by this thread -> ERROR + throw new IllegalStateException("Not deferred, isLocked on current and not GL-Thread: thread "+Thread.currentThread()); + } wait = false; // don't wait if exec immediately } for(int i=0; i<count-1; i++) { + glRunnableCount++; glRunnables.add( new GLRunnableTask(newGLRunnables.get(i), null, false) ); } rTask = new GLRunnableTask(newGLRunnables.get(count-1), wait ? rTaskLock : null, wait /* catch Exceptions if waiting for result */); + glRunnableCount++; glRunnables.add(rTask); } - if( !deferred ) { + if( !deferredHere ) { drawable.display(); } else if( wait ) { try { @@ -900,6 +1000,7 @@ public class GLDrawableHelper { return; } synchronized(glRunnablesLock) { + glRunnableCount++; glRunnables.add( new GLRunnableTask(glRunnable, null, false) ); } } @@ -961,8 +1062,8 @@ public class GLDrawableHelper { try { forceNativeRelease(context); } catch (final Throwable ex) { - ex.printStackTrace(); - throw new GLException(ex); + flushGLRunnables(); + throw GLException.newGLException(ex); } } exclusiveContextThread = t; @@ -980,7 +1081,21 @@ public class GLDrawableHelper { return exclusiveContextThread; } - private static final ThreadLocal<Runnable> perThreadInitAction = new ThreadLocal<Runnable>(); + private static final ThreadLocal<WeakReference<Runnable>> perThreadInitAction = new ThreadLocal<WeakReference<Runnable>>(); + private static final Runnable getLastInitAction() { + final WeakReference<Runnable> lastInitActionWR = perThreadInitAction.get(); + if( null != lastInitActionWR ) { + final Runnable lastInitAction = lastInitActionWR.get(); + if( null == lastInitAction ) { + perThreadInitAction.set(null); + } + return lastInitAction; + } + return null; + } + private static final void setLastInitAction(final Runnable initAction) { + perThreadInitAction.set(new WeakReference<Runnable>(initAction)); + } /** Principal helper method which runs a Runnable with the context made current. This could have been made part of GLContext, but a @@ -1004,8 +1119,7 @@ public class GLDrawableHelper { final Runnable initAction) { if(null==context) { if (DEBUG) { - final Exception e = new GLException(getThreadName()+" Info: GLDrawableHelper " + this + ".invokeGL(): NULL GLContext"); - e.printStackTrace(); + GLException.dumpThrowable("informal", new GLException("Info: GLDrawableHelper " + this + ".invokeGL(): NULL GLContext")); } return; } @@ -1030,9 +1144,11 @@ public class GLDrawableHelper { * @param autoDrawable * @param context * @param destroyContext destroy context in the end while holding the lock + * @throws GLException caused by {@link GLEventListener#dispose(GLAutoDrawable)} or context closing + * */ public final void disposeGL(final GLAutoDrawable autoDrawable, - final GLContext context, final boolean destroyContext) { + final GLContext context, final boolean destroyContext) throws GLException { // Support for recursive makeCurrent() calls as well as calling // other drawables' display() methods from within another one's GLContext lastContext = GLContext.getCurrent(); @@ -1042,20 +1158,27 @@ public class GLDrawableHelper { lastContext = null; } else { // utilize recursive locking - lastInitAction = perThreadInitAction.get(); + lastInitAction = getLastInitAction(); lastContext.release(); } } + GLException disposeCaught = null; + Throwable contextCloseCaught = null; + int res; try { res = context.makeCurrent(); if (GLContext.CONTEXT_NOT_CURRENT != res) { if(GLContext.CONTEXT_CURRENT_NEW == res) { - throw new GLException(getThreadName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); + throw new GLException(GLDrawableHelper.getThreadName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); } if( listeners.size() > 0 && null != autoDrawable ) { - disposeAllGLEventListener(autoDrawable, false); + try { + disposeAllGLEventListener(autoDrawable, false); + } catch(final GLException t) { + disposeCaught = t; + } } } } finally { @@ -1065,17 +1188,26 @@ public class GLDrawableHelper { } else { forceNativeRelease(context); } - flushGLRunnables(); - } catch (final Exception e) { - System.err.println("Caught exception on thread "+getThreadName()); - e.printStackTrace(); + } catch (final Throwable t) { + contextCloseCaught = t; } + flushGLRunnables(); // always flush GLRunnables at dispose + if (lastContext != null) { final int res2 = lastContext.makeCurrent(); if (null != lastInitAction && res2 == GLContext.CONTEXT_CURRENT_NEW) { lastInitAction.run(); } } + if( null != disposeCaught ) { + if( null != contextCloseCaught ) { + GLException.dumpThrowable("subsequent", contextCloseCaught); + } + throw disposeCaught; + } + if( null != contextCloseCaught ) { + throw GLException.newGLException(contextCloseCaught); + } } } @@ -1085,6 +1217,9 @@ public class GLDrawableHelper { final Runnable initAction) { final Thread currentThread = Thread.currentThread(); + Throwable glEventListenerCaught = null; + Throwable contextReleaseCaught = null; + // Exclusive Cases: // 1: lock - unlock : default // 2: lock - - : exclusive, not locked yet @@ -1116,7 +1251,7 @@ public class GLDrawableHelper { lastContext = null; } else { // utilize recursive locking - lastInitAction = perThreadInitAction.get(); + lastInitAction = getLastInitAction(); lastContext.release(); } } @@ -1131,7 +1266,7 @@ public class GLDrawableHelper { } if (GLContext.CONTEXT_NOT_CURRENT != res) { try { - perThreadInitAction.set(initAction); + setLastInitAction(initAction); if (GLContext.CONTEXT_CURRENT_NEW == res) { if (DEBUG) { System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); @@ -1142,6 +1277,8 @@ public class GLDrawableHelper { if ( autoSwapBufferMode ) { drawable.swapBuffers(); } + } catch (final Throwable t) { + glEventListenerCaught = t; } finally { if( _releaseExclusiveThread ) { exclusiveContextThread = null; @@ -1152,9 +1289,8 @@ public class GLDrawableHelper { if( releaseContext ) { try { context.release(); - } catch (final Exception e) { - System.err.println("Caught exception on thread "+getThreadName()); - e.printStackTrace(); + } catch (final Throwable t) { + contextReleaseCaught = t; } } } @@ -1166,6 +1302,17 @@ public class GLDrawableHelper { lastInitAction.run(); } } + if( null != glEventListenerCaught ) { + flushGLRunnables(); + if( null != contextReleaseCaught ) { + GLException.dumpThrowable("subsequent", contextReleaseCaught); + } + throw GLException.newGLException(glEventListenerCaught); + } + if( null != contextReleaseCaught ) { + flushGLRunnables(); + throw GLException.newGLException(contextReleaseCaught); + } } } @@ -1175,6 +1322,9 @@ public class GLDrawableHelper { final Runnable initAction) { final Thread currentThread = Thread.currentThread(); + Throwable glEventListenerCaught = null; + Throwable contextReleaseCaught = null; + // Exclusive Cases: // 1: lock - unlock : default // 2: lock - - : exclusive, not locked yet @@ -1205,7 +1355,7 @@ public class GLDrawableHelper { lastContext = null; } else { // utilize recursive locking - lastInitAction = perThreadInitAction.get(); + lastInitAction = getLastInitAction(); lastContext.release(); } } @@ -1229,7 +1379,7 @@ public class GLDrawableHelper { } if (GLContext.CONTEXT_NOT_CURRENT != res) { try { - perThreadInitAction.set(initAction); + setLastInitAction(initAction); if (GLContext.CONTEXT_CURRENT_NEW == res) { if (DEBUG) { System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); @@ -1246,6 +1396,8 @@ public class GLDrawableHelper { tdX = System.currentTimeMillis(); tdS = tdX - tdS; // swapBuffers } + } catch (final Throwable t) { + glEventListenerCaught = t; } finally { if( _releaseExclusiveThread ) { exclusiveContextSwitch = 0; @@ -1258,9 +1410,8 @@ public class GLDrawableHelper { try { context.release(); ctxReleased = true; - } catch (final Exception e) { - System.err.println("Caught exception on thread "+getThreadName()); - e.printStackTrace(); + } catch (final Throwable t) { + contextReleaseCaught = t; } } } @@ -1273,11 +1424,21 @@ public class GLDrawableHelper { lastInitAction.run(); } } + if( null != glEventListenerCaught ) { + flushGLRunnables(); + if( null != contextReleaseCaught ) { + GLException.dumpThrowable("subsequent", contextReleaseCaught); + } + throw GLException.newGLException(glEventListenerCaught); + } + if( null != contextReleaseCaught ) { + flushGLRunnables(); + throw GLException.newGLException(contextReleaseCaught); + } } final long td = System.currentTimeMillis() - t0; System.err.println("td0 "+td+"ms, fps "+(1.0/(td/1000.0))+", td-makeCurrent: "+tdA+"ms, td-render "+tdR+"ms, td-swap "+tdS+"ms, td-release "+tdX+"ms, ctx claimed: "+ctxClaimed+", ctx release: "+ctxReleased+", ctx destroyed "+ctxDestroyed); } protected static String getThreadName() { return Thread.currentThread().getName(); } - } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 3bb22612f..544aaf064 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -130,10 +130,11 @@ public abstract class GLDrawableImpl implements GLDrawable { } @Override - public GLCapabilitiesImmutable getChosenGLCapabilities() { + public final GLCapabilitiesImmutable getChosenGLCapabilities() { return (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); } + @Override public final GLCapabilitiesImmutable getRequestedGLCapabilities() { return requestedCapabilities; } diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 6046527d1..991a351e6 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -15,6 +15,7 @@ import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.VersionUtil; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.opengl.FBObject; +import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.FBObject.Attachment; import com.jogamp.opengl.FBObject.Colorbuffer; import com.jogamp.opengl.FBObject.TextureAttachment; @@ -44,13 +45,15 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { static { Debug.initSingleton(); DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); - DEBUG_SWAP = DEBUG || PropertyAccess.isPropertyDefined("jogl.debug.FBObject.Swap", true); + DEBUG_SWAP = PropertyAccess.isPropertyDefined("jogl.debug.FBObject.Swap", true); } private final GLDrawableImpl parent; private GLCapabilitiesImmutable origParentChosenCaps; private boolean initialized; + private int maxSamples; + private int fboModeBits; private int texUnit; private int samples; private boolean fboResetQuirk; @@ -59,9 +62,9 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { private int fboIBack; // points to GL_BACK buffer private int fboIFront; // points to GL_FRONT buffer private int pendingFBOReset = -1; - /** Indicated whether the FBO is bound. */ + /** Indicates whether the FBO is bound. */ private boolean fboBound; - /** Indicated whether the FBO is swapped, resets to false after makeCurrent -> contextMadeCurrent. */ + /** Indicates whether the FBO is swapped, resets to false after makeCurrent -> contextMadeCurrent. */ private boolean fboSwapped; /** dump fboResetQuirk info only once pre ClassLoader and only in DEBUG mode */ @@ -89,17 +92,79 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { final GLCapabilitiesImmutable fboCaps, final int textureUnit) { super(factory, surface, fboCaps, false); this.initialized = false; + this.fboModeBits = FBOMODE_USE_TEXTURE; this.parent = parent; this.origParentChosenCaps = getChosenGLCapabilities(); // just to avoid null, will be reset at initialize(..) this.texUnit = textureUnit; this.samples = fboCaps.getNumSamples(); - fboResetQuirk = false; + this.fboResetQuirk = false; + this.swapBufferContext = null; + } - // default .. // TODO: Add or remove TEXTURE (only) DoubleBufferMode support - // this.doubleBufferMode = ( samples > 0 || fboCaps.getDoubleBuffered() ) ? DoubleBufferMode.FBO : DoubleBufferMode.NONE ; + private final void setupFBO(final GL gl, final int idx, final int width, final int height, final int samples, + final boolean useAlpha, final int depthBits, final int stencilBits, + final boolean useTexture, final boolean realUnbind) { + final FBObject fbo = new FBObject(); + fbos[idx] = fbo; - this.swapBufferContext = null; + final boolean useDepth = depthBits > 0; + final boolean useStencil = stencilBits > 0; + + fbo.init(gl, width, height, samples); + if(fbo.getNumSamples() != samples) { + throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbo); + } + if(samples > 0 || !useTexture) { + fbo.attachColorbuffer(gl, 0, useAlpha); + } else { + fbo.attachTexture2D(gl, 0, useAlpha); + } + if( useStencil ) { + if( useDepth ) { + fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, depthBits); + } else { + fbo.attachRenderbuffer(gl, Attachment.Type.STENCIL, stencilBits); + } + } else if( useDepth ) { + fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, depthBits); + } + if(samples > 0) { + final FBObject ssink = new FBObject(); + { + ssink.init(gl, width, height, 0); + if( !useTexture ) { + ssink.attachColorbuffer(gl, 0, useAlpha); + } else { + ssink.attachTexture2D(gl, 0, useAlpha); + } + if( useStencil ) { + if( useDepth ) { + ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, depthBits); + } else { + ssink.attachRenderbuffer(gl, Attachment.Type.STENCIL, stencilBits); + } + } else if( useDepth ) { + ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, depthBits); + } + } + fbo.setSamplingSink(ssink); + fbo.resetSamplingSink(gl); // validate + } + // Clear the framebuffer allowing defined state not exposing previous content. + // Also remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting, + // otherwise first MSAA frame lacks antialiasing. + fbo.bind(gl); + if( useDepth ) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + } else { + gl.glClear(GL.GL_COLOR_BUFFER_BIT); + } + if( realUnbind ) { + fbo.unbind(gl); + } else { + fbo.markUnbound(); + } } private final void initialize(final boolean realize, final GL gl) { @@ -116,7 +181,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { if(realize) { final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true) - final int maxSamples = gl.getMaxRenderbufferSamples(); + maxSamples = gl.getMaxRenderbufferSamples(); // if > 0 implies fullFBOSupport { final int newSamples = samples <= maxSamples ? samples : maxSamples; if(DEBUG) { @@ -138,25 +203,21 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { fboIBack = 0; // head fboIFront = fbos.length - 1; // tail - for(int i=0; i<fbosN; i++) { - fbos[i] = new FBObject(); - fbos[i].reset(gl, getSurfaceWidth(), getSurfaceHeight(), samples, false); - if(fbos[i].getNumSamples() != samples) { - throw new InternalError("Sample number mismatch: "+samples+", fbos["+i+"] "+fbos[i]); - } - if(samples > 0) { - fbos[i].attachColorbuffer(gl, 0, chosenFBOCaps.getAlphaBits()>0); - } else { - fbos[i].attachTexture2D(gl, 0, chosenFBOCaps.getAlphaBits()>0); - } - if( chosenFBOCaps.getStencilBits() > 0 ) { - fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); - } else { - fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); - } + if( 0 == ( FBOMODE_USE_TEXTURE & fboModeBits ) && + gl.getContext().hasRendererQuirk(GLRendererQuirks.BuggyColorRenderbuffer) ) { + // GLRendererQuirks.BuggyColorRenderbuffer also disables MSAA, i.e. full FBO support + fboModeBits |= FBOMODE_USE_TEXTURE; } - fbos[fboIFront].resetSamplingSink(gl); + final boolean useTexture = 0 != ( FBOMODE_USE_TEXTURE & fboModeBits ); + final boolean useAlpha = chosenFBOCaps.getAlphaBits() > 0; + final int width = getSurfaceWidth(); + final int height = getSurfaceHeight(); + + for(int i=0; i<fbosN; i++) { + setupFBO(gl, i, width, height, samples, useAlpha, + chosenFBOCaps.getDepthBits(), chosenFBOCaps.getStencilBits(), useTexture, fbosN-1==i); + } fbos[0].formatToGLCapabilities(chosenFBOCaps); chosenFBOCaps.setDoubleBuffered( chosenFBOCaps.getDoubleBuffered() || samples > 0 ); } else { @@ -180,29 +241,26 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { swapBufferContext = sbc; } - private final void reset(final GL gl, final int idx, final int width, final int height, final int samples, final int alphaBits, final int stencilBits) { + private final void reset(final GL gl, final int idx, final int width, final int height, final int samples, + final boolean useAlpha, final int depthBits, final int stencilBits) { if( !fboResetQuirk ) { try { - fbos[idx].reset(gl, width, height, samples, false); + fbos[idx].reset(gl, width, height, samples); if(fbos[idx].getNumSamples() != samples) { throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]); } return; } catch (final GLException e) { fboResetQuirk = true; - if(DEBUG) { + if( DEBUG ) { if(!resetQuirkInfoDumped) { resetQuirkInfoDumped = true; System.err.println("GLFBODrawable: FBO Reset failed: "+e.getMessage()); System.err.println("GLFBODrawable: Enabling FBOResetQuirk, due to GL driver bug."); final JoglVersion joglVersion = JoglVersion.getInstance(); - if(DEBUG) { - System.err.println(VersionUtil.getPlatformInfo()); - System.err.println(joglVersion.toString()); - System.err.println(JoglVersion.getGLInfo(gl, null)); - } else { - System.err.println(joglVersion.getBriefOSGLBuildInfo(gl, null)); - } + System.err.println(VersionUtil.getPlatformInfo()); + System.err.println(joglVersion.toString()); + System.err.println(JoglVersion.getGLInfo(gl, null)); e.printStackTrace(); } } @@ -211,21 +269,8 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } // resetQuirk fallback fbos[idx].destroy(gl); - fbos[idx] = new FBObject(); - fbos[idx].reset(gl, getSurfaceWidth(), getSurfaceHeight(), samples, false); - if(fbos[idx].getNumSamples() != samples) { - throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]); - } - if(samples > 0) { - fbos[idx].attachColorbuffer(gl, 0, alphaBits>0); - } else { - fbos[idx].attachTexture2D(gl, 0, alphaBits>0); - } - if( stencilBits > 0 ) { - fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); - } else { - fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); - } + final boolean useTexture = 0 != ( FBOMODE_USE_TEXTURE & fboModeBits ); + setupFBO(gl, idx, width, height, samples, useAlpha, depthBits, stencilBits, useTexture, true); } private final void reset(final GL gl, int newSamples) throws GLException { @@ -248,7 +293,6 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { fboBound = false; // clear bound-flag immediatly, caused by contextMadeCurrent(..) - otherwise we would swap @ release fboSwapped = false; try { - final int maxSamples = gl.getMaxRenderbufferSamples(); newSamples = newSamples <= maxSamples ? newSamples : maxSamples; if(0==samples && 0<newSamples || 0<samples && 0==newSamples) { @@ -270,7 +314,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); for(int i=0; i<fbos.length; i++) { if( pendingFBOReset != i ) { - reset(gl, i, nWidth, nHeight, samples, caps.getAlphaBits(), caps.getStencilBits()); + reset(gl, i, nWidth, nHeight, samples, caps.getAlphaBits()>0, caps.getDepthBits(), caps.getStencilBits()); } } final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities(); @@ -289,10 +333,10 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } } if(null != tFBO) { - throw new GLException("GLFBODrawableImpl.reset(..) FBObject.reset(..) exception", tFBO); + throw GLException.newGLException(tFBO); } if(null != tGL) { - throw new GLException("GLFBODrawableImpl.reset(..) GLContext.release() exception", tGL); + throw GLException.newGLException(tGL); } if(DEBUG) { System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): END "+this); @@ -397,7 +441,8 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { // Safely reset the previous front FBO - after completing propagating swap if(0 <= pendingFBOReset) { final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); - reset(glc.getGL(), pendingFBOReset, getSurfaceWidth(), getSurfaceHeight(), samples, caps.getAlphaBits(), caps.getStencilBits()); + reset(glc.getGL(), pendingFBOReset, getSurfaceWidth(), getSurfaceHeight(), samples, + caps.getAlphaBits()>0, caps.getDepthBits(), caps.getStencilBits()); pendingFBOReset = -1; } } @@ -414,17 +459,16 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { fboIBack = ( fboIBack + 1 ) % fbos.length; final Colorbuffer colorbuffer = samples > 0 ? fbos[fboIFront].getSamplingSink() : fbos[fboIFront].getColorbuffer(0); + if(null == colorbuffer) { + throw new GLException("Front colorbuffer is null: samples "+samples+", "+this); + } final TextureAttachment texAttachment; - if(colorbuffer instanceof TextureAttachment) { - texAttachment = (TextureAttachment) colorbuffer; + if( colorbuffer.isTextureAttachment() ) { + texAttachment = colorbuffer.getTextureAttachment(); + gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit); } else { - if(null == colorbuffer) { - throw new GLException("Front colorbuffer is null: samples "+samples+", "+this); - } else { - throw new GLException("Front colorbuffer is not a texture: "+colorbuffer.getClass().getName()+": samples "+samples+", "+colorbuffer+", "+this); - } + texAttachment = null; } - gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit); fbos[fboIFront].use(gl, texAttachment); /* Included in above use command: @@ -447,6 +491,19 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } @Override + public final void setFBOMode(final int modeBits) throws IllegalStateException { + if( isInitialized() ) { + throw new IllegalStateException("Already initialized: "+this); + } + this.fboModeBits = modeBits; + } + + @Override + public final int getFBOMode() { + return fboModeBits; + } + + @Override public final void resetSize(final GL gl) throws GLException { reset(gl, samples); } @@ -468,9 +525,12 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } @Override - public final int setNumBuffers(final int bufferCount) throws GLException { + public final int setNumBuffers(final int bufferCount) throws IllegalStateException, GLException { + if( isInitialized() ) { + throw new IllegalStateException("Already initialized: "+this); + } // FIXME: Implement - return bufferCount; + return GLFBODrawableImpl.bufferCount; } @Override @@ -519,24 +579,24 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { } @Override - public final TextureAttachment getTextureBuffer(final int bufferName) throws IllegalArgumentException { + public final Colorbuffer getColorbuffer(final int bufferName) throws IllegalArgumentException { if(!initialized) { return null; } - final TextureAttachment res; + final Colorbuffer res; switch(bufferName) { case GL.GL_FRONT: if( samples > 0 ) { res = fbos[0].getSamplingSink(); } else { - res = (TextureAttachment) fbos[fboIFront].getColorbuffer(0); + res = fbos[fboIFront].getColorbuffer(0); } break; case GL.GL_BACK: if( samples > 0 ) { throw new IllegalArgumentException("Cannot access GL_BACK buffer of MSAA FBO: "+this); } else { - res = (TextureAttachment) fbos[fboIBack].getColorbuffer(0); + res = fbos[fboIBack].getColorbuffer(0); } break; default: diff --git a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java index 95c4ceb98..721dc7384 100644 --- a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java @@ -102,7 +102,7 @@ public class GLOffscreenAutoDrawableImpl extends GLAutoDrawableDelegate implemen } @Override - public final int setNumBuffers(final int bufferCount) throws GLException { + public final int setNumBuffers(final int bufferCount) throws /* IllegalStateException, */ GLException { return ((GLFBODrawableImpl)drawable).setNumBuffers(bufferCount); } @@ -128,13 +128,24 @@ public class GLOffscreenAutoDrawableImpl extends GLAutoDrawableDelegate implemen } @Override - public final FBObject.TextureAttachment getTextureBuffer(final int bufferName) { - return ((GLFBODrawableImpl)drawable).getTextureBuffer(bufferName); + public final FBObject.Colorbuffer getColorbuffer(final int bufferName) { + return ((GLFBODrawableImpl)drawable).getColorbuffer(bufferName); } @Override public void resetSize(final GL gl) throws GLException { ((GLFBODrawableImpl)drawable).resetSize(gl); } + + @Override + public final void setFBOMode(final int modeBits) throws IllegalStateException { + ((GLFBODrawableImpl)drawable).setFBOMode(modeBits); + + } + + @Override + public final int getFBOMode() { + return ((GLFBODrawableImpl)drawable).getFBOMode(); + } } } diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java index 0ceef6bf7..ca1c1869e 100644 --- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java +++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java @@ -90,8 +90,10 @@ public class GLRunnableTask implements GLRunnable { /** * Simply flush this task and notify a waiting executor. + * <p> * The executor which might have been blocked until notified * will be unblocked and the task removed from the queue. + * </p> * * @see #isFlushed() * @see #isInQueue() diff --git a/src/jogl/classes/jogamp/opengl/GLStateTracker.java b/src/jogl/classes/jogamp/opengl/GLStateTracker.java index d532a2567..dc49b35f4 100644 --- a/src/jogl/classes/jogamp/opengl/GLStateTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLStateTracker.java @@ -68,7 +68,7 @@ public class GLStateTracker { private IntIntHashMap pixelStateMap; private final ArrayList<SavedState> stack; - private static class SavedState { + static class SavedState { /** * Empty pixel-store state @@ -78,15 +78,14 @@ public class GLStateTracker { /** * set (client) pixel-store state, deep copy */ - private final void setPixelStateMap(final IntIntHashMap pixelStateMap) { + final void setPixelStateMap(final IntIntHashMap pixelStateMap) { this.pixelStateMap = (IntIntHashMap) pixelStateMap.clone(); } /** * get (client) pixel-store state, return reference */ - private final IntIntHashMap getPixelStateMap() { return pixelStateMap; } - + final IntIntHashMap getPixelStateMap() { return pixelStateMap; } } @@ -163,10 +162,11 @@ public class GLStateTracker { if(null==state) { throw new GLException("null stack element (remaining stack size "+stack.size()+")"); } + final IntIntHashMap statePixelStateMap = state.getPixelStateMap(); - if ( null != state.getPixelStateMap() ) { + if ( null != statePixelStateMap ) { // use pulled client pixel-store state from stack - pixelStateMap = state.getPixelStateMap(); + pixelStateMap = statePixelStateMap; } // else: empty-slot, not pushed by GL_CLIENT_PIXEL_STORE_BIT } } diff --git a/src/jogl/classes/jogamp/opengl/ThreadingImpl.java b/src/jogl/classes/jogamp/opengl/ThreadingImpl.java index 2b017e8e9..7b405e524 100644 --- a/src/jogl/classes/jogamp/opengl/ThreadingImpl.java +++ b/src/jogl/classes/jogamp/opengl/ThreadingImpl.java @@ -41,6 +41,7 @@ import java.security.PrivilegedAction; import javax.media.nativewindow.NativeWindowFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import javax.media.opengl.Threading.Mode; import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.PropertyAccess; @@ -49,16 +50,6 @@ import com.jogamp.common.util.ReflectionUtil; /** Implementation of the {@link javax.media.opengl.Threading} class. */ public class ThreadingImpl { - public enum Mode { - MT(0), ST_AWT(1), ST_WORKER(2); - - public final int id; - - Mode(final int id){ - this.id = id; - } - } - protected static final boolean DEBUG = Debug.debug("Threading"); private static boolean singleThreaded; @@ -93,28 +84,23 @@ public class ThreadingImpl { _isX11 = NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false); - // default setting - singleThreaded = true; - mode = ( hasAWT ? Mode.ST_AWT : Mode.ST_WORKER ); - if (singleThreadProp != null) { if (singleThreadProp.equals("true") || singleThreadProp.equals("auto")) { - singleThreaded = true; - mode = ( hasAWT ? Mode.ST_AWT : Mode.ST_WORKER ); + mode = ( hasAWT ? Mode.ST_AWT : Mode.MT ); } else if (singleThreadProp.equals("worker")) { - singleThreaded = true; mode = Mode.ST_WORKER; } else if (hasAWT && singleThreadProp.equals("awt")) { - singleThreaded = true; mode = Mode.ST_AWT; } else if (singleThreadProp.equals("false")) { - singleThreaded = false; mode = Mode.MT; } else { throw new RuntimeException("Unsupported value for property jogl.1thread: "+singleThreadProp+", should be [true/auto, worker, awt or false]"); } + } else { + mode = ( hasAWT ? Mode.ST_AWT : Mode.MT ); } + singleThreaded = Mode.MT != mode; ToolkitThreadingPlugin threadingPlugin=null; if(hasAWT) { @@ -155,9 +141,11 @@ public class ThreadingImpl { method. This method should be called as early as possible in an application. */ public static final void disableSingleThreading() { - singleThreaded = false; - if (Debug.verbose()) { - System.err.println("Application forced disabling of single-threading of javax.media.opengl implementation"); + if( Mode.MT != mode ) { + singleThreaded = false; + if (Debug.verbose()) { + System.err.println("Application forced disabling of single-threading of javax.media.opengl implementation"); + } } } @@ -167,22 +155,28 @@ public class ThreadingImpl { return singleThreaded; } - /** Indicates whether the current thread is the single thread on - which this implementation of the javax.media.opengl APIs - performs all of its OpenGL-related work. This method should only - be called if the single-thread model is in effect. */ + /** + * Indicates whether the current thread is capable of + * performing OpenGL-related work. + * <p> + * Method always returns <code>true</code> + * if {@link #getMode()} == {@link Mode#MT} or {@link #isSingleThreaded()} == <code>false</code>. + * </p> + */ public static final boolean isOpenGLThread() throws GLException { - if(null!=threadingPlugin) { + if( Mode.MT == mode || !singleThreaded ) { + return true; + } else if( null != threadingPlugin ) { return threadingPlugin.isOpenGLThread(); - } - - switch (mode) { - case ST_AWT: - throw new InternalError(); - case ST_WORKER: - return GLWorkerThread.isWorkerThread(); - default: - throw new InternalError("Illegal single-threading mode " + mode); + } else { + switch (mode) { + case ST_AWT: + throw new InternalError(); + case ST_WORKER: + return GLWorkerThread.isWorkerThread(); + default: + throw new InternalError("Illegal single-threading mode " + mode); + } } } @@ -213,6 +207,10 @@ public class ThreadingImpl { invokeOnWorkerThread(wait, r); break; + case MT: + r.run(); + break; + default: throw new InternalError("Illegal single-threading mode " + mode); } diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java index 24b89cd02..495887e0f 100644 --- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java +++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java @@ -254,7 +254,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { @Override protected final void initStreamImpl(final int vid, final int aid) throws IOException { - if( null == getURI() ) { + if( null == getUri() ) { return; } if( null == mp && null == cam ) { @@ -263,7 +263,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } else { int cameraId = 0; try { - cameraId = Integer.parseInt(cameraPath); + cameraId = Integer.parseInt(cameraPath.decode()); } catch (final NumberFormatException nfe) {} if( 0 <= cameraId && cameraId < Camera.getNumberOfCameras() ) { cam = Camera.open(cameraId); @@ -280,7 +280,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } // else FIXME: Select aid ! // Note: Both FIXMEs seem to be n/a via Android's MediaPlayer -> Switch to API level 16 MediaCodec/MediaExtractor .. try { - final Uri _uri = Uri.parse(getURI().toString()); + final Uri _uri = Uri.parse(getUri().toString()); mp.setDataSource(StaticContext.getContext(), _uri); } catch (final IllegalArgumentException e) { throw new RuntimeException(e); @@ -293,7 +293,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { try { mp.prepare(); } catch (final IOException ioe) { - throw new IOException("MediaPlayer failed to process stream <"+getURI().toString()+">: "+ioe.getMessage(), ioe); + throw new IOException("MediaPlayer failed to process stream <"+getUri().toString()+">: "+ioe.getMessage(), ioe); } final int r_aid = GLMediaPlayer.STREAM_ID_NONE == aid ? GLMediaPlayer.STREAM_ID_NONE : 1 /* fake */; final String icodec = "android"; @@ -381,7 +381,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { cam.setPreviewTexture(sTexFrame.surfaceTex); cam.startPreview(); } catch (final IOException ioe) { - throw new RuntimeException("MediaPlayer failed to process stream <"+getURI().toString()+">: "+ioe.getMessage(), ioe); + throw new RuntimeException("MediaPlayer failed to process stream <"+getUri().toString()+">: "+ioe.getMessage(), ioe); } } if( null != surface ) { diff --git a/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java b/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java index 26ec62785..3f8910fb5 100644 --- a/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java +++ b/src/jogl/classes/jogamp/opengl/awt/AWTThreadingPlugin.java @@ -108,6 +108,10 @@ public class AWTThreadingPlugin implements ToolkitThreadingPlugin { ThreadingImpl.invokeOnWorkerThread(wait, r); break; + case MT: + r.run(); + break; + default: throw new InternalError("Illegal single-threading mode " + ThreadingImpl.getMode()); } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 5a9a30313..2edb22314 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -184,7 +184,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } } if( null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper ) { - if(isANGLE && !enableANGLE) { + if(isANGLE && !GLProfile.enableANGLE) { if(DEBUG || GLProfile.DEBUG) { System.err.println("Info: EGLDrawableFactory.init - EGL/ES2 ANGLE disabled"); } diff --git a/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java b/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java index 9ff6bd637..51d8ca6fe 100644 --- a/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java +++ b/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java @@ -49,6 +49,7 @@ import javax.media.opengl.GL2; import javax.media.opengl.GL2ES2; import javax.media.opengl.GL2ES3; import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLContext; import javax.media.opengl.glu.GLU; import javax.media.opengl.GLException; @@ -255,8 +256,8 @@ public class Mipmap { */ public static void closestFit( final GL gl, final int target, final int width, final int height, final int internalFormat, final int format, final int type, final int[] newWidth, final int[] newHeight ) { - // Use proxy textures if OpenGL version >= 1.1 - if( Double.parseDouble( gl.glGetString( GL.GL_VERSION ).trim().substring( 0, 3 ) ) >= 1.1 ) { + // Use proxy textures if OpenGL GL2/GL3 version >= 1.1 + if( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version110) >= 0 ) { int widthPowerOf2 = nearestPower( width ); int heightPowerOf2 = nearestPower( height ); final int[] proxyWidth = new int[1]; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index dbca7c2e8..7066a6db5 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -828,7 +828,7 @@ public class MacOSXCGLContext extends GLContextImpl final long drawableHandle = drawable.getHandle(); if(drawable instanceof GLFBODrawableImpl) { final GLFBODrawableImpl fbod = (GLFBODrawableImpl)drawable; - texID = fbod.getTextureBuffer(GL.GL_FRONT).getName(); + texID = fbod.getColorbuffer(GL.GL_FRONT).getName(); pbufferHandle = 0; fbod.setSwapBufferContext(new GLFBODrawableImpl.SwapBufferContext() { @Override @@ -1043,7 +1043,7 @@ public class MacOSXCGLContext extends GLContextImpl final boolean valid; final boolean isFBO = drawable instanceof GLFBODrawableImpl; if( isFBO ){ - texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName(); + texID = ((GLFBODrawableImpl)drawable).getColorbuffer(GL.GL_FRONT).getName(); valid = 0 != texID; } else { texID = 0; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 7c05b8eab..045abca4c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -42,6 +42,7 @@ package jogamp.opengl.macosx.cgl; import java.nio.Buffer; import java.nio.FloatBuffer; +import java.nio.ShortBuffer; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -404,24 +405,29 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { /** Returns the length of the computed gamma ramp for this OS and hardware. Returns 0 if gamma changes are not supported. */ @Override - protected int getGammaRampLength() { + protected int getGammaRampLength(final NativeSurface surface) { return GAMMA_RAMP_LENGTH; } @Override - protected boolean setGammaRamp(final float[] ramp) { + protected boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { final FloatBuffer rampNIO = Buffers.newDirectFloatBuffer(ramp); - return CGL.setGammaRamp(ramp.length, rampNIO, rampNIO, rampNIO); } @Override - protected Buffer getGammaRamp() { - return null; + protected Buffer getGammaRamp(final NativeSurface surface) { + return ShortBuffer.allocate(0); // return a dummy gamma ramp default for reset } @Override - protected void resetGammaRamp(final Buffer originalGammaRamp) { + protected void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { CGL.resetGammaRamp(); } + + @Override + protected final void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { + CGL.resetGammaRamp(); + } + } diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java index 05e192bbc..0969199c6 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java +++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java @@ -28,7 +28,6 @@ package jogamp.opengl.util.av; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -46,7 +45,8 @@ import javax.media.opengl.GLProfile; import jogamp.opengl.Debug; -import com.jogamp.common.net.URIQueryProps; +import com.jogamp.common.net.UriQueryProps; +import com.jogamp.common.net.Uri; import com.jogamp.common.os.Platform; import com.jogamp.common.util.LFRingbuffer; import com.jogamp.common.util.Ringbuffer; @@ -92,15 +92,15 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { private final int[] texWrapST = { GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE }; /** User requested URI stream location. */ - private URI streamLoc = null; + private Uri streamLoc = null; /** * In case {@link #streamLoc} is a {@link GLMediaPlayer#CameraInputScheme}, * {@link #cameraPath} holds the URI's path portion - * as parsed in {@link #initStream(URI, int, int, int)}. + * as parsed in {@link #initStream(Uri, int, int, int)}. * @see #cameraProps */ - protected String cameraPath = null; + protected Uri.Encoded cameraPath = null; /** Optional camera properties, see {@link #cameraPath}. */ protected Map<String, String> cameraProps = null; @@ -530,7 +530,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } @Override - public final void initStream(final URI streamLoc, final int vid, final int aid, final int reqTextureCount) throws IllegalStateException, IllegalArgumentException { + public final void initStream(final Uri streamLoc, final int vid, final int aid, final int reqTextureCount) throws IllegalStateException, IllegalArgumentException { synchronized( stateLock ) { if(State.Uninitialized != state) { throw new IllegalStateException("Instance not in state unintialized: "+this); @@ -556,13 +556,13 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { // Pre-parse for camera-input scheme cameraPath = null; cameraProps = null; - final String streamLocScheme = streamLoc.getScheme(); + final Uri.Encoded streamLocScheme = streamLoc.scheme; if( null != streamLocScheme && streamLocScheme.equals(CameraInputScheme) ) { - final String rawPath = streamLoc.getRawPath(); + final Uri.Encoded rawPath = streamLoc.path; if( null != rawPath && rawPath.length() > 0 ) { // cut-off root fwd-slash cameraPath = rawPath.substring(1); - final URIQueryProps props = URIQueryProps.create(streamLoc, ';'); + final UriQueryProps props = UriQueryProps.create(streamLoc, ';'); cameraProps = props.getProperties(); } else { throw new IllegalArgumentException("Camera path is empty: "+streamLoc.toString()); @@ -1472,7 +1472,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } @Override - public final URI getURI() { return streamLoc; } + public final Uri getUri() { return streamLoc; } @Override public final int getVID() { return vid; } diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index 8ac1232b5..4601df67d 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -37,7 +37,6 @@ import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLException; -import com.jogamp.common.os.Platform; import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; @@ -292,7 +291,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { System.err.println("initStream: p1 "+this); } - final String streamLocS = IOUtil.decodeURIIfFilePath(getURI()); + final String streamLocS = IOUtil.getUriFilePathOrASCII(getUri()); destroyAudioSink(); if( GLMediaPlayer.STREAM_ID_NONE == aid ) { audioSink = AudioSinkFactory.createNull(); @@ -317,10 +316,10 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { case HPUX: case LINUX: case SUNOS: - resStreamLocS = dev_video_linux + cameraPath; + resStreamLocS = dev_video_linux + cameraPath.decode(); break; case WINDOWS: - resStreamLocS = cameraPath; + resStreamLocS = cameraPath.decode(); break; case MACOS: case OPENKODE: @@ -345,7 +344,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { // setStream(..) issues updateAttributes*(..), and defines avChosenAudioFormat, vid, aid, .. etc if(DEBUG) { System.err.println("initStream: p3 cameraPath "+cameraPath+", isCameraInput "+isCameraInput); - System.err.println("initStream: p3 stream "+getURI()+" -> "+streamLocS+" -> "+resStreamLocS); + System.err.println("initStream: p3 stream "+getUri()+" -> "+streamLocS+" -> "+resStreamLocS); System.err.println("initStream: p3 vid "+vid+", sizes "+sizes+", reqVideo "+rw+"x"+rh+"@"+rr+", aid "+aid+", aMaxChannelCount "+aMaxChannelCount+", aPrefSampleRate "+aPrefSampleRate); } natives.setStream0(moviePtr, resStreamLocS, isCameraInput, vid, sizes, rw, rh, rr, aid, aMaxChannelCount, aPrefSampleRate); diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java index 0eeb54bf6..5baf9e543 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java @@ -100,10 +100,10 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { if(0==moviePtr) { throw new GLException("OMX native instance null"); } - if(!getURI().getScheme().equals("file")) { - throw new IOException("Only file schemes are allowed: "+getURI()); + if( !getUri().isFileScheme() ) { + throw new IOException("Only file schemes are allowed: "+getUri()); } - final String path=getURI().getPath(); + final String path=getUri().path.decode(); if(DEBUG) { System.out.println("initGLStream: clean path "+path); } diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java index a9848f899..2dde27b1d 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java +++ b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java @@ -36,6 +36,7 @@ import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLArrayData; import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; import javax.media.opengl.fixedfunc.GLLightingFunc; import javax.media.opengl.fixedfunc.GLMatrixFunc; import javax.media.opengl.fixedfunc.GLPointerFunc; @@ -50,6 +51,7 @@ import com.jogamp.opengl.util.glsl.fixedfunc.ShaderSelectionMode; public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFunc { public static final int MAX_TEXTURE_UNITS = 8; + protected final GLProfile gl2es1GLProfile; protected FixedFuncPipeline fixedFunction; protected PMVMatrix pmvMatrix; protected boolean ownsPMVMatrix; @@ -61,6 +63,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun * @param pmvMatrix optional pass through PMVMatrix for the {@link FixedFuncHook} and {@link FixedFuncPipeline} */ public FixedFuncHook (final GL2ES2 gl, final ShaderSelectionMode mode, final PMVMatrix pmvMatrix) { + this.gl2es1GLProfile = GLProfile.createCustomGLProfile(GLProfile.GL2ES1, gl.getGLProfile().getImpl()); this.gl = gl; if(null != pmvMatrix) { this.ownsPMVMatrix = false; @@ -81,6 +84,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun final Class<?> shaderRootClass, final String shaderSrcRoot, final String shaderBinRoot, final String vertexColorFile, final String vertexColorLightFile, final String fragmentColorFile, final String fragmentColorTextureFile) { + this.gl2es1GLProfile = GLProfile.createCustomGLProfile(GLProfile.GL2ES1, gl.getGLProfile().getImpl()); this.gl = gl; if(null != pmvMatrix) { this.ownsPMVMatrix = false; @@ -110,6 +114,24 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun // // FixedFuncHookIf - hooks // + public final boolean isGL4core() { + return false; + } + public final boolean isGL3core() { + return false; + } + public final boolean isGLcore() { + return false; + } + public final boolean isGLES2Compatible() { + return false; + } + public final boolean isGLES3Compatible() { + return false; + } + public final GLProfile getGLProfile() { + return gl2es1GLProfile; + } public void glDrawArrays(final int mode, final int first, final int count) { fixedFunction.glDrawArrays(gl, mode, first, count); } diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java index 30559924d..36e8bc5a5 100644 --- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java +++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java @@ -41,6 +41,7 @@ import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.FovHVHalves; import com.jogamp.opengl.util.stereo.EyeParameter; import com.jogamp.opengl.util.stereo.StereoDevice; +import com.jogamp.opengl.util.stereo.StereoDeviceFactory; import com.jogamp.opengl.util.stereo.StereoDeviceRenderer; import com.jogamp.opengl.util.stereo.StereoUtil; @@ -207,16 +208,20 @@ public class GenericStereoDevice implements StereoDevice { final float[] DEFAULT_EYE_POSITION_OFFSET_STEREO = { 0.0f, 0.3f, 3.0f }; // 0.3 up, 3 back final float[] DEFAULT_EYE_POSITION_OFFSET_MONO = { 0.0f, 0.0f, 3.0f }; // 3 back + final DimensionImmutable surfaceSizeInPixel = new Dimension(1280, 800); + final float[] screenSizeInMeters = new float[] { 0.1498f, 0.0936f }; + final float interpupillaryDistanceInMeters = 0.0635f; + final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f; final float d2r = FloatUtil.PI / 180.0f; { config01Mono01 = new Config( "Def01Mono01", ShutterType.RollingTopToBottom, - new Dimension(1280, 800), // resolution - new float[] { 0.1498f, 0.0936f }, // screenSize [m] - new Dimension(1280, 800), // eye textureSize - 0.0936f/2f, // pupilCenterFromScreenTop [m] - 0.0635f, // IPD [m] + surfaceSizeInPixel, // resolution + screenSizeInMeters, // screenSize [m] + surfaceSizeInPixel, // eye textureSize + pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m] + interpupillaryDistanceInMeters, // IPD [m] new int[] { 0 }, // eye order new EyeParameter[] { new EyeParameter(0, DEFAULT_EYE_POSITION_OFFSET_MONO, @@ -231,11 +236,7 @@ public class GenericStereoDevice implements StereoDevice { } { - final DimensionImmutable surfaceSizeInPixel = new Dimension(1280, 800); - final float[] screenSizeInMeters = new float[] { 0.1498f, 0.0936f }; final DimensionImmutable eyeTextureSize = new Dimension(surfaceSizeInPixel.getWidth()/2, surfaceSizeInPixel.getHeight()); - final float interpupillaryDistanceInMeters = 0.0635f; - final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f; final float[] horizPupilCenterFromLeft = Config.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters); final float vertPupilCenterFromTop = Config.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters); final float fovy = 45f; @@ -249,7 +250,7 @@ public class GenericStereoDevice implements StereoDevice { surfaceSizeInPixel, // resolution screenSizeInMeters, // screenSize [m] eyeTextureSize, // eye textureSize - 0.0936f/2f, // pupilCenterFromScreenTop [m] + pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m] interpupillaryDistanceInMeters, // IPD [m] new int[] { 0, 1 }, // eye order new EyeParameter[] { @@ -274,11 +275,7 @@ public class GenericStereoDevice implements StereoDevice { if(StereoDevice.DEBUG) { System.err.println("Caught: "+t.getMessage()); t.printStackTrace(); } } - final DimensionImmutable surfaceSizeInPixel = new Dimension(1280, 800); - final float[] screenSizeInMeters = new float[] { 0.1498f, 0.0936f }; final DimensionImmutable eyeTextureSize = new Dimension(1122, 1553); - final float interpupillaryDistanceInMeters = 0.0635f; - final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f; final float[] horizPupilCenterFromLeft = Config.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters); final float vertPupilCenterFromTop = Config.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters); final float fovy = 129f; @@ -313,6 +310,7 @@ public class GenericStereoDevice implements StereoDevice { configs = new Config[] { config01Mono01, config02StereoSBS01, config03StereoSBSLense01 }; } + private final StereoDeviceFactory factory; public final int deviceIndex; public final Config config; @@ -321,7 +319,8 @@ public class GenericStereoDevice implements StereoDevice { private boolean sensorsStarted = false; - public GenericStereoDevice(final int deviceIndex, final StereoDevice.Config customConfig) { + public GenericStereoDevice(final StereoDeviceFactory factory, final int deviceIndex, final StereoDevice.Config customConfig) { + this.factory = factory; this.deviceIndex = deviceIndex; if( customConfig instanceof GenericStereoDevice.Config) { @@ -341,6 +340,9 @@ public class GenericStereoDevice implements StereoDevice { } @Override + public final StereoDeviceFactory getFactory() { return factory; } + + @Override public String toString() { return "GenericStereoDevice["+config+", surfacePos "+surfacePos+"]"; } @@ -431,26 +433,34 @@ public class GenericStereoDevice implements StereoDevice { defaultEyeParam.distNoseToPupilX, defaultEyeParam.distMiddleToPupilY, defaultEyeParam.eyeReliefZ); } + final boolean usePP = null != config.distortionMeshProducer && 0 != distortionBits; // use post-processing + final RectangleImmutable[] eyeViewports = new RectangleImmutable[eyeParam.length]; final DimensionImmutable eyeTextureSize = config.eyeTextureSize; final DimensionImmutable totalTextureSize; if( 1 < eyeParam.length ) { // Stereo SBS totalTextureSize = new Dimension(eyeTextureSize.getWidth()*2, eyeTextureSize.getHeight()); + if( 1 == textureCount ) { // validated in ctor below! eyeViewports[0] = new Rectangle(0, 0, - totalTextureSize.getWidth() / 2, totalTextureSize.getHeight()); + eyeTextureSize.getWidth(), eyeTextureSize.getHeight()); - eyeViewports[1] = new Rectangle((totalTextureSize.getWidth() + 1) / 2, 0, - totalTextureSize.getWidth() / 2, totalTextureSize.getHeight()); + eyeViewports[1] = new Rectangle(eyeTextureSize.getWidth(), 0, + eyeTextureSize.getWidth(), eyeTextureSize.getHeight()); } else { eyeViewports[0] = new Rectangle(0, 0, eyeTextureSize.getWidth(), eyeTextureSize.getHeight()); - eyeViewports[1] = eyeViewports[0]; + if( usePP ) { + eyeViewports[1] = eyeViewports[0]; + } else { + eyeViewports[1] = new Rectangle(eyeTextureSize.getWidth(), 0, + eyeTextureSize.getWidth(), eyeTextureSize.getHeight()); + } } } else { // Mono totalTextureSize = eyeTextureSize; - eyeViewports[0] = new Rectangle(0, 0, totalTextureSize.getWidth(), totalTextureSize.getHeight()); + eyeViewports[0] = new Rectangle(0, 0, eyeTextureSize.getWidth(), eyeTextureSize.getHeight()); } return new GenericStereoDeviceRenderer(this, distortionBits, textureCount, eyePositionOffset, eyeParam, pixelsPerDisplayPixel, textureUnit, eyeTextureSize, totalTextureSize, eyeViewports); diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java index a59e8d833..f2fa74743 100644 --- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java +++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java @@ -38,6 +38,6 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory { @Override public final StereoDevice createDevice(final int deviceIndex, final StereoDevice.Config config, final boolean verbose) { - return new GenericStereoDevice(deviceIndex, config); + return new GenericStereoDevice(this, deviceIndex, config); } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index 9c5a5b272..33980d663 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -51,6 +51,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLProfile; import com.jogamp.common.nio.Buffers; import com.jogamp.gluegen.runtime.ProcAddressTable; @@ -330,7 +331,7 @@ public class WindowsWGLContext extends GLContextImpl { isProcCreateContextAttribsARBAvailable = false; isExtARBCreateContextAvailable = false; } - if ( isProcCreateContextAttribsARBAvailable && isExtARBCreateContextAvailable ) { + if ( isProcCreateContextAttribsARBAvailable && isExtARBCreateContextAvailable && !GLProfile.disableOpenGLARBContext ) { // initial ARB context creation contextHandle = createContextARB(shareWithHandle, true); createContextARBTried=true; @@ -343,7 +344,9 @@ public class WindowsWGLContext extends GLContextImpl { } } else if (DEBUG) { System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - extension not available - share "+toHexString(shareWithHandle)+ - ", isProcCreateContextAttribsARBAvailable "+isProcCreateContextAttribsARBAvailable+", isExtGLXARBCreateContextAvailable "+isExtARBCreateContextAvailable); + ", isProcCreateContextAttribsARBAvailable "+isProcCreateContextAttribsARBAvailable+ + ", isExtGLXARBCreateContextAvailable "+isExtARBCreateContextAvailable+ + ", disableOpenGLARBContext "+GLProfile.disableOpenGLARBContext); } } } else { @@ -360,16 +363,18 @@ public class WindowsWGLContext extends GLContextImpl { } } } else { - if( glCaps.getGLProfile().isGL3() ) { - WGL.wglMakeCurrent(0, 0); - WGL.wglDeleteContext(temp_ctx); - throw new GLException(getThreadName()+": WindowsWGLContex.createContextImpl ctx !ARB, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glCaps.getGLProfile()+", current: "+getGLVersion()); + if( glCaps.getGLProfile().isGL3() && createContextARBTried ) { + // We shall not allow context creation >= GL3 w/ non ARB methods if ARB is used, + // otherwise context of similar profile but different creation method may not be share-able. + WGL.wglMakeCurrent(0, 0); + WGL.wglDeleteContext(temp_ctx); + throw new GLException(getThreadName()+": WindowsWGLContex.createContextImpl ctx !ARB but ARB is used, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glCaps.getGLProfile()+", current: "+getGLVersion()); } if(DEBUG) { - System.err.println("WindowsWGLContext.createContext failed, fall back to !ARB context "+getGLVersion()); + System.err.println("WindowsWGLContext.createContext ARB not used, fall back to !ARB context "+getGLVersion()); } - // continue with temp context for GL < 3.0 + // continue with temp context contextHandle = temp_ctx; if ( !wglMakeContextCurrent(drawable.getHandle(), drawableRead.getHandle(), contextHandle) ) { WGL.wglMakeCurrent(0, 0); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 4d8c85137..fa052d784 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -68,6 +68,7 @@ import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.GDIDummyUpstreamSurfaceHook; import jogamp.nativewindow.windows.GDISurface; import jogamp.nativewindow.windows.RegisteredClassFactory; +import jogamp.opengl.Debug; import jogamp.opengl.DesktopGLDynamicLookupHelper; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -77,17 +78,80 @@ import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.GLRendererQuirks; public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { + /** + * Bug 1036: NVidia Windows Driver 'Threaded optimization' workaround. + * <p> + * https://jogamp.org/bugzilla/show_bug.cgi?id=1036 + * </p> + * <p> + * Since NV driver 260.99 from 2010-12-11 a 'Threaded optimization' feature has been introduced. + * The driver spawns off a dedicated thread to off-load certain OpenGL tasks from the calling thread + * to perform them async and off-thread. + * </p> + * <p> + * If 'Threaded optimization' is manually enabled 'on', the driver may crash with JOGL's consistent + * multi-threaded usage - this is a driver bug. + * </p> + * <p> + * If 'Threaded optimization' is manually disabled 'off', the driver always works correctly. + * </p> + * <p> + * 'Threaded optimization' default setting is 'auto' and the driver may crash without this workaround. + * </p> + * <p> + * If setting the process affinity to '1' (1st CPU) while initialization and launching + * the {@link SharedResourceRunner}, the driver does not crash anymore in 'auto' mode. + * This might be either because the driver does not enable 'Threaded optimization' + * or because the driver's worker thread is bound to the same CPU. + * </p> + * <p> + * Property integer value <code>jogl.windows.cpu_affinity_mode</code>: + * <ul> + * <li>0 - none (no affinity, may cause driver crash with 'Threaded optimization' = ['auto', 'on'])</li> + * <li>1 - process affinity (default, workaround for driver crash for 'Threaded optimization' = 'auto', still crashes if set to 'on')</li> + * </ul> + * </p> + * <p> + * Test case reproducing the crash reliable is: com.jogamp.opengl.test.junit.jogl.caps.TestTranslucencyNEWT<br> + * (don't ask why ..) + * </p> + */ + private static final int CPU_AFFINITY_MODE; + + static { + Debug.initSingleton(); + CPU_AFFINITY_MODE = PropertyAccess.getIntProperty("jogl.windows.cpu_affinity_mode", true, 1); + } + private static DesktopGLDynamicLookupHelper windowsWGLDynamicLookupHelper = null; + private final CPUAffinity cpuAffinity; + public WindowsWGLDrawableFactory() { super(); + switch( CPU_AFFINITY_MODE ) { + case 0: + cpuAffinity = new NopCPUAffinity(); + break; + /** + * Doesn't work ! + case 2: + cpuAffinity = new WindowsThreadAffinity(); + break; + */ + default: + cpuAffinity = new WindowsProcessAffinity(); + break; + } + synchronized(WindowsWGLDrawableFactory.class) { if( null == windowsWGLDynamicLookupHelper ) { windowsWGLDynamicLookupHelper = AccessController.doPrivileged(new PrivilegedAction<DesktopGLDynamicLookupHelper>() { @@ -168,45 +232,23 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { return windowsWGLDynamicLookupHelper; } + /* pp */ static String toHexString(final long l) { return "0x"+Long.toHexString(l); } + private WindowsGraphicsDevice defaultDevice; private SharedResourceRunner sharedResourceRunner; private HashMap<String /*connection*/, SharedResourceRunner.Resource> sharedMap; - private long processAffinityChanges = 0; - private final PointerBuffer procMask = PointerBuffer.allocateDirect(1); - private final PointerBuffer sysMask = PointerBuffer.allocateDirect(1); - @Override protected void enterThreadCriticalZone() { - synchronized (sysMask) { - if( 0 == processAffinityChanges) { - final long pid = GDI.GetCurrentProcess(); - if ( GDI.GetProcessAffinityMask(pid, procMask, sysMask) ) { - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.enterThreadCriticalZone() - 0x" + Long.toHexString(pid) + " - " + getThreadName()); - // Thread.dumpStack(); - } - processAffinityChanges = pid; - GDI.SetProcessAffinityMask(pid, 1); - } - } + synchronized (cpuAffinity) { + cpuAffinity.set(1); } } @Override protected void leaveThreadCriticalZone() { - synchronized (sysMask) { - if( 0 != processAffinityChanges) { - final long pid = GDI.GetCurrentProcess(); - if( pid != processAffinityChanges) { - throw new GLException("PID doesn't match: set PID 0x" + Long.toHexString(processAffinityChanges) + - " this PID 0x" + Long.toHexString(pid) ); - } - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.leaveThreadCriticalZone() - 0x" + Long.toHexString(pid) + " - " + getThreadName()); - } - GDI.SetProcessAffinityMask(pid, sysMask.get(0)); - } + synchronized (cpuAffinity) { + cpuAffinity.reset(); } } @@ -344,6 +386,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { if (null != sr.context) { // may cause JVM SIGSEGV: sharedContext.destroy(); + sr.context.destroy(); // will also pull the dummy MutableSurface sr.context = null; } @@ -556,12 +599,12 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { private static final int GAMMA_RAMP_LENGTH = 256; @Override - protected final int getGammaRampLength() { + protected final int getGammaRampLength(final NativeSurface surface) { return GAMMA_RAMP_LENGTH; } @Override - protected final boolean setGammaRamp(final float[] ramp) { + protected final boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { final short[] rampData = new short[3 * GAMMA_RAMP_LENGTH]; for (int i = 0; i < GAMMA_RAMP_LENGTH; i++) { final short scaledValue = (short) (ramp[i] * 65535); @@ -570,18 +613,26 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { rampData[i + 2 * GAMMA_RAMP_LENGTH] = scaledValue; } - final long screenDC = GDI.GetDC(0); - final boolean res = GDI.SetDeviceGammaRamp(screenDC, ShortBuffer.wrap(rampData)); - GDI.ReleaseDC(0, screenDC); + final long hDC = surface.getSurfaceHandle(); + if( 0 == hDC ) { + return false; + } + // final long screenDC = GDI.GetDC(0); + final boolean res = GDI.SetDeviceGammaRamp(hDC, ShortBuffer.wrap(rampData)); + // GDI.ReleaseDC(0, screenDC); return res; } @Override - protected final Buffer getGammaRamp() { + protected final Buffer getGammaRamp(final NativeSurface surface) { final ShortBuffer rampData = ShortBuffer.wrap(new short[3 * GAMMA_RAMP_LENGTH]); - final long screenDC = GDI.GetDC(0); - final boolean res = GDI.GetDeviceGammaRamp(screenDC, rampData); - GDI.ReleaseDC(0, screenDC); + final long hDC = surface.getSurfaceHandle(); + if( 0 == hDC ) { + return null; + } + // final long screenDC = GDI.GetDC(0); + final boolean res = GDI.GetDeviceGammaRamp(hDC, rampData); + // GDI.ReleaseDC(0, screenDC); if (!res) { return null; } @@ -589,7 +640,22 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected final void resetGammaRamp(final Buffer originalGammaRamp) { + protected final void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { + if (originalGammaRamp == null) { + // getGammaRamp failed earlier + return; + } + final long hDC = surface.getSurfaceHandle(); + if( 0 == hDC ) { + return; + } + // final long screenDC = GDI.GetDC(0); + GDI.SetDeviceGammaRamp(hDC, originalGammaRamp); + // GDI.ReleaseDC(0, hDC); + } + + @Override + protected final void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { if (originalGammaRamp == null) { // getGammaRamp failed earlier return; @@ -598,4 +664,143 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { GDI.SetDeviceGammaRamp(screenDC, originalGammaRamp); GDI.ReleaseDC(0, screenDC); } + + + static interface CPUAffinity { + boolean set(final int newAffinity); + boolean reset(); + } + static final class WindowsThreadAffinity implements CPUAffinity { + private long threadHandle; + private long threadOrigAffinity; + private long threadNewAffinity; + public WindowsThreadAffinity() { + threadHandle = 0; + threadOrigAffinity = 0; + threadNewAffinity = 0; + } + @Override + public boolean set(final int newAffinity) { + final long tid = GDI.GetCurrentThread(); + if( 0 != threadHandle ) { + throw new IllegalStateException("Affinity already set"); + } + final long threadLastAffinity = GDI.SetThreadAffinityMask(tid, newAffinity); + final int werr = GDI.GetLastError(); + final boolean res; + if( 0 != threadLastAffinity ) { + res = true; + this.threadHandle = tid; + this.threadNewAffinity = newAffinity; + this.threadOrigAffinity = threadLastAffinity; + } else { + res = false; + } + if(DEBUG) { + System.err.println("WindowsThreadAffinity.set() - tid " + toHexString(tid) + " - " + getThreadName() + + ": OK "+res+" (werr "+werr+"), Affinity: "+toHexString(threadOrigAffinity) + " -> " + toHexString(newAffinity)); + } + return res; + } + @Override + public boolean reset() { + if( 0 == threadHandle ) { + return true; + } + final long tid = GDI.GetCurrentThread(); + if( tid != threadHandle) { + throw new IllegalStateException("TID doesn't match: set TID " + toHexString(threadHandle) + + " this TID " + toHexString(tid) ); + } + final long preThreadAffinity = GDI.SetThreadAffinityMask(threadHandle, threadOrigAffinity); + final boolean res = 0 != preThreadAffinity; + if(DEBUG) { + System.err.println("WindowsThreadAffinity.reset() - tid " + toHexString(threadHandle) + " - " + getThreadName() + + ": OK "+res+" (werr "+GDI.GetLastError()+"), Affinity: "+toHexString(threadNewAffinity)+" -> orig "+ toHexString(threadOrigAffinity)); + } + this.threadHandle = 0; + this.threadNewAffinity = this.threadOrigAffinity; + return res; + } + } + static final class WindowsProcessAffinity implements CPUAffinity { + private long processHandle; + private long newAffinity; + private final PointerBuffer procMask; + private final PointerBuffer sysMask; + + public WindowsProcessAffinity() { + processHandle = 0; + newAffinity = 0; + procMask = PointerBuffer.allocateDirect(1); + sysMask = PointerBuffer.allocateDirect(1); + } + @Override + public boolean set(final int newAffinity) { + if( 0 != processHandle ) { + throw new IllegalStateException("Affinity already set"); + } + final long pid = GDI.GetCurrentProcess(); + final boolean res; + if ( GDI.GetProcessAffinityMask(pid, procMask, sysMask) ) { + if( GDI.SetProcessAffinityMask(pid, newAffinity) ) { + this.processHandle = pid; + this.newAffinity = newAffinity; + res = true; + } else { + res = false; + } + if(DEBUG) { + System.err.println("WindowsProcessAffinity.set() - pid " + toHexString(pid) + " - " + getThreadName() + + ": OK "+res+" (werr "+GDI.GetLastError()+"), Affinity: procMask "+ toHexString(procMask.get(0)) + ", sysMask "+ toHexString(sysMask.get(0)) + + " -> "+toHexString(newAffinity)); + } + } else { + if(DEBUG) { + System.err.println("WindowsProcessAffinity.set() - pid " + toHexString(pid) + " - " + getThreadName() + + ": Error, could not GetProcessAffinityMask, werr "+GDI.GetLastError()); + } + res = false; + } + return res; + } + @Override + public boolean reset() { + if( 0 == processHandle ) { + return true; + } + final long pid = GDI.GetCurrentProcess(); + if( pid != processHandle) { + throw new IllegalStateException("PID doesn't match: set PID " + toHexString(processHandle) + + " this PID " + toHexString(pid) ); + } + final long origProcAffinity = procMask.get(0); + final boolean res = GDI.SetProcessAffinityMask(processHandle, origProcAffinity); + if(DEBUG) { + final int werr = GDI.GetLastError(); + System.err.println("WindowsProcessAffinity.reset() - pid " + toHexString(processHandle) + " - " + getThreadName() + + ": OK "+res+" (werr "+werr+"), Affinity: "+toHexString(newAffinity)+" -> procMask "+ toHexString(origProcAffinity)); + } + this.processHandle = 0; + this.newAffinity = origProcAffinity; + return res; + } + } + static final class NopCPUAffinity implements CPUAffinity { + public NopCPUAffinity() { } + @Override + public boolean set(final int newAffinity) { + if(DEBUG) { + System.err.println("NopCPUAffinity.set() - " + getThreadName()); + } + return false; + } + @Override + public boolean reset() { + if(DEBUG) { + System.err.println("NopCPUAffinity.reset() - " + getThreadName()); + } + return false; + } + } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index d4c3abc49..9631dbb5b 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -303,8 +303,8 @@ public class X11GLXContext extends GLContextImpl { if( !config.hasFBConfig() ) { // not able to use FBConfig -> GLX 1.1 forceGLXVersionOneOne(); - if(glp.isGL3()) { - throw new GLException(getThreadName()+": Unable to create OpenGL >= 3.1 context"); + if( glp.isGL3() ) { + throw new GLException(getThreadName()+": Unable to create OpenGL >= 3.1 context w/o FBConfig"); } contextHandle = GLX.glXCreateContext(display, config.getXVisualInfo(), shareWithHandle, direct); if ( 0 == contextHandle ) { @@ -343,7 +343,7 @@ public class X11GLXContext extends GLContextImpl { throw new GLException(getThreadName()+": Unable to create temp OpenGL context(1)"); } if ( !glXMakeContextCurrent(display, drawable.getHandle(), drawableRead.getHandle(), temp_ctx) ) { - throw new GLException(getThreadName()+": Error making temp context(1) current: display "+toHexString(display)+", context "+toHexString(temp_ctx)+", drawable "+drawable); + throw new GLException(getThreadName()+": Error making temp context(1) current: display "+toHexString(display)+", context "+toHexString(temp_ctx)+", drawable "+drawable); } setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT, false /* strictMatch */, null == sharedContext /* withinGLVersionsMapping */); // use GL_VERSION glXMakeContextCurrent(display, 0, 0, 0); // release temp context @@ -351,7 +351,7 @@ public class X11GLXContext extends GLContextImpl { // is*Available calls are valid since setGLFunctionAvailability(..) was called final boolean isProcCreateContextAttribsARBAvailable = isFunctionAvailable("glXCreateContextAttribsARB"); final boolean isExtARBCreateContextAvailable = isExtensionAvailable("GLX_ARB_create_context"); - if ( isProcCreateContextAttribsARBAvailable && isExtARBCreateContextAvailable ) { + if ( isProcCreateContextAttribsARBAvailable && isExtARBCreateContextAvailable && !GLProfile.disableOpenGLARBContext ) { // initial ARB context creation contextHandle = createContextARB(shareWithHandle, direct); createContextARBTried=true; @@ -362,9 +362,11 @@ public class X11GLXContext extends GLContextImpl { System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - creation failed - share "+toHexString(shareWithHandle)); } } - } else if (DEBUG) { + } else if( DEBUG ) { System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - extension not available - share "+toHexString(shareWithHandle)+ - ", isProcCreateContextAttribsARBAvailable "+isProcCreateContextAttribsARBAvailable+", isExtGLXARBCreateContextAvailable "+isExtARBCreateContextAvailable); + ", isProcCreateContextAttribsARBAvailable "+isProcCreateContextAttribsARBAvailable+ + ", isExtGLXARBCreateContextAvailable "+isExtARBCreateContextAvailable+ + ", disableOpenGLARBContext "+GLProfile.disableOpenGLARBContext); } } } else { @@ -380,21 +382,24 @@ public class X11GLXContext extends GLContextImpl { } } } else { - if( glp.isGL3() ) { - glXMakeContextCurrent(display, 0, 0, 0); - GLX.glXDestroyContext(display, temp_ctx); - throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ctx !ARB, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glp+", current: "+getGLVersion()); + if( glp.isGL3() && createContextARBTried ) { + // We shall not allow context creation >= GL3 w/ non ARB methods if ARB is used, + // otherwise context of similar profile but different creation method may not be share-able. + glXMakeContextCurrent(display, 0, 0, 0); + GLX.glXDestroyContext(display, temp_ctx); + throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ctx !ARB but ARB is used, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glp+", current: "+getGLVersion()); } + if(DEBUG) { - System.err.println(getThreadName()+": X11GLXContext.createContextImpl failed, fall back to !ARB context "+getGLVersion()); + System.err.println(getThreadName()+": X11GLXContext.createContextImpl ARB not used, fall back to !ARB context "+getGLVersion()); } - // continue with temp context for GL <= 3.0 + // continue with temp context contextHandle = temp_ctx; if ( !glXMakeContextCurrent(display, drawable.getHandle(), drawableRead.getHandle(), contextHandle) ) { - glXMakeContextCurrent(display, 0, 0, 0); - GLX.glXDestroyContext(display, temp_ctx); - throw new GLException(getThreadName()+": Error making context(1) current: display "+toHexString(display)+", context "+toHexString(contextHandle)+", drawable "+drawable); + glXMakeContextCurrent(display, 0, 0, 0); + GLX.glXDestroyContext(display, temp_ctx); + throw new GLException(getThreadName()+": Error making context(1) current: display "+toHexString(display)+", context "+toHexString(contextHandle)+", drawable "+drawable); } if (DEBUG) { System.err.println(getThreadName() + ": createContextImpl: OK (old-2) share "+toHexString(shareWithHandle)); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index fbab32963..60e4438d0 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -72,6 +72,7 @@ import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; +import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.VersionNumber; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; @@ -562,34 +563,34 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { private boolean gotGammaRampLength; private int gammaRampLength; @Override - protected final synchronized int getGammaRampLength() { + protected final synchronized int getGammaRampLength(final NativeSurface surface) { if (gotGammaRampLength) { return gammaRampLength; } - - final long display = getOrCreateSharedDpy(defaultDevice); + final long display = surface.getDisplayHandle(); if(0 == display) { return 0; } + final int screenIdx = surface.getScreenIndex(); final int[] size = new int[1]; - final boolean res = X11Lib.XF86VidModeGetGammaRampSize(display, - X11Lib.DefaultScreen(display), - size, 0); + final boolean res = X11Lib.XF86VidModeGetGammaRampSize(display, screenIdx, size, 0); if (!res) { return 0; } gotGammaRampLength = true; gammaRampLength = size[0]; + System.err.println("XXX: Gamma ramp size: "+gammaRampLength); return gammaRampLength; } @Override - protected final boolean setGammaRamp(final float[] ramp) { - final long display = getOrCreateSharedDpy(defaultDevice); + protected final boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { + final long display = surface.getDisplayHandle(); if(0 == display) { return false; } + final int screenIdx = surface.getScreenIndex(); final int len = ramp.length; final short[] rampData = new short[len]; @@ -597,36 +598,52 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData[i] = (short) (ramp[i] * 65535); } - final boolean res = X11Lib.XF86VidModeSetGammaRamp(display, - X11Lib.DefaultScreen(display), + final boolean res = X11Lib.XF86VidModeSetGammaRamp(display, screenIdx, rampData.length, rampData, 0, rampData, 0, rampData, 0); + if( DEBUG ) { + dumpRamp("SET__", rampData.length, rampData, rampData, rampData); + } return res; } + private static void dumpRamp(final String prefix, final int size, final ShortBuffer r, final ShortBuffer g, final ShortBuffer b) { + for(int i=0; i<size; i++) { + if( 0 == i % 4 ) { + System.err.printf("%n%4d/%4d %s: ", i, size, prefix); + } + System.err.printf(" [%04X %04X %04X], ", r.get(i), g.get(i), b.get(i)); + } + System.err.println(); + } + private static void dumpRamp(final String prefix, final int size, final short[] r, final short[] g, final short[] b) { + for(int i=0; i<size; i++) { + if( 0 == i % 4 ) { + System.err.printf("%n%4d/%4d %s: ", i, size, prefix); + } + System.err.printf(" [%04X %04X %04X], ", r[i], g[i], b[i]); + } + System.err.println(); + } + @Override - protected final Buffer getGammaRamp() { - final long display = getOrCreateSharedDpy(defaultDevice); + protected final Buffer getGammaRamp(final NativeSurface surface) { + final long display = surface.getDisplayHandle(); if(0 == display) { return null; } + final int screenIdx = surface.getScreenIndex(); + + final int size = getGammaRampLength(surface); - final int size = getGammaRampLength(); - final ShortBuffer rampData = ShortBuffer.wrap(new short[3 * size]); - rampData.position(0); - rampData.limit(size); - final ShortBuffer redRampData = rampData.slice(); - rampData.position(size); - rampData.limit(2 * size); - final ShortBuffer greenRampData = rampData.slice(); - rampData.position(2 * size); - rampData.limit(3 * size); - final ShortBuffer blueRampData = rampData.slice(); - - final boolean res = X11Lib.XF86VidModeGetGammaRamp(display, - X11Lib.DefaultScreen(display), + final ShortBuffer rampData = Buffers.newDirectShortBuffer(3 * size); + final ShortBuffer redRampData = Buffers.slice(rampData, 0 * size, size); + final ShortBuffer greenRampData = Buffers.slice(rampData, 1 * size, size); + final ShortBuffer blueRampData = Buffers.slice(rampData, 2 * size, size); + + final boolean res = X11Lib.XF86VidModeGetGammaRamp(display, screenIdx, size, redRampData, greenRampData, @@ -634,40 +651,62 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { if (!res) { return null; } + if( DEBUG ) { + dumpRamp("GET__", size, redRampData, greenRampData, blueRampData); + } return rampData; } @Override - protected final void resetGammaRamp(final Buffer originalGammaRamp) { + protected final void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { if (originalGammaRamp == null) { return; // getGammaRamp failed originally } - final long display = getOrCreateSharedDpy(defaultDevice); + final long display = surface.getDisplayHandle(); if(0 == display) { return; } + final int screenIdx = surface.getScreenIndex(); + + resetGammaRamp(display, screenIdx, originalGammaRamp); + } + + @Override + protected final void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { + if (originalGammaRamp == null) { + return; // getGammaRamp failed originally + } + final long display = X11Util.openDisplay(deviceScreenID.deviceConnection); + if( 0 == display ) { + return; + } + try { + resetGammaRamp(display, deviceScreenID.screenIdx, originalGammaRamp); + } finally { + X11Util.closeDisplay(display); + } + } + private static final void resetGammaRamp(final long display, final int screenIdx, final Buffer originalGammaRamp) { final ShortBuffer rampData = (ShortBuffer) originalGammaRamp; final int capacity = rampData.capacity(); if ((capacity % 3) != 0) { throw new IllegalArgumentException("Must not be the original gamma ramp"); } final int size = capacity / 3; - rampData.position(0); - rampData.limit(size); - final ShortBuffer redRampData = rampData.slice(); - rampData.position(size); - rampData.limit(2 * size); - final ShortBuffer greenRampData = rampData.slice(); - rampData.position(2 * size); - rampData.limit(3 * size); - final ShortBuffer blueRampData = rampData.slice(); - - X11Lib.XF86VidModeSetGammaRamp(display, - X11Lib.DefaultScreen(display), - size, - redRampData, - greenRampData, - blueRampData); + + final ShortBuffer redRampData = Buffers.slice(rampData, 0 * size, size); + final ShortBuffer greenRampData = Buffers.slice(rampData, 1 * size, size); + final ShortBuffer blueRampData = Buffers.slice(rampData, 2 * size, size); + if( DEBUG ) { + dumpRamp("RESET", size, redRampData, greenRampData, blueRampData); + } + + X11Lib.XF86VidModeSetGammaRamp(display, screenIdx, + size, + redRampData, + greenRampData, + blueRampData); } + } |