commit 0f011027d45947d786cd84fa060cee8daa11231a
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Thu May 25 17:33:30 2017 +0100

    Major speedup, BLUR fully optimized now.
    
    Multiblur app, worst case (all 8 cubes blurred with max radius, HIGHEST quality: Nexus5X: 46.7 FPS, Nexus 4: 29.7 FPS.

diff --git a/src/main/java/org/distorted/library/DistortedFramebuffer.java b/src/main/java/org/distorted/library/DistortedFramebuffer.java
index 1286fb0..9445b7f 100644
--- a/src/main/java/org/distorted/library/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/DistortedFramebuffer.java
@@ -50,9 +50,8 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
         GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
         GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
         GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mWidth, mHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
-        GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0+i, GLES30.GL_TEXTURE_2D, mColorH[i], 0);
         }
-
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[0], 0);
       GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
       GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
 
diff --git a/src/main/java/org/distorted/library/DistortedNode.java b/src/main/java/org/distorted/library/DistortedNode.java
index ff799a6..f796948 100644
--- a/src/main/java/org/distorted/library/DistortedNode.java
+++ b/src/main/java/org/distorted/library/DistortedNode.java
@@ -266,20 +266,18 @@ public class DistortedNode implements DistortedSlave
     if( input.setAsInput() )
       {
       int quality = effects.getQuality();
-      DistortedFramebuffer buffer1 = surface.mBuffer1[quality];
-      DistortedFramebuffer buffer2 = surface.mBuffer2[quality];
+      DistortedFramebuffer buffer = surface.mBuffer[quality];
       float w = mSurface.getWidth() /2.0f;
       float h = mSurface.getHeight()/2.0f;
+      buffer.setAsOutput();
 
       // Draw the color buffer of the object.
-      buffer1.setAsOutput();
       mState.apply();
-      mEffects.drawPriv(w, h, mMesh, buffer1, currTime, 0);
+      mEffects.drawPriv(w, h, mMesh, buffer, currTime, 0);
 
       // Draw stencil + depth buffers of the object enlarged by HALO pixels around.
-      buffer2.setAsOutput();
       DistortedRenderState.setUpStencilMark();
-      mEffects.drawPriv(w, h, mMesh, buffer2, currTime, effects.getHalo()*buffer2.mMipmap);
+      mEffects.drawPriv(w, h, mMesh, buffer, currTime, effects.getHalo()*buffer.mMipmap);
       DistortedRenderState.unsetUpStencilMark();
 
       return 1;
diff --git a/src/main/java/org/distorted/library/DistortedOutputSurface.java b/src/main/java/org/distorted/library/DistortedOutputSurface.java
index 25f725d..eca8e28 100644
--- a/src/main/java/org/distorted/library/DistortedOutputSurface.java
+++ b/src/main/java/org/distorted/library/DistortedOutputSurface.java
@@ -64,7 +64,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 
   private ArrayList<Job> mJobs = new ArrayList<>();
 
-  DistortedFramebuffer[] mBuffer1, mBuffer2;
+  DistortedFramebuffer[] mBuffer;
 
   private long mTime;
   private float mFOV;
@@ -110,8 +110,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
     mClearStencil = 0;
     mClear = GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT;
 
-    mBuffer1 = new DistortedFramebuffer[EffectQuality.LENGTH];
-    mBuffer2 = new DistortedFramebuffer[EffectQuality.LENGTH];
+    mBuffer = new DistortedFramebuffer[EffectQuality.LENGTH];
 
     mMipmap = 1.0f;
 
@@ -164,10 +163,8 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 
     for(int j=0; j<EffectQuality.LENGTH; j++)
       {
-      mBuffer1[j] = new DistortedFramebuffer(1,BOTH_DEPTH_STENCIL,TYPE_SYST, (int)(mWidth*mipmap), (int)(mHeight*mipmap) );
-      mBuffer2[j] = new DistortedFramebuffer(1,BOTH_DEPTH_STENCIL,TYPE_SYST, (int)(mWidth*mipmap), (int)(mHeight*mipmap) );
-      mBuffer1[j].mMipmap = mipmap;
-      mBuffer2[j].mMipmap = mipmap;
+      mBuffer[j] = new DistortedFramebuffer(2,BOTH_DEPTH_STENCIL,TYPE_SYST, (int)(mWidth*mipmap), (int)(mHeight*mipmap) );
+      mBuffer[j].mMipmap = mipmap;
       mipmap *= EffectQuality.MULTIPLIER;
       }
 
@@ -182,10 +179,11 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 
     for(int j=0; j<EffectQuality.LENGTH; j++)
       {
-      mBuffer1[j].setAsOutput();
-      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
-      mBuffer2[j].setAsOutput();
+      mBuffer[j].setAsOutput();
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mBuffer[j].mColorH[1], 0);
       GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mBuffer[j].mColorH[0], 0);
+      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
       }
     }
 
@@ -212,7 +210,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
       if( currB==0 ) numRenders += child.draw(time,this);
       else
         {
-        if( mBuffer1[0]==null ) createBuffers();
+        if( mBuffer[0]==null ) createBuffers();
         numRenders += child.markStencilAndDraw(time,this,currP);
         if( i==num-1 ) numRenders += currP.postprocess(time,this);
         }
diff --git a/src/main/java/org/distorted/library/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
index 7ea18e9..d2bc39c 100644
--- a/src/main/java/org/distorted/library/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
@@ -271,11 +271,11 @@ class EffectQueuePostprocess extends EffectQueue
       {
       compute(time);
 
-      DistortedFramebuffer buffer1 = surface.mBuffer1[mQualityLevel];
-      DistortedFramebuffer buffer2 = surface.mBuffer2[mQualityLevel];
+      DistortedFramebuffer buffer = surface.mBuffer[mQualityLevel];
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, buffer.mFBOH[0]);
 
-      float w1 = buffer1.mWidth;
-      float h1 = buffer1.mHeight;
+      float w1 = buffer.mWidth;
+      float h1 = buffer.mHeight;
       float w2 = surface.mWidth;
       float h2 = surface.mHeight;
 
@@ -289,8 +289,9 @@ class EffectQueuePostprocess extends EffectQueue
       // horizontal blur
       GLES30.glViewport(0, 0, (int)w1, (int)h1);
       mBlur1Program.useProgram();
-      buffer1.setAsInput();
-      buffer2.setAsOutput();
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[1], 0);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mColorH[0]);
 
       GLES30.glUniform1fv( mWeights1H, radius+1, weightsCache,offset);
       GLES30.glUniform1i( mRadius1H, radius);
@@ -304,11 +305,14 @@ class EffectQueuePostprocess extends EffectQueue
       DistortedRenderState.useStencilMark();
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
       DistortedRenderState.unuseStencilMark();
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
       // vertical blur
       mBlur2Program.useProgram();
-      buffer2.setAsInput();
-      buffer1.setAsOutput();
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[0], 0);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mColorH[1]);
 
       GLES30.glColorMask(true,true,true,true);
       GLES30.glClearColor(0.0f,0.0f,0.0f,0.0f);
@@ -323,18 +327,28 @@ class EffectQueuePostprocess extends EffectQueue
       GLES30.glVertexAttribPointer(mBlur2Program.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glVertexAttribPointer(mBlur2Program.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
 
-      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_STENCIL_ATTACHMENT, GLES30.GL_TEXTURE_2D, buffer2.mDepthStencilH[0], 0);
       DistortedRenderState.useStencilMark();
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
       DistortedRenderState.unuseStencilMark();
-      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_STENCIL_ATTACHMENT, GLES30.GL_TEXTURE_2D, buffer1.mDepthStencilH[0], 0);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
       // blit the results with DEPTH to surface.
       GLES30.glViewport(0, 0, (int)w2, (int)h2);
-      buffer1.setAsInput();
-      buffer2.setAsDepth();
       surface.setAsOutput(time);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mColorH[0]);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mDepthStencilH[0]);
+
+      GLES30.glDisable(GLES30.GL_STENCIL_TEST);
+      GLES30.glStencilMask(0x00);
+
       DistortedEffects.blitDepthPriv(surface);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
       // after each postprocess, clear buffers
       GLES30.glStencilMask(0xff);
@@ -343,10 +357,12 @@ class EffectQueuePostprocess extends EffectQueue
       GLES30.glClearColor(0.0f,0.0f,0.0f,0.0f);
       GLES30.glClearDepthf(1.0f);
       GLES30.glClearStencil(0);
-      buffer1.setAsOutput();
-      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
-      buffer2.setAsOutput();
+
+      buffer.setAsOutput();
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[1], 0);
       GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[0], 0);
+      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
       }
 
     return mNumEffects;
