diff --git a/android/core/src/processing/opengl/FrameBuffer.java b/android/core/src/processing/opengl/FrameBuffer.java index 27e0f87f5..253c61aa9 100644 --- a/android/core/src/processing/opengl/FrameBuffer.java +++ b/android/core/src/processing/opengl/FrameBuffer.java @@ -76,13 +76,17 @@ public class FrameBuffer implements PConstants { this(parent, w, h, 1, 1, 0, 0, false, screen); } - FrameBuffer(PApplet parent, int w, int h, int samples, int colorBuffers, - int depthBits, int stencilBits, boolean packedDepthStencil, - boolean screen) { + FrameBuffer(PApplet parent) { this.parent = parent; pg = (PGraphicsOpenGL)parent.g; pgl = pg.pgl; context = pgl.createEmptyContext(); + } + + FrameBuffer(PApplet parent, int w, int h, int samples, int colorBuffers, + int depthBits, int stencilBits, boolean packedDepthStencil, + boolean screen) { + this(parent); glFbo = 0; glDepth = 0; @@ -145,20 +149,22 @@ public class FrameBuffer implements PConstants { @Override protected void finalize() throws Throwable { try { - if (glFbo != 0) { - pg.finalizeFrameBufferObject(glFbo, context.id()); - } - if (glDepth != 0) { - pg.finalizeRenderBufferObject(glDepth, context.id()); - } - if (glStencil != 0) { - pg.finalizeRenderBufferObject(glStencil, context.id()); - } - if (glMultisample != 0) { - pg.finalizeRenderBufferObject(glMultisample, context.id()); - } - if (glDepthStencil != 0) { - pg.finalizeRenderBufferObject(glDepthStencil, context.id()); + if (!screenFb) { + if (glFbo != 0) { + pg.finalizeFrameBufferObject(glFbo, context.id()); + } + if (glDepth != 0) { + pg.finalizeRenderBufferObject(glDepth, context.id()); + } + if (glStencil != 0) { + pg.finalizeRenderBufferObject(glStencil, context.id()); + } + if (glMultisample != 0) { + pg.finalizeRenderBufferObject(glMultisample, context.id()); + } + if (glDepthStencil != 0) { + pg.finalizeRenderBufferObject(glDepthStencil, context.id()); + } } } finally { super.finalize(); @@ -230,6 +236,12 @@ public class FrameBuffer implements PConstants { return 0 < stencilBits; } + public void setFBO(int id) { + if (screenFb) { + glFbo = id; + } + } + /////////////////////////////////////////////////////////// // Color buffer setters. @@ -278,6 +290,27 @@ public class FrameBuffer implements PConstants { } + public void swapColorBuffers() { + for (int i = 0; i < numColorBuffers - 1; i++) { + int i1 = (i + 1); + Texture tmp = colorBufferTex[i]; + colorBufferTex[i] = colorBufferTex[i1]; + colorBufferTex[i1] = tmp; + } + + pg.pushFramebuffer(); + pg.setFramebuffer(this); + for (int i = 0; i < numColorBuffers; i++) { + pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0 + i, + colorBufferTex[i].glTarget, + colorBufferTex[i].glName, 0); + } + pgl.validateFramebuffer(); + + pg.popFramebuffer(); + } + + /////////////////////////////////////////////////////////// // Allocate/release framebuffer. @@ -291,28 +324,31 @@ public class FrameBuffer implements PConstants { if (screenFb) { glFbo = 0; } else { + //create the FBO object... glFbo = pg.createFrameBufferObject(context.id()); - } - // create the rest of the stuff... - if (multisample) { - createColorBufferMultisample(); - } - - if (packedDepthStencil) { - createPackedDepthStencilBuffer(); - } else { - if (0 < depthBits) { - createDepthBuffer(); + // ... and then create the rest of the stuff. + if (multisample) { + createColorBufferMultisample(); } - if (0 < stencilBits) { - createStencilBuffer(); + + if (packedDepthStencil) { + createPackedDepthStencilBuffer(); + } else { + if (0 < depthBits) { + createDepthBuffer(); + } + if (0 < stencilBits) { + createStencilBuffer(); + } } } } protected void release() { + if (screenFb) return; + if (glFbo != 0) { pg.finalizeFrameBufferObject(glFbo, context.id()); glFbo = 0; @@ -337,6 +373,8 @@ public class FrameBuffer implements PConstants { protected boolean contextIsOutdated() { + if (screenFb) return false; + boolean outdated = !pgl.contextIsCurrent(context); if (outdated) { pg.removeFrameBufferObject(glFbo, context.id()); diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 357b1786c..43594fe00 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -386,8 +386,8 @@ public class PGraphicsOpenGL extends PGraphics { /** Used to create a temporary copy of the color buffer of this * rendering surface when applying a filter */ - protected Texture textureCopy; - protected PImage imageCopy; +// protected Texture textureCopy; +// protected PImage imageCopy; /** IntBuffer wrapping the pixels array. */ protected IntBuffer pixelBuffer; @@ -1149,8 +1149,10 @@ public class PGraphicsOpenGL extends PGraphics { protected void setFramebuffer(FrameBuffer fbo) { - currentFramebuffer = fbo; - currentFramebuffer.bind(); + if (currentFramebuffer != fbo) { + currentFramebuffer = fbo; + currentFramebuffer.bind(); + } } @@ -1159,9 +1161,12 @@ public class PGraphicsOpenGL extends PGraphics { throw new RuntimeException("popFramebuffer call is unbalanced."); } fbStackDepth--; - currentFramebuffer.finish(); - currentFramebuffer = fbStack[fbStackDepth]; - currentFramebuffer.bind(); + FrameBuffer fbo = fbStack[fbStackDepth]; + if (currentFramebuffer != fbo) { + currentFramebuffer.finish(); + currentFramebuffer = fbo; + currentFramebuffer.bind(); + } } @@ -3299,9 +3304,13 @@ public class PGraphicsOpenGL extends PGraphics { smooth = true; if (maxSamples < level) { - PGraphics.showWarning("Smooth level " + level + - " is not supported by the hardware. Using " + - maxSamples + " instead."); + if (0 < maxSamples) { + PGraphics.showWarning("Smooth level " + level + + " is not available. Using " + + maxSamples + " instead."); + } else{ + PGraphics.showWarning("Smooth is not available."); + } level = maxSamples; } @@ -5423,20 +5432,6 @@ public class PGraphicsOpenGL extends PGraphics { if (offscreenMultisample) { offscreenFramebufferMultisample.copy(offscreenFramebuffer); } - - // Make the offscreen color buffer opaque so it doesn't show - // the background when drawn on the main surface. - if (offscreenMultisample) { - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - pgl.colorMask(false, false, false, true); - pgl.clearColor(0, 0, 0, 1); - pgl.clear(PGL.COLOR_BUFFER_BIT); - pgl.colorMask(true, true, true, true); - if (offscreenMultisample) { - popFramebuffer(); - } } if (needEndDraw) { @@ -5663,6 +5658,7 @@ public class PGraphicsOpenGL extends PGraphics { loadTexture(); +/* if (textureCopy == null || textureCopy.width != width || textureCopy.height != height) { Texture.Parameters params = new Texture.Parameters(ARGB, Texture.POINT, @@ -5673,6 +5669,7 @@ public class PGraphicsOpenGL extends PGraphics { } textureCopy.set(texture.glTarget, texture.glName, texture.glWidth, texture.glHeight, width, height); +*/ // Disable writing to the depth buffer, so that after applying the filter we // can still use the depth information to keep adding geometry to the scene. @@ -5681,21 +5678,23 @@ public class PGraphicsOpenGL extends PGraphics { // that has been drawn before. pgl.disable(PGL.DEPTH_TEST); - PolyTexShader prevTexShader = polyTexShader; - polyTexShader = (PolyTexShader) shader; + // Drawing a textured quad in 2D, covering the entire screen, + // with the filter shader applied to it: + begin2D(); + // Changing light configuration and shader after begin2D() + // because it calls flush(). boolean prevLights = lights; lights = false; int prevTextureMode = textureMode; textureMode = NORMAL; boolean prevStroke = stroke; stroke = false; - - // Drawing a textured quad in 2D, covering the entire screen, - // with the filter shader applied to it: - begin2D(); + PolyTexShader prevTexShader = polyTexShader; + polyTexShader = (PolyTexShader) shader; beginShape(QUADS); - texture(imageCopy); + //texture(imageCopy); + texture(this); vertex(0, 0, 0, 0); vertex(width, 0, 1, 0); vertex(width, height, 1, 1); @@ -5703,13 +5702,13 @@ public class PGraphicsOpenGL extends PGraphics { endShape(); end2D(); + polyTexShader = prevTexShader; + // Restoring previous configuration. stroke = prevStroke; lights = prevLights; textureMode = prevTextureMode; - polyTexShader = prevTexShader; - if (!hints[DISABLE_DEPTH_TEST]) { pgl.enable(PGL.DEPTH_TEST); } @@ -6096,10 +6095,7 @@ public class PGraphicsOpenGL extends PGraphics { int major = pgl.getGLVersion()[0]; if (major < 2) { - // There might be problems... - PGraphics.showWarning("The OpenGL version is less than 2.0 so " + - "Processing might not draw properly"); - // ... but GLSL might still be available through extensions. + // GLSL might still be available through extensions. if (OPENGL_EXTENSIONS.indexOf("_fragment_shader") == -1 || OPENGL_EXTENSIONS.indexOf("_vertex_shader") == -1 || OPENGL_EXTENSIONS.indexOf("_shader_objects") == -1 || diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 1171b64e1..cdd738027 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -45,7 +45,6 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; -import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLCanvas; import javax.media.opengl.glu.GLU; @@ -57,7 +56,6 @@ import processing.core.PConstants; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; -import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.AnimatorBase; /** @@ -398,14 +396,6 @@ public class PGL { // FBO for anti-aliased rendering - protected int drawTexName; - protected int drawTexWidth, drawTexHeight; - protected FBObject drawFBO; - - /* - protected static final boolean ENABLE_OSX_SCREEN_FBO = false; - protected static final int MIN_OSX_VER_FOR_SCREEN_FBO = 6; - protected static final int MIN_SAMPLES_FOR_SCREEN_FBO = 1; protected boolean needScreenFBO = false; protected int fboWidth, fboHeight; protected int numSamples; @@ -420,7 +410,6 @@ public class PGL { protected int[] glDepthBuffer = { 0 }; protected int[] glStencilBuffer = { 0 }; protected int contextHashCode; -*/ /////////////////////////////////////////////////////////// @@ -521,6 +510,16 @@ public class PGL { protected void initPrimarySurface(int antialias) { + if (PApplet.platform == PConstants.MACOSX) { + needScreenFBO = enable_screen_FBO_macosx; + } else if (PApplet.platform == PConstants.WINDOWS) { + needScreenFBO = enable_screen_FBO_windows; + } else if (PApplet.platform == PConstants.LINUX) { + needScreenFBO = enable_screen_FBO_linux; + } else { + needScreenFBO = enable_screen_FBO_other; + } + if (profile == null) { profile = GLProfile.getDefault(); } else { @@ -541,23 +540,13 @@ public class PGL { // Setting up the desired GL capabilities; GLCapabilities caps = new GLCapabilities(profile); - if (1 < antialias) { + if (1 < antialias && !needScreenFBO) { caps.setSampleBuffers(true); caps.setNumSamples(antialias); } else { caps.setSampleBuffers(false); } - if (PApplet.platform == PConstants.MACOSX) { - caps.setFBO(enable_screen_FBO_macosx); - } else if (PApplet.platform == PConstants.WINDOWS) { - caps.setFBO(enable_screen_FBO_windows); - } else if (PApplet.platform == PConstants.LINUX) { - caps.setFBO(enable_screen_FBO_linux); - } else { - caps.setFBO(enable_screen_FBO_other); - } - caps.setDepthBits(24); caps.setStencilBits(8); caps.setAlphaBits(8); @@ -614,8 +603,183 @@ public class PGL { if (!setFramerate) { setFrameRate(targetFramerate); } + + if (needScreenFBO && glColorFbo[0] == 0) { + + + String ext = gl.glGetString(GL.GL_EXTENSIONS); + if (-1 < ext.indexOf("texture_non_power_of_two")) { + fboWidth = pg.width; + fboHeight = pg.height; + } else { + fboWidth = PGL.nextPowerOfTwo(pg.width); + fboHeight = PGL.nextPowerOfTwo(pg.height); + } + + if (-1 < ext.indexOf("_framebuffer_multisample")) { + numSamples = qualityToSamples(pg.quality); + } else { + numSamples = 1; + } + multisample = 1 < numSamples; + + if (multisample && gl2x == null) { + throw new RuntimeException("Doesn't have the OpenGL extensions " + + "necessary for multisampling."); + } + packedDepthStencil = ext.indexOf("packed_depth_stencil") != -1; + + contextHashCode = context.hashCode(); + + // Create the color texture... + gl.glGenTextures(2, glColorTex, 0); +// for (int i = 0; i < 2; i++) { // Don't create back-buffer for now. + for (int i = 0; i < 1; i++) { + gl.glBindTexture(GL.GL_TEXTURE_2D, glColorTex[i]); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, + GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, + GL.GL_CLAMP_TO_EDGE); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, fboWidth, fboHeight, + 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null); + initTexture(GL.GL_TEXTURE_2D, PGL.RGBA, fboWidth, fboHeight); + } + gl.glBindTexture(GL.GL_TEXTURE_2D, 0); + + // ...and attach to the color framebuffer. + gl.glGenFramebuffers(1, glColorFbo, 0); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, + GL.GL_TEXTURE_2D, glColorTex[0], 0); + + if (multisample) { + // Now, creating mutisampled FBO with packed depth and stencil buffers. + gl.glGenFramebuffers(1, glMultiFbo, 0); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glMultiFbo[0]); + + // color render buffer... + gl.glGenRenderbuffers(1, glColorRenderBuffer, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glColorRenderBuffer[0]); + gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, + GL.GL_RGBA8, fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, + GL.GL_RENDERBUFFER, glColorRenderBuffer[0]); + + if (packedDepthStencil) { + // packed depth+stencil buffer... + gl.glGenRenderbuffers(1, glPackedDepthStencil, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glPackedDepthStencil[0]); + gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, + GL.GL_DEPTH24_STENCIL8, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, + glPackedDepthStencil[0]); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, + glPackedDepthStencil[0]); + } else { + // Separate depth and stencil buffers... + gl.glGenRenderbuffers(1, glDepthBuffer, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBuffer[0]); + gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, + GL.GL_DEPTH_COMPONENT24, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, + glDepthBuffer[0]); + + // Some hardware doesn't support distinct depth and stencil buffers: + // http://lists.apple.com/archives/mac-opengl/2008/Aug/msg00089.html + // which just results in an unsupported framebuffer error. + gl.glGenRenderbuffers(1, glStencilBuffer, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBuffer[0]); + gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, + GL.GL_STENCIL_INDEX8, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, + glStencilBuffer[0]); + } + validateFramebuffer(); + + // Clear all the buffers in the multisample FBO + gl.glClearDepth(1); + gl.glClearStencil(0); + gl.glClearColor(0, 0, 0, 0); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT | + GL.GL_STENCIL_BUFFER_BIT | + GL.GL_COLOR_BUFFER_BIT); + + // All set with multisampled FBO! + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); + } else { + if (packedDepthStencil) { + // packed depth+stencil buffer... + gl.glGenRenderbuffers(1, glPackedDepthStencil, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glPackedDepthStencil[0]); + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, + glPackedDepthStencil[0]); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, + glPackedDepthStencil[0]); + } else { + // Separate depth and stencil buffers... + gl.glGenRenderbuffers(1, glDepthBuffer, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBuffer[0]); + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT24, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, + glDepthBuffer[0]); + + gl.glGenRenderbuffers(1, glStencilBuffer, 0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBuffer[0]); + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_STENCIL_INDEX8, + fboWidth, fboHeight); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, glStencilBuffer[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. + gl.glClearDepth(1); + gl.glClearStencil(0); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); + } + + // The screen framebuffer is the color FBO just created. We need + // to update the screenFramebuffer object so when the framebuffer + // is popped back to the screen, the correct id is set. + PGraphicsOpenGL.screenFramebuffer.glFbo = glColorFbo[0]; + + backTex = 1; + frontTex = 0; + } else { + // To make sure that the default screen buffer is used, specially after + // doing screen rendering on an FBO. + PGraphicsOpenGL.screenFramebuffer.glFbo = 0; + } } + protected void updateOffscreen(PGL primary) { gl = primary.gl; gl2 = primary.gl2; @@ -623,59 +787,49 @@ public class PGL { } - protected int primaryReadFramebuffer() { - if (capabilities.isFBO()) { - return context.getDefaultReadFramebuffer(); - } else { - return 0; - } - } - - protected int primaryDrawFramebuffer() { - if (capabilities.isFBO()) { - return context.getDefaultDrawFramebuffer(); - } else { - return 0; - } - } - protected int primaryDrawBuffer() { - if (capabilities.isFBO()) { - return GL.GL_COLOR_ATTACHMENT0; - } else { + if (glColorFbo[0] == 0) { return GL.GL_BACK; + } else { + return GL.GL_COLOR_ATTACHMENT0; } } - protected int primaryReadBuffer() { - if (capabilities.isFBO()) { - return GL.GL_COLOR_ATTACHMENT0; - } else { - return GL.GL_BACK; - } +/* + protected boolean primaryIsDoubleBuffered() { + // When using the multisampled FBO, the color + // FBO is single buffered as it has only one + // texture bound to it. + //return glColorFbo[0] == 0; + return true; } +*/ protected boolean primaryIsFboBacked() { - return capabilities.isFBO(); + return glColorFbo[0] != 0; } + protected int getFboTexTarget() { return GL.GL_TEXTURE_2D; } + protected int getFboTexName() { - return drawTexName; + return glColorTex[0]; } + protected int getFboWidth() { - return drawTexWidth; + return fboWidth; } + protected int getFboHeight() { - return drawTexHeight; + return fboHeight; } - /* + protected void bindPrimaryColorFBO() { if (multisample) { // Blit the contents of the multisampled FBO into the color FBO, @@ -721,7 +875,7 @@ public class PGL { gl.glDeleteRenderbuffers(1, glColorRenderBuffer, 0); } } -*/ + protected int qualityToSamples(int quality) { if (quality <= 1) { @@ -733,26 +887,15 @@ public class PGL { } } - protected void forceUpdate() { - if (0 < capabilities.getNumSamples()) { - drawFBO.syncSamplingSink(gl); - drawFBO.bind(gl); - } - } - - protected void bindBackBufferTex() { - /* if (!texturingIsEnabled(GL.GL_TEXTURE_2D)) { enableTexturing(GL.GL_TEXTURE_2D); } gl.glBindTexture(GL.GL_TEXTURE_2D, glColorTex[backTex]); - */ } protected void unbindBackBufferTex() { - /* if (textureIsBound(GL.GL_TEXTURE_2D, glColorTex[backTex])) { // We don't want to unbind another texture // that might be bound instead of this one. @@ -764,7 +907,6 @@ public class PGL { gl.glBindTexture(GL.GL_TEXTURE_2D, 0); } } - */ } @@ -774,7 +916,6 @@ public class PGL { protected void beginOnscreenDraw(boolean clear) { - /* if (glColorFbo[0] != 0) { gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, @@ -795,12 +936,10 @@ public class PGL { PGraphicsOpenGL.screenFramebuffer.glFbo = glColorFbo[0]; } } - */ } protected void endOnscreenDraw(boolean clear0) { - /* if (glColorFbo[0] != 0) { if (multisample) { // Blit the contents of the multisampled FBO into the color FBO: @@ -849,7 +988,6 @@ public class PGL { // frontTex = backTex; // backTex = temp; } - */ } @@ -1497,11 +1635,7 @@ public class PGL { public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { - - gl.glReadPixels(x, y, width, height, format, type, buffer); - - } @@ -2444,50 +2578,12 @@ public class PGL { // Java specific stuff + protected class PGLListener implements GLEventListener { @Override public void display(GLAutoDrawable adrawable) { drawable = adrawable; context = adrawable.getContext(); - - if (capabilities.isFBO()) { - GLFBODrawable fboDrawable = null; - if (toolkit == AWT) { - GLCanvas drCanvas = (GLCanvas)adrawable; - fboDrawable = (GLFBODrawable)drCanvas.getDelegatedDrawable(); -// FBObject fboFront = dr.getFBObject(GL.GL_FRONT); -// FBObject.Colorbuffer colorBuf = fboFront.getColorbuffer(0); -// FBObject.TextureAttachment texFront = (FBObject.TextureAttachment) colorBuf; -// System.out.println("front texture: " + texFront.getName()); - } else { - GLWindow drWindow = (GLWindow)adrawable; - fboDrawable = (GLFBODrawable)drWindow.getDelegatedDrawable(); - } - FBObject.TextureAttachment texAttach = null; - if (fboDrawable != null) { - //fboBack = fboDrawable.getFBObject(GL.GL_BACK); - //fboFront = fboDrawable.getFBObject(GL.GL_FRONT); - //FBObject.Colorbuffer colorBuf = fboFront.getSamplingSinkFBO().getColorbuffer(0); - //texAttach = (FBObject.TextureAttachment) colorBuf; - //texAttach = fboBack.getSamplingSink(); - - drawFBO = fboDrawable.getFBObject(GL.GL_BACK); - if (0 < capabilities.getNumSamples()) { - // When using multisampled FBO,the back buffer is the MSAA - // surface so it cannot read from, the one to use is the front. - texAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); - } else { - // W/out multisampling, rendering is done on the back buffer. - texAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); - } - } - if (texAttach != null) { - drawTexName = texAttach.getName(); - drawTexWidth = texAttach.getWidth(); - drawTexHeight = texAttach.getHeight(); - } - } - gl = context.getGL(); gl2 = gl.getGL2ES2(); try { @@ -2529,13 +2625,11 @@ public class PGL { drawable = adrawable; context = adrawable.getContext(); - /* if (glColorFbo[0] != 0) { // The screen FBO hack needs the FBO to be recreated when starting // and after resizing. glColorFbo[0] = 0; } - */ } } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index b44d0f6a6..43594fe00 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -363,8 +363,7 @@ public class PGraphicsOpenGL extends PGraphics { static protected int fbStackDepth; static protected FrameBuffer[] fbStack = new FrameBuffer[FB_STACK_DEPTH]; - static protected FrameBuffer drawFramebuffer; - static protected FrameBuffer readFramebuffer; + static protected FrameBuffer screenFramebuffer; static protected FrameBuffer currentFramebuffer; // ....................................................... @@ -1553,17 +1552,12 @@ public class PGraphicsOpenGL extends PGraphics { getGLParameters(); } - if (primarySurface) { - if (drawFramebuffer == null) { - drawFramebuffer = new FrameBuffer(parent, width, height, true); - setFramebuffer(drawFramebuffer); - } - drawFramebuffer.setFBO(pgl.primaryDrawFramebuffer()); - if (readFramebuffer == null) { - readFramebuffer = new FrameBuffer(parent, width, height, true); - } - readFramebuffer.setFBO(pgl.primaryReadFramebuffer()); + if (screenFramebuffer == null) { + screenFramebuffer = new FrameBuffer(parent, width, height, true); + setFramebuffer(screenFramebuffer); + } + if (primarySurface) { pgl.updatePrimary(); pgl.drawBuffer(pgl.primaryDrawBuffer()); } else { @@ -1874,24 +1868,30 @@ public class PGraphicsOpenGL extends PGraphics { } - - protected void beginPixelsOp(int op) { if (primarySurface) { - // We read or write from the back buffer, where all the - // drawing in the current frame is taking place. - pushFramebuffer(); - if (op == OP_READ) { - setFramebuffer(readFramebuffer); - pgl.readBuffer(pgl.primaryReadBuffer()); - if (pgl.primaryIsFboBacked()) { - pgl.forceUpdate(); + if (pgl.primaryIsFboBacked()) { + if (op == OP_READ) { + // We read from the color FBO, but the multisample FBO is currently + // bound, so: + offscreenNotCurrent = true; + pgl.bindPrimaryColorFBO(); + pgl.readBuffer(pgl.primaryDrawBuffer()); + } else { + // We write directly to the multisample FBO. + offscreenNotCurrent = false; + pgl.drawBuffer(pgl.primaryDrawBuffer()); } } else { - setFramebuffer(drawFramebuffer); - pgl.drawBuffer(pgl.primaryDrawBuffer()); + // We read or write from the back buffer, where all the + // drawing in the current frame is taking place. + if (op == OP_READ) { + pgl.readBuffer(pgl.primaryDrawBuffer()); + } else { + pgl.drawBuffer(pgl.primaryDrawBuffer()); + } + offscreenNotCurrent = false; } - offscreenNotCurrent = true; } else { // Making sure that the offscreen FBO is current. This allows to do calls // like loadPixels(), set() or get() without enclosing them between @@ -1933,18 +1933,6 @@ public class PGraphicsOpenGL extends PGraphics { protected void endPixelsOp() { - if (offscreenNotCurrent) { - if (!primarySurface && pixelsOp == OP_WRITE && offscreenMultisample) { - // We were writing to the multisample FBO, so we need - // to blit its contents to the color FBO. - offscreenFramebufferMultisample.copy(offscreenFramebuffer); - } - popFramebuffer(); - } - - pixelsOp = OP_NONE; - - /* if (offscreenNotCurrent) { if (primarySurface) { pgl.bindPrimaryMultiFBO(); @@ -1958,7 +1946,6 @@ public class PGraphicsOpenGL extends PGraphics { } } pixelsOp = OP_NONE; - */ } @@ -5320,6 +5307,7 @@ public class PGraphicsOpenGL extends PGraphics { pgl.readPixels(0, 0, width, height, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); + PGL.nativeToJavaARGB(pixels, width, height); } @@ -5415,9 +5403,13 @@ public class PGraphicsOpenGL extends PGraphics { loadTextureImpl(Texture.POINT, false); if (pgl.primaryIsFboBacked()) { - pgl.forceUpdate(); + pgl.bindPrimaryColorFBO(); + // Copy the contents of the FBO used by the primary surface into + // texture, this copy operation is very fast because it is resolved + // in the GPU. texture.set(pgl.getFboTexTarget(), pgl.getFboTexName(), pgl.getFboWidth(), pgl.getFboHeight(), width, height); + pgl.bindPrimaryMultiFBO(); } else { // Here we go the slow route: we first copy the contents of the color // buffer into a pixels array (but we keep it in native format) and @@ -5934,7 +5926,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void bindBackTexture() { if (primarySurface) { - //pgl.bindBackBufferTex(); + pgl.bindBackBufferTex(); } else { } @@ -5943,7 +5935,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void unbindBackTexture() { if (primarySurface) { - //pgl.unbindBackBufferTex(); + pgl.unbindBackBufferTex(); } else { } @@ -6109,8 +6101,8 @@ public class PGraphicsOpenGL extends PGraphics { OPENGL_EXTENSIONS.indexOf("_shader_objects") == -1 || OPENGL_EXTENSIONS.indexOf("_shading_language") == -1) { // GLSL extensions are not present, we cannot do anything else here. - throw new RuntimeException("Processing cannot run because GLSL shaders" + - " are not available."); + throw new RuntimeException("GLSL shaders are not supported by this " + + "video card"); } }