From 1d8afa983869d984a4df1f0fa8d34c52d847bf20 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 17 Dec 2012 02:33:05 +0000 Subject: [PATCH] FBO layer is enabled when sketch tries to use the front texture (prev. frame) or shader filter --- android/core/src/processing/opengl/PGL.java | 161 +++++++++++++----- .../processing/opengl/PGraphicsOpenGL.java | 2 + core/src/processing/opengl/PGL.java | 111 ++++++------ .../processing/opengl/PGraphicsOpenGL.java | 2 + 4 files changed, 185 insertions(+), 91 deletions(-) diff --git a/android/core/src/processing/opengl/PGL.java b/android/core/src/processing/opengl/PGL.java index 5a40c200d..a84de383e 100644 --- a/android/core/src/processing/opengl/PGL.java +++ b/android/core/src/processing/opengl/PGL.java @@ -52,27 +52,18 @@ import android.opengl.GLU; * */ public class PGL { - public static final boolean USE_DIRECT_BUFFERS = false; - public static final int MIN_DIRECT_BUFFER_SIZE = 1; + + /////////////////////////////////////////////////////////// + + // Parameters + + public static boolean FORCE_SCREEN_FBO = false; + public static final boolean USE_DIRECT_BUFFERS = false; + public static final int MIN_DIRECT_BUFFER_SIZE = 1; public static final boolean SAVE_SURFACE_TO_PIXELS = false; - /** Size of a short (in bytes). */ - protected static final int SIZEOF_SHORT = Short.SIZE / 8; - - /** Size of an int (in bytes). */ - protected static final int SIZEOF_INT = Integer.SIZE / 8; - - /** Size of a float (in bytes). */ - protected static final int SIZEOF_FLOAT = Float.SIZE / 8; - - /** Size of a byte (in bytes). */ - protected static final int SIZEOF_BYTE = Byte.SIZE / 8; - - /** Size of a vertex index. */ - protected static final int SIZEOF_INDEX = SIZEOF_SHORT; - - /** Type of a vertex index. */ - protected static final int INDEX_TYPE = GLES20.GL_UNSIGNED_SHORT; + /** Enables/disables mipmap use. **/ + protected static final boolean MIPMAPS_ENABLED = false; /** Initial sizes for arrays of input and tessellated data. */ protected static final int DEFAULT_IN_VERTICES = 16; @@ -115,8 +106,12 @@ public class PGL { /** Minimum array size to use arrayCopy method(). **/ protected static final int MIN_ARRAYCOPY_SIZE = 2; - /** Enables/disables mipmap use. **/ - protected static final boolean MIPMAPS_ENABLED = false; + protected static final int SIZEOF_SHORT = Short.SIZE / 8; + protected static final int SIZEOF_INT = Integer.SIZE / 8; + protected static final int SIZEOF_FLOAT = Float.SIZE / 8; + protected static final int SIZEOF_BYTE = Byte.SIZE / 8; + protected static final int SIZEOF_INDEX = SIZEOF_SHORT; + protected static final int INDEX_TYPE = GLES20.GL_UNSIGNED_SHORT; /** Machine Epsilon for float precision. **/ protected static float FLOAT_EPS = Float.MIN_VALUE; @@ -145,7 +140,7 @@ public class PGL { "precision mediump int;\n" + "#endif\n"; - /////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////// // OpenGL constants @@ -349,11 +344,15 @@ public class PGL { // FBO layer - public static boolean FORCE_SCREEN_FBO = false; + protected static boolean fboLayerByDefault = FORCE_SCREEN_FBO; protected static boolean fboLayerCreated = false; protected static boolean fboLayerInUse = false; protected static boolean firstFrame = true; + protected static int reqNumSamples; + protected static int numSamples; protected static IntBuffer glColorFbo; + protected static IntBuffer glMultiFbo; + protected static IntBuffer glColorBuf; protected static IntBuffer glColorTex; protected static IntBuffer glDepthStencil; protected static IntBuffer glDepth; @@ -423,6 +422,8 @@ public class PGL { if (glColorTex == null) { glColorTex = allocateIntBuffer(2); glColorFbo = allocateIntBuffer(1); + glMultiFbo = allocateIntBuffer(1); + glColorBuf = allocateIntBuffer(1); glDepthStencil = allocateIntBuffer(1); glDepth = allocateIntBuffer(1); glStencil = allocateIntBuffer(1); @@ -442,10 +443,7 @@ public class PGL { protected void initSurface(int antialias) { - // We do the initialization in updatePrimary() because - // at the moment initPrimarySurface() gets called we - // cannot rely on the GL surface being actually - // available. + reqNumSamples = qualityToSamples(antialias); fboLayerCreated = false; fboLayerInUse = false; firstFrame = true; @@ -456,6 +454,8 @@ public class PGL { if (glColorTex != null) { deleteTextures(2, glColorTex); deleteFramebuffers(1, glColorFbo); + deleteFramebuffers(1, glMultiFbo); + deleteRenderbuffers(1, glColorBuf); deleteRenderbuffers(1, glDepthStencil); deleteRenderbuffers(1, glDepth); deleteRenderbuffers(1, glStencil); @@ -477,6 +477,13 @@ public class PGL { fboHeight = nextPowerOfTwo(pg.height); } + if (-1 < ext.indexOf("_framebuffer_multisample")) { + numSamples = reqNumSamples; + } else { + numSamples = 1; + } + boolean multisample = 1 < numSamples; + boolean packed = ext.indexOf("packed_depth_stencil") != -1; int depthBits = getDepthBits(); int stencilBits = getStencilBits(); @@ -502,18 +509,38 @@ public class PGL { framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, glColorTex.get(backTex), 0); + if (multisample) { + // Creating multisampled FBO + genFramebuffers(1, glMultiFbo); + bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); + + // color render buffer... + genRenderbuffers(1, glColorBuf); + bindRenderbuffer(RENDERBUFFER, glColorBuf.get(0)); + renderbufferStorageMultisample(RENDERBUFFER, numSamples, + RGBA8, fboWidth, fboHeight); + framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0, + RENDERBUFFER, glColorBuf.get(0)); + } + + // Creating depth and stencil buffers if (packed && depthBits == 24 && stencilBits == 8) { // packed depth+stencil buffer - genRenderbuffers(1, glDepthStencil); bindRenderbuffer(RENDERBUFFER, glDepthStencil.get(0)); - renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8, - fboWidth, fboHeight); + if (multisample) { + renderbufferStorageMultisample(RENDERBUFFER, numSamples, + DEPTH24_STENCIL8, fboWidth, fboHeight); + } else { + renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8, + fboWidth, fboHeight); + } framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, glDepthStencil.get(0)); framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER, glDepthStencil.get(0)); - } else { // separate depth and stencil buffers + } else { + // separate depth and stencil buffers if (0 < depthBits) { int depthComponent = DEPTH_COMPONENT16; if (depthBits == 32) { @@ -526,7 +553,13 @@ public class PGL { genRenderbuffers(1, glDepth); bindRenderbuffer(RENDERBUFFER, glDepth.get(0)); - renderbufferStorage(RENDERBUFFER, depthComponent, fboWidth, fboHeight); + if (multisample) { + renderbufferStorageMultisample(RENDERBUFFER, numSamples, + depthComponent, fboWidth, fboHeight); + } else { + renderbufferStorage(RENDERBUFFER, depthComponent, + fboWidth, fboHeight); + } framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, glDepth.get(0)); } @@ -543,19 +576,25 @@ public class PGL { genRenderbuffers(1, glStencil); bindRenderbuffer(RENDERBUFFER, glStencil.get(0)); - renderbufferStorage(RENDERBUFFER, stencilIndex, fboWidth, fboHeight); + if (multisample) { + renderbufferStorageMultisample(RENDERBUFFER, numSamples, + stencilIndex, fboWidth, fboHeight); + } else { + renderbufferStorage(RENDERBUFFER, stencilIndex, + fboWidth, fboHeight); + } framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER, glStencil.get(0)); } } + validateFramebuffer(); - // Clear the depth and stencil buffers in the color FBO. There is no - // need to clear the color buffers because the textures attached were - // properly initialized blank. + // Clear all buffers. clearDepth(1); clearStencil(0); - clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT); + clearColor(0, 0, 0, 0); + clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT); bindFramebuffer(FRAMEBUFFER, 0); @@ -605,6 +644,11 @@ public class PGL { } + protected void needFBOLayer() { + FORCE_SCREEN_FBO = true; + } + + protected boolean isMultisampled() { return false; } @@ -697,7 +741,24 @@ public class PGL { protected void syncBackTexture() { - // Nothing to do because there is no MSAA in GLES20 + if (1 < numSamples) { + bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); + bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); + blitFramebuffer(0, 0, fboWidth, fboHeight, + 0, 0, fboWidth, fboHeight, + COLOR_BUFFER_BIT, NEAREST); + } + } + + + protected int qualityToSamples(int quality) { + if (quality <= 1) { + return 1; + } else { + // Number of samples is always an even number: + int n = 2 * (quality / 2); + return n; + } } @@ -707,10 +768,15 @@ public class PGL { protected void beginDraw(boolean clear0) { - if ((!clear0 || FORCE_SCREEN_FBO) && glColorFbo.get(0) != 0) { + if (fboLayerInUse(clear0)) { bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, glColorTex.get(backTex), 0); + + if (1 < numSamples) { + bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); + } + if (firstFrame) { // No need to draw back color buffer because we are in the first frame. clearColor(0, 0, 0, 0); @@ -722,6 +788,7 @@ public class PGL { fboWidth, fboHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); } + fboLayerInUse = true; } else { fboLayerInUse = false; @@ -730,11 +797,21 @@ public class PGL { if (firstFrame) { firstFrame = false; } + + if (!fboLayerByDefault) { + // The result of this assignment is the following: if the user requested + // at some point the use of the FBO layer, but subsequently didn't do + // request it again, then the rendering won't use the FBO layer if not + // needed, since it is slower than simple onscreen rendering. + FORCE_SCREEN_FBO = false; + } } protected void endDraw(boolean clear) { if (fboLayerInUse) { + syncBackTexture(); + // Draw the contents of the back texture to the screen framebuffer. bindFramebuffer(FRAMEBUFFER, 0); @@ -772,6 +849,12 @@ public class PGL { } + protected boolean fboLayerInUse(boolean clear0) { + boolean cond = !clear0 || FORCE_SCREEN_FBO || 1 < numSamples; + return cond && glColorFbo.get(0) != 0; + } + + /////////////////////////////////////////////////////////// // Caps query diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 88f3de178..a08ee7313 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5365,6 +5365,7 @@ public class PGraphicsOpenGL extends PGraphics { return; } + pgl.needFBOLayer(); loadTexture(); if (filterTexture == null || filterTexture.contextIsOutdated()) { filterTexture = new Texture(parent, texture.width, texture.height, @@ -6511,6 +6512,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void unbind() { if (-1 < pframeSamplerLoc) { + pgl.needFBOLayer(); pgl.activeTexture(PGL.TEXTURE0 + lastTexUnit); pgCurrent.unbindBackTexture(); pgl.activeTexture(PGL.TEXTURE0); diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 2f8529cc6..9525a1899 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -72,32 +72,19 @@ import com.jogamp.opengl.util.AnimatorBase; */ @SuppressWarnings("static-access") public class PGL { - public static final boolean USE_JOGL_FBOLAYER = true; - public static final boolean USE_DIRECT_BUFFERS = true; - public static final int MIN_DIRECT_BUFFER_SIZE = 1; + + /////////////////////////////////////////////////////////// + + // Parameters + + public static final boolean USE_JOGL_FBOLAYER = false; + public static boolean FORCE_SCREEN_FBO = false; + public static final boolean USE_DIRECT_BUFFERS = true; + public static final int MIN_DIRECT_BUFFER_SIZE = 1; public static final boolean SAVE_SURFACE_TO_PIXELS = true; - // The two windowing toolkits available to use in JOGL: - protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing - protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html - - /** Size of a short (in bytes). */ - protected static final int SIZEOF_SHORT = Short.SIZE / 8; - - /** Size of an int (in bytes). */ - protected static final int SIZEOF_INT = Integer.SIZE / 8; - - /** Size of a float (in bytes). */ - protected static final int SIZEOF_FLOAT = Float.SIZE / 8; - - /** Size of a byte (in bytes). */ - protected static final int SIZEOF_BYTE = Byte.SIZE / 8; - - /** Size of a vertex index. */ - protected static final int SIZEOF_INDEX = SIZEOF_SHORT; - - /** Type of a vertex index. */ - protected static final int INDEX_TYPE = GL.GL_UNSIGNED_SHORT; + /** Enables/disables mipmap use. **/ + protected static final boolean MIPMAPS_ENABLED = true; /** Initial sizes for arrays of input and tessellated data. */ protected static final int DEFAULT_IN_VERTICES = 64; @@ -140,8 +127,30 @@ public class PGL { /** Minimum array size to use arrayCopy method(). **/ protected static final int MIN_ARRAYCOPY_SIZE = 2; - /** Enables/disables mipmap use. **/ - protected static final boolean MIPMAPS_ENABLED = true; + /** JOGL's windowing toolkit */ + // The two windowing toolkits available to use in JOGL: + protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing + protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html + protected static int toolkit = NEWT; + + /** Enables/disables use of animator */ + protected static boolean useAnimator = false; + + protected static boolean enable_screen_FBO_macosx = true; + protected static boolean enable_screen_FBO_windows = true; + protected static boolean enable_screen_FBO_linux = true; + protected static boolean enable_screen_FBO_other = true; + + protected static int request_depth_bits = 24; + protected static int request_stencil_bits = 8; + protected static int request_alpha_bits = 8; + + protected static final int SIZEOF_SHORT = Short.SIZE / 8; + protected static final int SIZEOF_INT = Integer.SIZE / 8; + protected static final int SIZEOF_FLOAT = Float.SIZE / 8; + protected static final int SIZEOF_BYTE = Byte.SIZE / 8; + protected static final int SIZEOF_INDEX = SIZEOF_SHORT; + protected static final int INDEX_TYPE = GL.GL_UNSIGNED_SHORT; /** Machine Epsilon for float precision. **/ protected static float FLOAT_EPS = Float.MIN_VALUE; @@ -356,9 +365,7 @@ public class PGL { /** Selected GL profile */ public static GLProfile profile; - /** OpenGL thread: - * TODO - * http://forum.processing.org/topic/2-x-pgraphics-thread-crash */ + /** OpenGL thread */ protected static Thread glThread; /** The PGraphics object using this interface */ @@ -377,21 +384,6 @@ public class PGL { * multisampled renerbuffers) */ protected static GL2 gl2x; - /** Windowing toolkit */ - protected static int toolkit = NEWT; - - /** Enables/disables use of animator */ - protected static boolean useAnimator = false; - - protected static boolean enable_screen_FBO_macosx = true; - protected static boolean enable_screen_FBO_windows = true; - protected static boolean enable_screen_FBO_linux = true; - protected static boolean enable_screen_FBO_other = true; - - protected static int request_depth_bits = 24; - protected static int request_stencil_bits = 8; - protected static int request_alpha_bits = 8; - /** The AWT-OpenGL canvas */ protected static GLCanvas canvasAWT; @@ -419,10 +411,9 @@ public class PGL { /////////////////////////////////////////////////////////// - // Objects for onscreen FBO-based rendering + // FBO layer - - public static boolean FORCE_SCREEN_FBO = false; + protected static boolean fboLayerByDefault = FORCE_SCREEN_FBO; protected static boolean fboLayerCreated = false; protected static boolean fboLayerInUse = false; protected static boolean firstFrame = true; @@ -438,9 +429,6 @@ public class PGL { protected static int fboWidth, fboHeight; protected static int backTex, frontTex; - protected static boolean needToClearBuffers; - - /** Back (== draw, current frame) buffer */ protected static FBObject backFBO; /** Sink buffer, used in the multisampled case */ @@ -450,6 +438,8 @@ public class PGL { protected static FBObject.TextureAttachment backTexAttach; protected static FBObject.TextureAttachment frontTexAttach; + protected static boolean needToClearBuffers; + /////////////////////////////////////////////////////////// // Texture rendering @@ -918,7 +908,11 @@ public class PGL { } else { return fboLayerInUse; } + } + + protected void needFBOLayer() { + FORCE_SCREEN_FBO = true; } @@ -1116,8 +1110,7 @@ public class PGL { protected void beginDraw(boolean clear0) { if (USE_JOGL_FBOLAYER) return; - if ((!clear0 || FORCE_SCREEN_FBO || 1 < numSamples) && - glColorFbo.get(0) != 0) { + if (fboLayerInUse(clear0)) { bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, glColorTex.get(backTex), 0); @@ -1146,6 +1139,14 @@ public class PGL { if (firstFrame) { firstFrame = false; } + + if (!fboLayerByDefault) { + // The result of this assignment is the following: if the user requested + // at some point the use of the FBO layer, but subsequently didn't do + // request it again, then the rendering won't use the FBO layer if not + // needed, since it is slower than simple onscreen rendering. + FORCE_SCREEN_FBO = false; + } } @@ -1224,6 +1225,12 @@ public class PGL { } + protected boolean fboLayerInUse(boolean clear0) { + boolean cond = !clear0 || FORCE_SCREEN_FBO || 1 < numSamples; + return cond && glColorFbo.get(0) != 0; + } + + ////////////////////////////////////////////////////////////////////////////// // Caps query diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 88f3de178..a08ee7313 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5365,6 +5365,7 @@ public class PGraphicsOpenGL extends PGraphics { return; } + pgl.needFBOLayer(); loadTexture(); if (filterTexture == null || filterTexture.contextIsOutdated()) { filterTexture = new Texture(parent, texture.width, texture.height, @@ -6511,6 +6512,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void unbind() { if (-1 < pframeSamplerLoc) { + pgl.needFBOLayer(); pgl.activeTexture(PGL.TEXTURE0 + lastTexUnit); pgCurrent.unbindBackTexture(); pgl.activeTexture(PGL.TEXTURE0);