diff options
author | Sven Gothel <[email protected]> | 2014-07-28 15:29:59 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-07-28 15:29:59 +0200 |
commit | e96882ae569c681e1b28da6701bf547f6dd9eda8 (patch) | |
tree | 52b087b7020af25d03e32c13b8b84e09c41337b4 /src/jogl | |
parent | 876a168f6757454e8a02543b53e32b89e54282bd (diff) |
Bug 1037 - FBObject/GLFBODrawable: Do not assume using a TextureAttachment for a Colorbuffer, also make DEPTH optional.
API Change
+++
In certain cases a TextureAttachment for the FBO's color buffer
is not desired, either for performance reasons where texture functionality
is not required or to avoid texture restrictions like size, etc.
+++
GLFBODrawable shall use TextureAttachment for the FBO's color buffer
and a DEPTH buffer per default.
However, the user shall be allowed to use a plain ColorAttachment (renderbuffer)
and also no DEPTH buffer.
+++
FBObject Details:
- Colorbuffer interface exposes Attachment details
like format, size, etc as well as it's implementation
specifics, isTextureAttachment() and getTextureAttachment() allowing a clean cast and type query.
- Allow ColorAttachment to be used for non MSAA
- Make TextureAttachment optional for method 'use(GL, TextureAttachment)'
- Only validate size against MAX_TEXTURESIZE if using a TextureAttachment
- API Change:
- rename: getColorAttachmentCount() -> getColorbufferCount()
- add: getTextureAttachmentCount()
- change 'TextureAttachment getSamplingSink()' -> 'Colorbuffer getSamplingSink()'
Diffstat (limited to 'src/jogl')
8 files changed, 386 insertions, 183 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java index 8c076e742..f0f94466c 100644 --- a/src/jogl/classes/com/jogamp/opengl/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java @@ -66,9 +66,8 @@ public class FBObject { private static enum DetachAction { NONE, DISPOSE, RECREATE }; /** - * Marker interface, denotes a color buffer attachment. + * Generic color buffer FBO attachment, either of type {@link ColorAttachment} or {@link TextureAttachment}. * <p>Always an instance of {@link Attachment}.</p> - * <p>Either an instance of {@link ColorAttachment} or {@link TextureAttachment}.</b> */ public static interface Colorbuffer { /** @@ -76,23 +75,55 @@ public class FBObject { * @return <code>true</code> if newly initialized, otherwise <code>false</code>. * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case. */ - public boolean initialize(GL gl) throws GLException; + boolean initialize(GL gl) throws GLException; /** * Releases the color buffer if initialized, i.e. name is not <code>zero</code>. * @throws GLException if buffer release fails. */ - public void free(GL gl) throws GLException; + void free(GL gl) throws GLException; /** * Writes the internal format to the given GLCapabilities object. * @param caps the destination for format bits * @param rgba8Avail whether rgba8 is available */ - public void formatToGLCapabilities(GLCapabilities caps, boolean rgba8Avail); + void formatToGLCapabilities(GLCapabilities caps, boolean rgba8Avail); + + /** + * Returns <code>true</code> if instance is of type {@link TextureAttachment} + * and <code>false</code> if instance is of type {@link ColorAttachment}. + */ + boolean isTextureAttachment(); + + /** + * Casts this object to a {@link TextureAttachment} reference, see {@link #isTextureAttachment()}. + * @throws GLException if this object is not of type {@link TextureAttachment} + * @see #isTextureAttachment() + */ + TextureAttachment getTextureAttachment(); + + /** + * Casts this object to a {@link ColorAttachment} reference, see {@link #isTextureAttachment()}. + * @throws GLException if this object is not of type {@link ColorAttachment} + * @see #isTextureAttachment() + */ + ColorAttachment getColorAttachment(); + + /** internal format of colorbuffer */ + int getFormat(); + + /** width of colorbuffer */ + int getWidth(); + + /** height of colorbuffer */ + int getHeight(); + + /** colorbuffer name [1..max] */ + int getName(); } - /** Common super class of all attachments */ + /** Common super class of all FBO attachments */ public static abstract class Attachment { public enum Type { NONE, DEPTH, STENCIL, DEPTH_STENCIL, COLOR, COLOR_TEXTURE, DEPTH_TEXTURE, STENCIL_TEXTURE; @@ -220,6 +251,9 @@ public class FBObject { } } + /** immutable internal format of attachment */ + public final int getFormat() { return format; } + /** width of attachment */ public final int getWidth() { return width; } /** height of attachment */ @@ -423,14 +457,21 @@ public class FBObject { } } - /** Color render buffer attachment */ + /** Color render buffer FBO attachment */ public static class ColorAttachment extends RenderAttachment implements Colorbuffer { public ColorAttachment(final int iFormat, final int samples, final int width, final int height, final int name) { super(Type.COLOR, iFormat, samples, width, height, name); } + @Override + public final boolean isTextureAttachment() { return false; } + @Override + public final TextureAttachment getTextureAttachment() { throw new GLException("Not a TextureAttachment, but ColorAttachment"); } + @Override + public final ColorAttachment getColorAttachment() { return this; } + } - /** Texture attachment */ + /** Texture FBO attachment */ public static class TextureAttachment extends Attachment implements Colorbuffer { /** details of the texture setup */ public final int dataFormat, dataType, magFilter, minFilter, wrapS, wrapT; @@ -530,6 +571,14 @@ public class FBObject { setName(0); } } + + @Override + public final boolean isTextureAttachment() { return true; } + @Override + public final TextureAttachment getTextureAttachment() { return this; } + @Override + public final ColorAttachment getColorAttachment() { throw new GLException("Not a ColorAttachment, but TextureAttachment"); } + @Override public String toString() { return getClass().getSimpleName()+"[type "+type+", target GL_TEXTURE_2D, level 0, format "+toHexString(format)+ @@ -677,12 +726,13 @@ public class FBObject { private int fbName; private boolean bound; - private int colorAttachmentCount; - private Colorbuffer[] colorAttachmentPoints; // colorbuffer attachment points + private int colorbufferCount; + private int textureAttachmentCount; + private Colorbuffer[] colorbufferAttachments; // colorbuffer attachment points private RenderAttachment depth, stencil; // depth and stencil maybe equal in case of packed-depth-stencil private FBObject samplingSink; // MSAA sink - private TextureAttachment samplingSinkTexture; + private Colorbuffer samplingColorSink; private boolean samplingSinkDirty; // @@ -693,8 +743,8 @@ public class FBObject { if(!initialized) { throw new GLException("FBO not initialized"); } - if(maxColorAttachments != colorAttachmentPoints.length) { - throw new InternalError("maxColorAttachments "+maxColorAttachments+", array.length "+colorAttachmentPoints.length); + if(maxColorAttachments != colorbufferAttachments.length) { + throw new InternalError("maxColorAttachments "+maxColorAttachments+", array.length "+colorbufferAttachments.length); } if(0 > point || point >= maxColorAttachments) { throw new IllegalArgumentException("attachment point out of range: "+point+", should be within [0.."+(maxColorAttachments-1)+"], "+this); @@ -703,29 +753,35 @@ public class FBObject { private final void validateAddColorAttachment(final int point, final Colorbuffer ca) { validateColorAttachmentPointRange(point); - if( null != colorAttachmentPoints[point] ) { - throw new IllegalArgumentException("Cannot attach "+ca+", attachment point already in use by "+colorAttachmentPoints[point]+", "+this); + if( null != colorbufferAttachments[point] ) { + throw new IllegalArgumentException("Cannot attach "+ca+", attachment point already in use by "+colorbufferAttachments[point]+", "+this); } } private final void addColorAttachment(final int point, final Colorbuffer ca) { validateColorAttachmentPointRange(point); - final Colorbuffer c = colorAttachmentPoints[point]; + final Colorbuffer c = colorbufferAttachments[point]; if( null != c && c != ca ) { throw new IllegalArgumentException("Add failed: requested to add "+ca+" at "+point+", but slot is holding "+c+"; "+this); } - colorAttachmentPoints[point] = ca; - colorAttachmentCount++; + colorbufferAttachments[point] = ca; + colorbufferCount++; + if( ca.isTextureAttachment() ) { + textureAttachmentCount++; + } } private final void removeColorAttachment(final int point, final Colorbuffer ca) { validateColorAttachmentPointRange(point); - final Colorbuffer c = colorAttachmentPoints[point]; + final Colorbuffer c = colorbufferAttachments[point]; if( null != c && c != ca ) { throw new IllegalArgumentException("Remove failed: requested to removed "+ca+" at "+point+", but slot is holding "+c+"; "+this); } - colorAttachmentPoints[point] = null; - colorAttachmentCount--; + colorbufferAttachments[point] = null; + colorbufferCount--; + if( ca.isTextureAttachment() ) { + textureAttachmentCount--; + } } /** @@ -738,7 +794,7 @@ public class FBObject { */ public final Colorbuffer getColorbuffer(final int attachmentPoint) { validateColorAttachmentPointRange(attachmentPoint); - return colorAttachmentPoints[attachmentPoint]; + return colorbufferAttachments[attachmentPoint]; } /** @@ -751,8 +807,8 @@ public class FBObject { * @return -1 if the {@link Colorbuffer} could not be found, otherwise [0..{@link #getMaxColorAttachments()}-1] */ public final int getColorbufferAttachmentPoint(final Colorbuffer ca) { - for(int i=0; i<colorAttachmentPoints.length; i++) { - if( colorAttachmentPoints[i] == ca ) { + for(int i=0; i<colorbufferAttachments.length; i++) { + if( colorbufferAttachments[i] == ca ) { return i; } } @@ -783,7 +839,7 @@ public class FBObject { * otherwise false. */ public final boolean hasAttachmentUsingAlpha() { - final int caCount = getColorAttachmentCount(); + final int caCount = getColorbufferCount(); boolean hasAlpha = false; for(int i=0; i<caCount; i++) { final Attachment ca = (Attachment)getColorbuffer(i); @@ -830,13 +886,14 @@ public class FBObject { this.fbName = 0; this.bound = false; - this.colorAttachmentPoints = null; // at init .. - this.colorAttachmentCount = 0; + this.colorbufferAttachments = null; // at init .. + this.colorbufferCount = 0; + this.textureAttachmentCount = 0; this.depth = null; this.stencil = null; this.samplingSink = null; - this.samplingSinkTexture = null; + this.samplingColorSink = null; this.samplingSinkDirty = true; } @@ -878,12 +935,15 @@ public class FBObject { } maxColorAttachments = realMaxColorAttachments <= 8 ? realMaxColorAttachments : 8; // cap to limit array size - colorAttachmentPoints = new Colorbuffer[maxColorAttachments]; - colorAttachmentCount = 0; + colorbufferAttachments = new Colorbuffer[maxColorAttachments]; + colorbufferCount = 0; + textureAttachmentCount = 0; maxSamples = gl.getMaxRenderbufferSamples(); gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, val, 0); - maxTextureSize = val[0]; + final int _maxTextureSize = val[0]; + // FIXME maxTextureSize = 512; + maxTextureSize = _maxTextureSize; gl.glGetIntegerv(GL.GL_MAX_RENDERBUFFER_SIZE, val, 0); maxRenderbufferSize = val[0]; @@ -896,11 +956,11 @@ public class FBObject { this.samples = samples <= maxSamples ? samples : maxSamples; if(DEBUG) { - System.err.println("FBObject "+width+"x"+height+", "+samples+" -> "+this.samples+" samples"); + System.err.println("FBObject.init() START: "+width+"x"+height+", "+samples+" -> "+this.samples+" samples"); System.err.println("fullFBOSupport: "+fullFBOSupport); System.err.println("maxColorAttachments: "+maxColorAttachments+"/"+realMaxColorAttachments+" [capped/real]"); System.err.println("maxSamples: "+maxSamples); - System.err.println("maxTextureSize: "+maxTextureSize); + System.err.println("maxTextureSize: "+_maxTextureSize+" -> "+maxTextureSize); System.err.println("maxRenderbufferSize: "+maxRenderbufferSize); System.err.println("rgba8: "+rgba8Avail); System.err.println("depth24: "+depth24Avail); @@ -912,8 +972,7 @@ public class FBObject { System.err.println("packedDepthStencil: "+packedDepthStencilAvail); System.err.println("NV_fbo_color_attachments: "+NV_fbo_color_attachments); System.err.println(gl.getContext().getGLVersion()); - System.err.println(JoglVersion.getGLStrings(gl, null).toString()); - System.err.println(gl.getContext()); + System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); } checkNoError(null, gl.glGetError(), "FBObject Init.pre"); // throws GLException if error @@ -944,7 +1003,7 @@ public class FBObject { vStatus = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // always incomplete w/o attachments! if(DEBUG) { - System.err.println("FBObject.init(): "+this); + System.err.println("FBObject.init() END: "+this); } } @@ -1007,9 +1066,11 @@ public class FBObject { if( newWidth != width || newHeight != height || newSamples != samples ) { if( 0 >= newWidth ) { newWidth = 1; } if( 0 >= newHeight ) { newHeight = 1; } - if( newWidth > 2 + maxTextureSize || newHeight > 2 + maxTextureSize || - newWidth > maxRenderbufferSize || newHeight > maxRenderbufferSize ) { - throw new GLException("size "+width+"x"+height+" exceeds on of the maxima [texture "+maxTextureSize+", renderbuffer "+maxRenderbufferSize+"]"); + if( textureAttachmentCount > 0 && ( newWidth > 2 + maxTextureSize || newHeight > 2 + maxTextureSize ) ) { + throw new GLException("size "+width+"x"+height+" exceeds on of the maximum texture size "+maxTextureSize); + } + if( newWidth > maxRenderbufferSize || newHeight > maxRenderbufferSize ) { + throw new GLException("size "+width+"x"+height+" exceeds on of the maxima renderbuffer size "+maxRenderbufferSize); } if(DEBUG) { @@ -1018,6 +1079,16 @@ public class FBObject { final boolean wasBound = isBound(); + final int sampleCountChange; + if( 0 < samples && 0 < newSamples || 0 == samples && 0 == newSamples ) { + sampleCountChange = 0; // keep MSAA settings + } else if( 0 == samples && 0 < newSamples ) { + sampleCountChange = 1; // add MSAA + } else if( 0 < samples && 0 == newSamples ) { + sampleCountChange = -1; // remove MSAA + } else { + throw new IllegalArgumentException("Error in sampleCount change: "+samples+" -> "+newSamples); + } width = newWidth; height = newHeight; samples = newSamples; @@ -1027,7 +1098,7 @@ public class FBObject { samplingSink = new FBObject(); samplingSink.init(gl, width, height, 0); } - detachAllImpl(gl, true , true); + detachAllImpl(gl, true, true, sampleCountChange); if(resetSamplingSink) { resetSamplingSink(gl); } @@ -1134,7 +1205,7 @@ public class FBObject { case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: case GL2ES3.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: case GL3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: - if(0 == colorAttachmentCount || null == depth) { + if(0 == colorbufferCount || null == depth) { // we are in transition return true; } @@ -1196,8 +1267,8 @@ public class FBObject { * @see #createColorTextureAttachment(GLProfile, boolean, int, int) */ public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha) throws GLException { - return (TextureAttachment)attachColorbuffer(gl, attachmentPoint, - createColorTextureAttachment(gl, alpha, width, height)); + return attachColorbuffer(gl, attachmentPoint, + createColorTextureAttachment(gl, alpha, width, height)).getTextureAttachment(); } /** @@ -1218,8 +1289,8 @@ public class FBObject { * @see #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int) */ public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha, final int magFilter, final int minFilter, final int wrapS, final int wrapT) throws GLException { - return (TextureAttachment)attachColorbuffer(gl, attachmentPoint, - createColorTextureAttachment(gl, alpha, width, height, magFilter, minFilter, wrapS, wrapT)); + return attachColorbuffer(gl, attachmentPoint, + createColorTextureAttachment(gl, alpha, width, height, magFilter, minFilter, wrapS, wrapT)).getTextureAttachment(); } /** @@ -1243,8 +1314,8 @@ public class FBObject { public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final int internalFormat, final int dataFormat, final int dataType, final int magFilter, final int minFilter, final int wrapS, final int wrapT) throws GLException { - return (TextureAttachment)attachColorbuffer(gl, attachmentPoint, - createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT)); + return attachColorbuffer(gl, attachmentPoint, + createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT)).getTextureAttachment(); } /** @@ -1266,7 +1337,26 @@ public class FBObject { } else { internalFormat = alpha ? GL.GL_RGBA4 : GL.GL_RGB565; } - return new ColorAttachment(internalFormat, samples, width, height, 0); + return createColorAttachment(internalFormat, samples, width, height); + } + + /** + * Creates a {@link ColorAttachment}, selecting the format automatically. + * <p> + * For GLES3, sampling-sink {@link Colorbuffer} format <b>must be equal</b> w/ the sampling-source {@link Colorbuffer}. + * Implementation aligns w/ {@link #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)} + * and is enforced via {@link #sampleSinkFormatMismatch(GL)}. + * </p> + * + * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>; + * @return uninitialized ColorAttachment instance describing the new attached colorbuffer + */ + public static final ColorAttachment createColorAttachment(final int internalFormat, final int samples, final int width, final int height) { + return new ColorAttachment(internalFormat, samples, width, height, 0 /* name not yet determined */); + } + + public static final RenderAttachment createRenderAttachment(final Type type, final int internalFormat, final int samples, final int width, final int height) { + return new RenderAttachment(type, internalFormat, samples, width, height, 0 /* name not yet determined */); } /** @@ -1283,7 +1373,7 @@ public class FBObject { * @see #createColorAttachment(boolean) */ public final ColorAttachment attachColorbuffer(final GL gl, final int attachmentPoint, final boolean alpha) throws GLException { - return (ColorAttachment) attachColorbuffer(gl, attachmentPoint, createColorAttachment(alpha)); + return attachColorbuffer(gl, attachmentPoint, createColorAttachment(alpha)).getColorAttachment(); } /** @@ -1304,7 +1394,7 @@ public class FBObject { throw new IllegalArgumentException("colorformat invalid: "+toHexString(internalFormat)+", "+this); } - return (ColorAttachment) attachColorbuffer(gl, attachmentPoint, new ColorAttachment(internalFormat, samples, width, height, 0)); + return attachColorbuffer(gl, attachmentPoint, createColorAttachment(internalFormat, samples, width, height)).getColorAttachment(); } /** @@ -1337,10 +1427,9 @@ public class FBObject { final boolean initializedColorbuf = colbuf.initialize(gl); addColorAttachment(attachmentPoint, colbuf); - if(colbuf instanceof TextureAttachment) { - final TextureAttachment texA = (TextureAttachment) colbuf; - - if(samples>0) { + if( colbuf.isTextureAttachment() ) { + final TextureAttachment texA = colbuf.getTextureAttachment(); + if( samples > 0 ) { removeColorAttachment(attachmentPoint, texA); if(initializedColorbuf) { texA.free(gl); @@ -1360,8 +1449,8 @@ public class FBObject { throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this); } } - } else if(colbuf instanceof ColorAttachment) { - final ColorAttachment colA = (ColorAttachment) colbuf; + } else { + final ColorAttachment colA = colbuf.getColorAttachment(); // Attach the color buffer gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, @@ -1516,7 +1605,7 @@ public class FBObject { private final void attachRenderbufferImpl2(final GL gl, final Attachment.Type atype, final int internalFormat) throws GLException { if( Attachment.Type.DEPTH == atype ) { if(null == depth) { - depth = new RenderAttachment(Type.DEPTH, internalFormat, samples, width, height, 0); + depth = createRenderAttachment(Type.DEPTH, internalFormat, samples, width, height); } else { depth.setSize(width, height); depth.setSamples(samples); @@ -1524,7 +1613,7 @@ public class FBObject { depth.initialize(gl); } else if( Attachment.Type.STENCIL == atype ) { if(null == stencil) { - stencil = new RenderAttachment(Type.STENCIL, internalFormat, samples, width, height, 0); + stencil = createRenderAttachment(Type.STENCIL, internalFormat, samples, width, height); } else { stencil.setSize(width, height); stencil.setSamples(samples); @@ -1535,7 +1624,7 @@ public class FBObject { if(null != stencil) { throw new InternalError("XXX: DEPTH_STENCIL, depth was null, stencil not: "+this.toString()); } - depth = new RenderAttachment(Type.DEPTH_STENCIL, internalFormat, samples, width, height, 0); + depth = createRenderAttachment(Type.DEPTH_STENCIL, internalFormat, samples, width, height); } else { depth.setSize(width, height); depth.setSamples(samples); @@ -1581,7 +1670,7 @@ public class FBObject { public final Colorbuffer detachColorbuffer(final GL gl, final int attachmentPoint, final boolean dispose) throws IllegalArgumentException { bind(gl); - final Colorbuffer res = detachColorbufferImpl(gl, attachmentPoint, dispose ? DetachAction.DISPOSE : DetachAction.NONE); + final Colorbuffer res = detachColorbufferImpl(gl, attachmentPoint, dispose ? DetachAction.DISPOSE : DetachAction.NONE, 0); if(null == res) { throw new IllegalArgumentException("ColorAttachment at "+attachmentPoint+", not attached, "+this); } @@ -1591,8 +1680,8 @@ public class FBObject { return res; } - private final Colorbuffer detachColorbufferImpl(final GL gl, final int attachmentPoint, final DetachAction detachAction) { - Colorbuffer colbuf = colorAttachmentPoints[attachmentPoint]; // shortcut, don't validate here + private final Colorbuffer detachColorbufferImpl(final GL gl, final int attachmentPoint, final DetachAction detachAction, final int sampleCountChange) { + Colorbuffer colbuf = colorbufferAttachments[attachmentPoint]; // shortcut, don't validate here if(null == colbuf) { return null; @@ -1600,8 +1689,8 @@ public class FBObject { removeColorAttachment(attachmentPoint, colbuf); - if(colbuf instanceof TextureAttachment) { - final TextureAttachment texA = (TextureAttachment) colbuf; + if( colbuf.isTextureAttachment() ) { + final TextureAttachment texA = colbuf.getTextureAttachment(); if( 0 != texA.getName() ) { gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + attachmentPoint, @@ -1616,17 +1705,17 @@ public class FBObject { } } if(DetachAction.RECREATE == detachAction) { - if(samples == 0) { - // stay non MSAA - texA.setSize(width, height); - } else { - // switch to MSAA + if( 0 < sampleCountChange ) { + // switch to MSAA: TextureAttachment -> ColorAttachment colbuf = createColorAttachment(hasAlpha(texA.format)); + } else { + // keep MSAA settings + texA.setSize(width, height); } attachColorbufferImpl(gl, attachmentPoint, colbuf); } - } else if(colbuf instanceof ColorAttachment) { - final ColorAttachment colA = (ColorAttachment) colbuf; + } else { + final ColorAttachment colA = colbuf.getColorAttachment(); if( 0 != colA.getName() ) { gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0+attachmentPoint, @@ -1640,19 +1729,22 @@ public class FBObject { } } if(DetachAction.RECREATE == detachAction) { - if(samples > 0) { - // stay MSAA + if( 0 <= sampleCountChange || null == samplingColorSink ) { + // keep ColorAttachment, + // including 'switch to non-MSAA' if no samplingColorSink is available + // to determine whether a TextureAttachment or ColorAttachment is desired! colA.setSize(width, height); colA.setSamples(samples); } else { // switch to non MSAA - if(null != samplingSinkTexture) { - colbuf = createColorTextureAttachment(samplingSinkTexture.format, width, height, - samplingSinkTexture.dataFormat, samplingSinkTexture.dataType, - samplingSinkTexture.magFilter, samplingSinkTexture.minFilter, - samplingSinkTexture.wrapS, samplingSinkTexture.wrapT); + if( samplingColorSink.isTextureAttachment() ) { + final TextureAttachment samplingTextureSink = samplingColorSink.getTextureAttachment(); + colbuf = createColorTextureAttachment(samplingTextureSink.format, width, height, + samplingTextureSink.dataFormat, samplingTextureSink.dataType, + samplingTextureSink.magFilter, samplingTextureSink.minFilter, + samplingTextureSink.wrapS, samplingTextureSink.wrapT); } else { - colbuf = createColorTextureAttachment(gl, true, width, height); + colbuf = createColorAttachment(samplingColorSink.getFormat(), 0, width, height); } } attachColorbuffer(gl, attachmentPoint, colbuf); @@ -1663,14 +1755,14 @@ public class FBObject { private final void freeAllColorbufferImpl(final GL gl) { for(int i=0; i<maxColorAttachments; i++) { - final Colorbuffer colbuf = colorAttachmentPoints[i]; // shortcut, don't validate here + final Colorbuffer colbuf = colorbufferAttachments[i]; // shortcut, don't validate here if(null == colbuf) { return; } - if(colbuf instanceof TextureAttachment) { - final TextureAttachment texA = (TextureAttachment) colbuf; + if( colbuf.isTextureAttachment() ) { + final TextureAttachment texA = colbuf.getTextureAttachment(); if( 0 != texA.getName() ) { gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + i, @@ -1678,8 +1770,8 @@ public class FBObject { gl.glBindTexture(GL.GL_TEXTURE_2D, 0); } texA.free(gl); - } else if(colbuf instanceof ColorAttachment) { - final ColorAttachment colA = (ColorAttachment) colbuf; + } else { + final ColorAttachment colA = colbuf.getColorAttachment(); if( 0 != colA.getName() ) { gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + i, @@ -1849,7 +1941,7 @@ public class FBObject { * and disposes them. * <p>Leaves the FBO bound, if initialized!</p> * <p> - * An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}. + * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}. * </p> * @param gl the current GL context */ @@ -1857,7 +1949,7 @@ public class FBObject { if(null != samplingSink) { samplingSink.detachAll(gl); } - detachAllImpl(gl, true/* detachNonColorbuffer */, false /* recreate */); + detachAllImpl(gl, true/* detachNonColorbuffer */, false /* recreate */, 0); } /** @@ -1865,7 +1957,7 @@ public class FBObject { * and disposes them. * <p>Leaves the FBO bound, if initialized!</p> * <p> - * An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}. + * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}. * </p> * @param gl the current GL context */ @@ -1873,14 +1965,14 @@ public class FBObject { if(null != samplingSink) { samplingSink.detachAllColorbuffer(gl); } - detachAllImpl(gl, false/* detachNonColorbuffer */, false /* recreate */); + detachAllImpl(gl, false/* detachNonColorbuffer */, false /* recreate */, 0); } /** * Detaches all {@link TextureAttachment}s and disposes them. * <p>Leaves the FBO bound, if initialized!</p> * <p> - * An attached sampling sink texture will be detached as well, see {@link #getSamplingSink()}. + * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}. * </p> * @param gl the current GL context */ @@ -1893,8 +1985,8 @@ public class FBObject { } bind(gl); for(int i=0; i<maxColorAttachments; i++) { - if(colorAttachmentPoints[i] instanceof TextureAttachment) { - detachColorbufferImpl(gl, i, DetachAction.DISPOSE); + if( colorbufferAttachments[i].isTextureAttachment() ) { + detachColorbufferImpl(gl, i, DetachAction.DISPOSE, 0); } } if(DEBUG) { @@ -1913,7 +2005,7 @@ public class FBObject { detachRenderbufferImpl(gl, Attachment.Type.DEPTH_STENCIL, DetachAction.DISPOSE); } - private final void detachAllImpl(final GL gl, final boolean detachNonColorbuffer, final boolean recreate) { + private final void detachAllImpl(final GL gl, final boolean detachNonColorbuffer, final boolean recreate, final int sampleCountChange) { if( !isInitialized() ) { return; } @@ -1928,9 +2020,9 @@ public class FBObject { } } for(int i=0; i<maxColorAttachments; i++) { - detachColorbufferImpl(gl, i, recreate ? DetachAction.RECREATE : DetachAction.DISPOSE); + detachColorbufferImpl(gl, i, recreate ? DetachAction.RECREATE : DetachAction.DISPOSE, sampleCountChange); } - if( !recreate && colorAttachmentCount>0 ) { + if( !recreate && colorbufferCount>0 ) { throw new InternalError("Non zero ColorAttachments "+this); } @@ -1969,7 +2061,7 @@ public class FBObject { samplingSink.destroy(gl); } - detachAllImpl(gl, true /* detachNonColorbuffer */, false /* recreate */); + detachAllImpl(gl, true /* detachNonColorbuffer */, false /* recreate */, 0); // cache FB names, preset exposed to zero, // braking ties w/ GL/GLContext link to getReadFramebuffer()/getWriteFramebuffer() @@ -1991,16 +2083,16 @@ public class FBObject { private final boolean sampleSinkSizeMismatch() { return samplingSink.getWidth() != width || samplingSink.getHeight() != height ; } - private final boolean sampleSinkTexMismatch() { - return null == samplingSinkTexture || 0 == samplingSinkTexture.getName() ; + private final boolean sampleColorsinkUninit() { + return null != samplingColorSink && 0 == samplingColorSink.getName() ; } private final boolean sampleSinkDepthStencilMismatch() { - final boolean depthMismatch = ( null != depth && null == samplingSink.depth ) || - ( null != depth && null != samplingSink.depth && + final boolean depthMismatch = null != depth && + ( null == samplingSink.depth || depth.format != samplingSink.depth.format ); - final boolean stencilMismatch = ( null != stencil && null == samplingSink.stencil ) || - ( null != stencil && null != samplingSink.stencil && + final boolean stencilMismatch = null != stencil && + ( null == samplingSink.stencil || stencil.format != samplingSink.stencil.format ); return depthMismatch || stencilMismatch; @@ -2011,10 +2103,10 @@ public class FBObject { * and {@link #createColorAttachment(boolean)}. */ private final boolean sampleSinkFormatMismatch(final GL gl) { - if( null != samplingSinkTexture && getColorAttachmentCount() > 0 && gl.isGL2ES3() ) { + if( null != samplingColorSink && getColorbufferCount() > 0 && gl.isGL2ES3() ) { final Attachment ca = (Attachment)getColorbuffer(0); // should be at attachment-point 0 - return ( null != ca && ca.format != samplingSinkTexture.format ) || - hasAlpha(samplingSinkTexture.format) != hasAttachmentUsingAlpha(); + return ( null != ca && ca.format != samplingColorSink.getFormat() ) || + hasAlpha(samplingColorSink.getFormat()) != hasAttachmentUsingAlpha(); } return false; } @@ -2037,34 +2129,41 @@ public class FBObject { * @throws GLException in case of an error, i.e. size too big, etc .. */ public final void resetSamplingSink(final GL gl) throws GLException { - if(0 == samples) { + if(DEBUG) { + System.err.println("FBObject.resetSamplingSink.0"); + } + if( 0 == samples ) { // MSAA off if(null != samplingSink && samplingSink.initialized) { // cleanup samplingSink.detachAll(gl); } + if(DEBUG) { + System.err.println("FBObject.resetSamplingSink.X1: zero samples \n\tTHIS "+this); + } return; } - if(null == samplingSink ) { + if( null == samplingSink ) { samplingSink = new FBObject(); } - if(!samplingSink.initialized) { + if( !samplingSink.initialized ) { samplingSink.init(gl, width, height, 0); } + if(DEBUG) { + System.err.println("FBObject.resetSamplingSink.1: \n\tTHIS "+this+",\n\tSINK "+samplingSink); + } boolean sampleSinkFormatMismatch = sampleSinkFormatMismatch(gl); boolean sampleSinkSizeMismatch = sampleSinkSizeMismatch(); - boolean sampleSinkTexMismatch = sampleSinkTexMismatch(); boolean sampleSinkDepthStencilMismatch = sampleSinkDepthStencilMismatch(); + boolean sampleColorsinkUninit = sampleColorsinkUninit(); - /** if(DEBUG) { - System.err.println("FBObject.resetSamplingSink.0: \n\tTHIS "+this+",\n\tSINK "+samplesSink+ - "\n\t format "+sampleSinkFormatMismatch+", size "+sampleSinkSizeMismatch +", tex "+sampleSinkTexMismatch +", depthStencil "+sampleSinkDepthStencilMismatch); - } */ - - if(!sampleSinkFormatMismatch && !sampleSinkSizeMismatch && !sampleSinkTexMismatch && !sampleSinkDepthStencilMismatch) { + if(!sampleSinkFormatMismatch && !sampleSinkSizeMismatch && !sampleColorsinkUninit && !sampleSinkDepthStencilMismatch) { + if(DEBUG) { + System.err.println("FBObject.resetSamplingSink.X2: Matching: format "+!sampleSinkFormatMismatch+", size "+!sampleSinkSizeMismatch +", csUninit "+!sampleColorsinkUninit +", depthStencil "+!sampleSinkDepthStencilMismatch); + } // all properties match .. return; } @@ -2072,27 +2171,36 @@ public class FBObject { unbind(gl); if(DEBUG) { - System.err.println("FBObject.resetSamplingSink: BEGIN\n\tTHIS "+this+",\n\tSINK "+samplingSink+ - "\n\t format "+sampleSinkFormatMismatch+", size "+sampleSinkSizeMismatch +", tex "+sampleSinkTexMismatch +", depthStencil "+sampleSinkDepthStencilMismatch); + System.err.println("FBObject.resetSamplingSink.2: Mismatch. Matching: format "+!sampleSinkFormatMismatch+", size "+!sampleSinkSizeMismatch +", csUninit "+!sampleColorsinkUninit +", depthStencil "+!sampleSinkDepthStencilMismatch); + Thread.dumpStack(); } if( sampleSinkDepthStencilMismatch ) { samplingSink.detachAllRenderbuffer(gl); } + final Colorbuffer preSamplingColorSink = samplingColorSink; + final boolean samplingColorSinkShallBeTA = null == preSamplingColorSink || preSamplingColorSink.isTextureAttachment(); + if( sampleSinkFormatMismatch ) { samplingSink.detachAllColorbuffer(gl); - samplingSinkTexture = null; + samplingColorSink = null; } else if( sampleSinkSizeMismatch ) { samplingSink.reset(gl, width, height); } - if(null == samplingSinkTexture) { + if(null == samplingColorSink) { final boolean hasAlpha = hasAttachmentUsingAlpha(); - samplingSinkTexture = samplingSink.attachTexture2D(gl, 0, hasAlpha); - } else if( 0 == samplingSinkTexture.getName() ) { - samplingSinkTexture.setSize(width, height); - samplingSink.attachColorbuffer(gl, 0, samplingSinkTexture); + if( samplingColorSinkShallBeTA ) { + samplingColorSink = samplingSink.attachTexture2D(gl, 0, hasAlpha); + } else { + samplingColorSink = samplingSink.attachColorbuffer(gl, 0, hasAlpha); + } + } else if( 0 == samplingColorSink.getName() ) { + // final boolean dispose = true; + // detachColorbufferImpl(gl, 0, dispose ? DetachAction.DISPOSE : DetachAction.NONE); + ((Attachment)samplingColorSink).setSize(width, height); + samplingSink.attachColorbuffer(gl, 0, samplingColorSink); } if( sampleSinkDepthStencilMismatch ) { @@ -2104,16 +2212,16 @@ public class FBObject { sampleSinkFormatMismatch = sampleSinkFormatMismatch(gl); sampleSinkSizeMismatch = sampleSinkSizeMismatch(); - sampleSinkTexMismatch = sampleSinkTexMismatch(); sampleSinkDepthStencilMismatch = sampleSinkDepthStencilMismatch(); - if(sampleSinkFormatMismatch || sampleSinkSizeMismatch || sampleSinkTexMismatch || sampleSinkDepthStencilMismatch) { + sampleColorsinkUninit = sampleColorsinkUninit(); + if(sampleSinkFormatMismatch || sampleSinkSizeMismatch || sampleColorsinkUninit || sampleSinkDepthStencilMismatch) { throw new InternalError("Samples sink mismatch after reset: \n\tTHIS "+this+",\n\t SINK "+samplingSink+ - "\n\t format "+sampleSinkFormatMismatch+", size "+sampleSinkSizeMismatch +", tex "+sampleSinkTexMismatch +", depthStencil "+sampleSinkDepthStencilMismatch); + "\n\t Mismatch. Matching: format "+!sampleSinkFormatMismatch+", size "+!sampleSinkSizeMismatch +", csUninit "+!sampleColorsinkUninit +", depthStencil "+!sampleSinkDepthStencilMismatch); } if(DEBUG) { - System.err.println("FBObject.resetSamplingSink: END\n\tTHIS "+this+",\n\tSINK "+samplingSink+ - "\n\t format "+sampleSinkFormatMismatch+", size "+sampleSinkSizeMismatch +", tex "+sampleSinkTexMismatch +", depthStencil "+sampleSinkDepthStencilMismatch); + System.err.println("FBObject.resetSamplingSink.XX: END\n\tTHIS "+this+",\n\tSINK "+samplingSink+ + "\n\t Matching: format "+!sampleSinkFormatMismatch+", size "+!sampleSinkSizeMismatch +", csUninit "+!sampleColorsinkUninit +", depthStencil "+!sampleSinkDepthStencilMismatch); } } @@ -2127,13 +2235,13 @@ public class FBObject { final FBObject prev = samplingSink; if( null == newSamplingSink) { samplingSink = null; - samplingSinkTexture = null; + samplingColorSink = null; } else if( samples > 0 ) { if( newSamplingSink.getNumSamples() > 0 ) { throw new GLException("SamplingSink FBO cannot use MSAA itself: "+newSamplingSink); } samplingSink = newSamplingSink; - samplingSinkTexture = (TextureAttachment) newSamplingSink.getColorbuffer(0); + samplingColorSink = newSamplingSink.getColorbuffer(0); } else { throw new GLException("Setting SamplingSink for non MSAA FBO not allowed: "+this); } @@ -2222,7 +2330,7 @@ public class FBObject { /** * If multisampling is being used and flagged dirty by a previous call of {@link #bind(GL)} or after initialization, - * the msaa-buffers are sampled to it's sink {@link #getSamplingSink()}. + * the msaa-buffers are sampled to it's sink {@link #getSamplingTextureSink()}. * <p> * Method also resets the sampling sink configuration via {@link #resetSamplingSink(GL)} if used and required. * </p> @@ -2267,22 +2375,24 @@ public class FBObject { } /** - * Bind the given texture colorbuffer. + * {@link #syncSamplingSink(GL) Synchronize the sampling sink} and bind the given {@link TextureAttachment}, if not <code>null</code>. * - * <p>If using multiple texture units, ensure you call {@link GL#glActiveTexture(int)} first!</p> + * <p>If using a {@link TextureAttachment} and multiple texture units, ensure you call {@link GL#glActiveTexture(int)} first!</p> * * <p>{@link #syncSamplingSink(GL)} is being called</p> * * <p>Leaves the FBO unbound!</p> * * @param gl the current GL context - * @param ta {@link TextureAttachment} to use, prev. attached w/ {@link #attachTexture2D(GL, int, boolean, int, int, int, int) attachTexture2D(..)} + * @param ta {@link TextureAttachment} to use, prev. attached w/ {@link #attachTexture2D(GL, int, boolean, int, int, int, int) attachTexture2D(..)}, + * may be <code>null</code> in case no {@link TextureAttachment} is used. * @throws IllegalArgumentException */ public final void use(final GL gl, final TextureAttachment ta) throws IllegalArgumentException { - if(null == ta) { throw new IllegalArgumentException("Null TextureAttachment, this: "+toString()); } syncSamplingSink(gl); - gl.glBindTexture(GL.GL_TEXTURE_2D, ta.getName()); // use it .. + if( null != ta ) { + gl.glBindTexture(GL.GL_TEXTURE_2D, ta.getName()); // use it .. + } } /** @@ -2369,8 +2479,10 @@ public class FBObject { /** Returns the framebuffer name to read from. Depending on multisampling, this may be a different framebuffer. */ public final int getReadFramebuffer() { return ( samples > 0 ) ? samplingSink.getReadFramebuffer() : fbName; } public final int getDefaultReadBuffer() { return GL.GL_COLOR_ATTACHMENT0; } - /** Return the number of color/texture attachments */ - public final int getColorAttachmentCount() { return colorAttachmentCount; } + /** Return the number of attached {@link Colorbuffer}s */ + public final int getColorbufferCount() { return colorbufferCount; } + /** Return the number of attached {@link TextureAttachment}s */ + public final int getTextureAttachmentCount() { return textureAttachmentCount; } /** Return the stencil {@link RenderAttachment} attachment, if exist. Maybe share the same {@link Attachment#getName()} as {@link #getDepthAttachment()}, if packed depth-stencil is being used. */ public final RenderAttachment getStencilAttachment() { return stencil; } /** Return the depth {@link RenderAttachment} attachment. Maybe share the same {@link Attachment#getName()} as {@link #getStencilAttachment()}, if packed depth-stencil is being used. */ @@ -2379,8 +2491,9 @@ public class FBObject { /** Return the complete multisampling {@link FBObject} sink, if using multisampling. */ public final FBObject getSamplingSinkFBO() { return samplingSink; } - /** Return the multisampling {@link TextureAttachment} sink, if using multisampling. */ - public final TextureAttachment getSamplingSink() { return samplingSinkTexture; } + /** Return the multisampling {@link Colorbuffer} sink, if using multisampling. */ + public final Colorbuffer getSamplingSink() { return samplingColorSink; } + /** * Returns <code>true</code> if the multisampling colorbuffer (msaa-buffer) * has been flagged dirty by a previous call of {@link #bind(GL)}, @@ -2392,11 +2505,11 @@ public class FBObject { @Override public final String toString() { - final String caps = null != colorAttachmentPoints ? Arrays.asList(colorAttachmentPoints).toString() : null ; + final String caps = null != colorbufferAttachments ? Arrays.asList(colorbufferAttachments).toString() : null ; return "FBO[name r/w "+fbName+"/"+getReadFramebuffer()+", init "+initialized+", bound "+bound+", size "+width+"x"+height+ ", samples "+samples+"/"+maxSamples+", depth "+depth+", stencil "+stencil+ - ", color attachments: "+colorAttachmentCount+"/"+maxColorAttachments+ - ": "+caps+", msaa["+samplingSinkTexture+", hasSink "+(null != samplingSink)+ + ", colorbuffer attachments: "+colorbufferCount+"/"+maxColorAttachments+", with "+textureAttachmentCount+" textures"+ + ": "+caps+", msaa["+samplingColorSink+", hasSink "+(null != samplingSink)+ ", dirty "+samplingSinkDirty+"], state "+getStatusString()+", obj "+toHexString(objectHashCode())+"]"; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java index 0801b65fa..c9445b74f 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java @@ -105,7 +105,7 @@ public class StereoClientRenderer implements GLEventListener { } fbos[i].setSamplingSink(ssink); fbos[i].resetSamplingSink(gl); // validate - fboTexs[i] = fbos[i].getSamplingSink(); + fboTexs[i] = fbos[i].getSamplingSink().getTextureAttachment(); } else { fboTexs[i] = fbos[i].attachTexture2D(gl, 0, false, magFilter, minFilter, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE); fbos[i].attachRenderbuffer(gl, Type.DEPTH, 24); @@ -125,9 +125,9 @@ public class StereoClientRenderer implements GLEventListener { } numSamples = fbos[i].getNumSamples(); if(numSamples>0) { - fboTexs[i] = fbos[i].getSamplingSink(); + fboTexs[i] = fbos[i].getSamplingSink().getTextureAttachment(); } else { - fboTexs[i] = (TextureAttachment) fbos[i].getColorbuffer(0); + fboTexs[i] = fbos[i].getColorbuffer(0).getTextureAttachment(); } } } diff --git a/src/jogl/classes/javax/media/opengl/GLFBODrawable.java b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java index a34fca0fa..f423e0ee4 100644 --- a/src/jogl/classes/javax/media/opengl/GLFBODrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLFBODrawable.java @@ -31,6 +31,8 @@ package javax.media.opengl; import javax.media.nativewindow.NativeWindowException; import com.jogamp.opengl.FBObject; +import com.jogamp.opengl.FBObject.Colorbuffer; +import com.jogamp.opengl.FBObject.ColorAttachment; import com.jogamp.opengl.FBObject.TextureAttachment; /** @@ -62,12 +64,12 @@ import com.jogamp.opengl.FBObject.TextureAttachment; * </p> * <p> * It would be possible to implement double buffering simply using - * {@link TextureAttachment}s with one {@link FBObject framebuffer}. + * {@link Colorbuffer}s with one {@link FBObject framebuffer}. * This would require mode selection and hence complicate the API. Besides, it would * not support differentiation of read and write framebuffer and hence not be spec compliant. * </p> * <p> - * Actual swapping of the {@link TextureAttachment texture}s and/or {@link FBObject framebuffer} + * Actual swapping of the {@link Colorbuffer}s and/or {@link FBObject framebuffer} * is performed either in the {@link jogamp.opengl.GLContextImpl#contextMadeCurrent(boolean) context current hook} * or when {@link jogamp.opengl.GLDrawableImpl#swapBuffersImpl(boolean) swapping buffers}, whatever comes first. * </p> @@ -75,19 +77,43 @@ import com.jogamp.opengl.FBObject.TextureAttachment; public interface GLFBODrawable extends GLDrawable { // public enum DoubleBufferMode { NONE, TEXTURE, FBO }; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support + /** FBO Mode Bit: Use a {@link TextureAttachment} for the {@link #getColorbuffer(int) render colorbuffer} ({@link #FBOMODE_DEFAULT default}), see {@link #setFBOMode(int)}. */ + public static final int FBOMODE_USE_TEXTURE = 1 << 0; + /** FBO Mode Bit: Use a depth renderbuffer ({@link #FBOMODE_DEFAULT default}), see {@link #setFBOMode(int)}. */ + public static final int FBOMODE_USE_DEPTH = 1 << 1; + + /** FBO Default Mode Bit: {@link #FBOMODE_USE_TEXTURE} | {@link #FBOMODE_USE_DEPTH}. */ + public static final int FBOMODE_DEFAULT = FBOMODE_USE_TEXTURE | FBOMODE_USE_DEPTH; + /** * @return <code>true</code> if initialized, i.e. a {@link GLContext} is bound and made current once, otherwise <code>false</code>. */ public boolean isInitialized(); /** + * Set the FBO mode bits used for FBO creation. + * <p> + * See {@link #FBOMODE_DEFAULT} values. + * </p> + * + * @param modeBits custom FBO mode bits like {@link #FBOMODE_USE_TEXTURE} and {@link #FBOMODE_USE_DEPTH}. + * @throws IllegalStateException if the underlying FBO is already {@link #isInitialized()}. + */ + void setFBOMode(final int modeBits) throws IllegalStateException; + + /** + * @return the used FBO mode bits, mutable via {@link #setFBOMode(int)} + */ + int getFBOMode(); + + /** * Notify this instance about upstream size change * to reconfigure the {@link FBObject}. * @param gl GL context object bound to this drawable, will be made current during operation. * A prev. current context will be make current after operation. * @throws GLException if resize operation failed */ - void resetSize(GL gl) throws GLException; + void resetSize(final GL gl) throws GLException; /** * @return the used texture unit @@ -98,7 +124,7 @@ public interface GLFBODrawable extends GLDrawable { * * @param unit the texture unit to be used */ - void setTextureUnit(int unit); + void setTextureUnit(final int unit); /** * Set the number of sample buffers if using MSAA @@ -108,7 +134,7 @@ public interface GLFBODrawable extends GLDrawable { * @param newSamples new sample size * @throws GLException if resetting the FBO failed */ - void setNumSamples(GL gl, int newSamples) throws GLException; + void setNumSamples(final GL gl, final int newSamples) throws GLException; /** * @return the number of sample buffers if using MSAA, otherwise 0 @@ -126,7 +152,7 @@ public interface GLFBODrawable extends GLDrawable { * @return the new number of buffers (FBO) used, maybe different than the requested <code>bufferCount</code> (see above) * @throws GLException if already initialized, see {@link #isInitialized()}. */ - int setNumBuffers(int bufferCount) throws GLException; + int setNumBuffers(final int bufferCount) throws GLException; /** * @return the number of buffers (FBO) being used. 1 if not using {@link GLCapabilities#getDoubleBuffered() double buffering}, @@ -162,19 +188,24 @@ public interface GLFBODrawable extends GLDrawable { * @return the named {@link FBObject} * @throws IllegalArgumentException if an illegal buffer name is being used */ - FBObject getFBObject(int bufferName) throws IllegalArgumentException; + FBObject getFBObject(final int bufferName) throws IllegalArgumentException; /** - * Returns the named texture buffer. + * Returns the named {@link Colorbuffer} instance. * <p> * If MSAA is being used, only the {@link GL#GL_FRONT} buffer is accessible * and an exception is being thrown if {@link GL#GL_BACK} is being requested. * </p> + * <p> + * Depending on the {@link #setFBOMode(int) fbo mode} the resulting {@link Colorbuffer} + * is either a {@link TextureAttachment} ({@link #FBOMODE_DEFAULT default}) or a {@link ColorAttachment}, + * see {@link Colorbuffer#isTextureAttachment()}. + * </p> * @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names - * @return the named {@link TextureAttachment} + * @return the named {@link Colorbuffer} * @throws IllegalArgumentException if using MSAA and {@link GL#GL_BACK} is requested or an illegal buffer name is being used */ - FBObject.TextureAttachment getTextureBuffer(int bufferName) throws IllegalArgumentException; + Colorbuffer getColorbuffer(final int bufferName) throws IllegalArgumentException; /** Resizeable {@link GLFBODrawable} specialization */ public interface Resizeable extends GLFBODrawable { diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index f0ba08c3e..40fc1001f 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -1812,7 +1812,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // perform vert-flipping via OpenGL/FBO final GLFBODrawable fboDrawable = (GLFBODrawable)offscreenDrawable; - final FBObject.TextureAttachment fboTex = fboDrawable.getTextureBuffer(GL.GL_FRONT); + final FBObject.TextureAttachment fboTex = fboDrawable.getColorbuffer(GL.GL_FRONT).getTextureAttachment(); fboFlipped.bind(gl); diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PMSAAES2.java index fa81e2a3f..ca50b5d2d 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 @@ -457,7 +457,10 @@ public class VBORegion2PMSAAES2 extends GLRegion { fbo.reset(gl, fboWidth, fboHeight, sampleCount[0], false); 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, 24); + } final FBObject ssink = new FBObject(); { ssink.reset(gl, fboWidth, fboHeight); diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 6046527d1..2d0f8f70b 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -51,6 +51,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { private GLCapabilitiesImmutable origParentChosenCaps; private boolean initialized; + private int fboModeBits; private int texUnit; private int samples; private boolean fboResetQuirk; @@ -89,6 +90,7 @@ 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 | FBOMODE_USE_DEPTH; this.parent = parent; this.origParentChosenCaps = getChosenGLCapabilities(); // just to avoid null, will be reset at initialize(..) @@ -138,25 +140,56 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { fboIBack = 0; // head fboIFront = fbos.length - 1; // tail + final boolean useTexture = 0 != ( FBOMODE_USE_TEXTURE & fboModeBits ); + final boolean useDepth = 0 != ( FBOMODE_USE_DEPTH & fboModeBits ); + final boolean useStencil = chosenFBOCaps.getStencilBits() > 0; + final boolean useAlpha = chosenFBOCaps.getAlphaBits() > 0; + final int width = getSurfaceWidth(); + final int height = getSurfaceHeight(); + for(int i=0; i<fbosN; i++) { fbos[i] = new FBObject(); - fbos[i].reset(gl, getSurfaceWidth(), getSurfaceHeight(), samples, false); + fbos[i].reset(gl, width, height, 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); + if(samples > 0 || !useTexture) { + fbos[i].attachColorbuffer(gl, 0, useAlpha); } else { - fbos[i].attachTexture2D(gl, 0, chosenFBOCaps.getAlphaBits()>0); + fbos[i].attachTexture2D(gl, 0, useAlpha); } - if( chosenFBOCaps.getStencilBits() > 0 ) { - fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); - } else { + if( useStencil ) { + if( useDepth ) { + fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); + } else { + fbos[i].attachRenderbuffer(gl, Attachment.Type.STENCIL, 24); + } + } else if( useDepth ) { fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); } + if(samples > 0) { + final FBObject ssink = new FBObject(); + { + ssink.reset(gl, width, height); + if( !useTexture ) { + ssink.attachColorbuffer(gl, 0, useAlpha); + } else { + ssink.attachTexture2D(gl, 0, useAlpha); + } + if( useStencil ) { + if( useDepth ) { + ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); + } else { + ssink.attachRenderbuffer(gl, Attachment.Type.STENCIL, 24); + } + } else if( useDepth ) { + ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + } + } + fbos[i].setSamplingSink(ssink); + fbos[i].resetSamplingSink(gl); // validate + } } - fbos[fboIFront].resetSamplingSink(gl); - fbos[0].formatToGLCapabilities(chosenFBOCaps); chosenFBOCaps.setDoubleBuffered( chosenFBOCaps.getDoubleBuffered() || samples > 0 ); } else { @@ -414,17 +447,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 +479,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); } @@ -519,24 +564,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..60cc9f0fd 100644 --- a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java @@ -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/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; |