commit 66103fb2049db189c52f6c09762c2dc3a8684b36
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Apr 3 13:31:32 2020 +0100

    Speedup: only allocate one postprocessing buffer set of the quality we need, not all in one go.

diff --git a/src/main/java/org/distorted/library/main/InternalOutputSurface.java b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
index 3b76a30..4388334 100644
--- a/src/main/java/org/distorted/library/main/InternalOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
@@ -38,10 +38,21 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
   public static final int DEPTH_NO_STENCIL    = 1;
   public static final int BOTH_DEPTH_STENCIL  = 2;
 
-  public static final float DEFAULT_FOV = 60.0f;
-  public static final float DEFAULT_NEAR=  0.1f;
+  static final float DEFAULT_FOV = 60.0f;
+  static final float DEFAULT_NEAR=  0.1f;
 
-  float mFOV, mDistance, mNear, mMipmap;
+  private float mFOV;
+
+  private long[] mTime;
+  private float mClearR, mClearG, mClearB, mClearA, mClearDepth;
+  private int mClear, mClearStencil;
+  private boolean mRenderWayOIT;
+  private InternalChildrenList mChildren;
+
+  // Global buffers used for postprocessing
+  private static DistortedFramebuffer[] mBuffer= new DistortedFramebuffer[EffectQuality.LENGTH];
+
+  float mDistance, mNear, mMipmap;
   float[] mProjectionMatrix;
   int mDepthStencilCreated, mDepthStencil;
   int[] mDepthStencilH, mFBOH;
@@ -50,13 +61,6 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
   int mCurrFBO;     // internal current FBO (see DistortedLibrary.FBO_QUEUE_SIZE)
   int mWidth, mHeight;
 
-  private static DistortedFramebuffer[] mBuffer=null; // Global buffers used for postprocessing.
-  private long[] mTime;
-  private float mClearR, mClearG, mClearB, mClearA, mClearDepth;
-  private int mClear, mClearStencil;
-  private boolean mRenderWayOIT;
-  private InternalChildrenList mChildren;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   InternalOutputSurface(int width, int height, int createColor, int numfbos, int numcolors, int depthStencil, int fbo, int type)
@@ -142,7 +146,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private static void createPostprocessingBuffers(int width, int height, float near)
+  private static void createPostprocessingBuffers(int quality, int width, int height, float near)
     {
     final float CLEAR_R = 1.0f;
     final float CLEAR_G = 1.0f;
@@ -151,18 +155,14 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     final float CLEAR_D = 1.0f;
     final int   CLEAR_S = 0;
 
-    mBuffer = new DistortedFramebuffer[EffectQuality.LENGTH];
     float mipmap=1.0f;
 
-    for (int j=0; j<EffectQuality.LENGTH; j++)
-      {
-      mBuffer[j] = new DistortedFramebuffer(DistortedLibrary.FBO_QUEUE_SIZE,2,BOTH_DEPTH_STENCIL,TYPE_SYST, (int)(width*mipmap), (int)(height*mipmap) );
-      mBuffer[j].mMipmap = mipmap;
-      mBuffer[j].mNear = near;  // copy mNear as well (for blitting- see PostprocessEffect.apply() )
-      mBuffer[j].glClearColor(CLEAR_R, CLEAR_G, CLEAR_B, CLEAR_A);
+    for (int j=0; j<quality; j++) mipmap *= EffectQuality.MULTIPLIER;
 
-      mipmap *= EffectQuality.MULTIPLIER;
-      }
+    mBuffer[quality] = new DistortedFramebuffer(DistortedLibrary.FBO_QUEUE_SIZE,2,BOTH_DEPTH_STENCIL,TYPE_SYST, (int)(width*mipmap), (int)(height*mipmap) );
+    mBuffer[quality].mMipmap = mipmap;
+    mBuffer[quality].mNear = near;  // copy mNear as well (for blitting- see PostprocessEffect.apply() )
+    mBuffer[quality].glClearColor(CLEAR_R, CLEAR_G, CLEAR_B, CLEAR_A);
 
     InternalObject.toDo(); // create the FBOs immediately. This is safe as we must be holding the OpenGL context now.
 
@@ -171,16 +171,13 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     GLES31.glClearDepthf(CLEAR_D);
     GLES31.glClearStencil(CLEAR_S);
 
-    for (int j=0; j<EffectQuality.LENGTH; j++)
+    for(int k = 0; k< DistortedLibrary.FBO_QUEUE_SIZE; k++)
       {
-      for(int k = 0; k< DistortedLibrary.FBO_QUEUE_SIZE; k++)
-        {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mBuffer[j].mFBOH[k]);
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[j].mColorH[2*k+1], 0);
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT | GLES31.GL_DEPTH_BUFFER_BIT | GLES31.GL_STENCIL_BUFFER_BIT);
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[j].mColorH[2*k  ], 0);
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
-        }
+      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mBuffer[quality].mFBOH[k]);
+      GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k+1], 0);
+      GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT | GLES31.GL_DEPTH_BUFFER_BIT | GLES31.GL_STENCIL_BUFFER_BIT);
+      GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k  ], 0);
+      GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
       }
 
     InternalRenderState.colorDepthStencilRestore();
@@ -192,15 +189,12 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
   static synchronized void onDestroy()
     {
-    if( mBuffer!=null )
-      {
-      for (int j = 0; j < EffectQuality.LENGTH; j++)
+    for (int j=0; j<EffectQuality.LENGTH; j++)
+      if( mBuffer[j]!=null )
         {
+        mBuffer[j].markForDeletion();
         mBuffer[j] = null;
         }
-
-      mBuffer = null;
-      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -212,35 +206,28 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 // Also, adjust the Buffers so their Projection is the same like the surface we are supposed to be
 // rendering to.
 
-  private static void clonePostprocessingViewportAndProjection(InternalOutputSurface from)
+  private static void clonePostprocessingViewportAndProjection(InternalOutputSurface surface, InternalOutputSurface from)
     {
-    if( mBuffer[0].mWidth != from.mWidth || mBuffer[0].mHeight != from.mHeight ||
-        mBuffer[0].mFOV   != from.mFOV   || mBuffer[0].mNear   != from.mNear    )
+    if( surface.mWidth != from.mWidth || surface.mHeight != from.mHeight ||
+        surface.mFOV   != from.mFOV   || surface.mNear   != from.mNear    )
       {
-      InternalOutputSurface surface;
-
-      for(int i=0; i<EffectQuality.LENGTH; i++)
-        {
-        surface = mBuffer[i];
+      surface.mWidth  = (int)(from.mWidth *surface.mMipmap);
+      surface.mHeight = (int)(from.mHeight*surface.mMipmap);
+      surface.mFOV    = from.mFOV;
+      surface.mNear   = from.mNear;  // Near plane is independent of the mipmap level
 
-        surface.mWidth  = (int)(from.mWidth *surface.mMipmap);
-        surface.mHeight = (int)(from.mHeight*surface.mMipmap);
-        surface.mFOV    = from.mFOV;
-        surface.mNear   = from.mNear;  // Near plane is independent of the mipmap level
+      surface.createProjection();
 
-        surface.createProjection();
+      int maxw = Math.max(surface.mWidth , surface.mRealWidth );
+      int maxh = Math.max(surface.mHeight, surface.mRealHeight);
 
-        int maxw = Math.max(surface.mWidth , surface.mRealWidth );
-        int maxh = Math.max(surface.mHeight, surface.mRealHeight);
-
-        if (maxw > surface.mRealWidth || maxh > surface.mRealHeight)
-          {
-          surface.mRealWidth = maxw;
-          surface.mRealHeight = maxh;
+      if (maxw > surface.mRealWidth || maxh > surface.mRealHeight)
+        {
+        surface.mRealWidth = maxw;
+        surface.mRealHeight = maxh;
 
-          surface.recreate();
-          surface.create();
-          }
+        surface.recreate();
+        surface.create();
         }
       }
     }
@@ -382,11 +369,6 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
     setCurrFBO(fbo);
 
-    if( mBuffer!=null )
-      {
-      for (int i=0; i<EffectQuality.LENGTH; i++) mBuffer[i].setCurrFBO(fbo);
-      }
-
     if( oit && numChildren>0 )
       {
       oitClear(this);
@@ -414,17 +396,16 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
         }
       else
         {
-        if( mBuffer==null )
-          {
-          createPostprocessingBuffers(mWidth,mHeight,mNear);
-          for (int j=0; j<EffectQuality.LENGTH; j++) mBuffer[j].setCurrFBO(fbo);
-          }
+        int currQuality = currQueue.getQuality();
+
+        if( mBuffer[currQuality]==null ) createPostprocessingBuffers(currQuality, mWidth, mHeight, mNear);
+        mBuffer[currQuality].setCurrFBO(fbo);
 
         if( lastBucket!=currBucket )
           {
           if( lastBucket==0 )
             {
-            clonePostprocessingViewportAndProjection(this);
+            clonePostprocessingViewportAndProjection(mBuffer[currQuality],this);
             }
           else
             {
@@ -452,7 +433,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
             buffer.clearBuffer(fbo);
             }
 
-          buffer= mBuffer[currQueue.getQuality()];
+          buffer= mBuffer[currQuality];
           bucketChange= i;
           renderDirectly = currQueue.getRender();
           }
@@ -759,9 +740,9 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
       mNear=0.99f;
       }
 
-    if( mBuffer!=null )
+    for(int j=0; j<EffectQuality.LENGTH; j++)
       {
-      for(int j=0; j<EffectQuality.LENGTH; j++) mBuffer[j].mNear = mNear;
+      if( mBuffer[j]!=null ) mBuffer[j].mNear = mNear;
       }
 
     createProjection();
@@ -857,13 +838,15 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
  *                    transparent fragments than it has space for and readjust its internal buffers,
  *                    but only after a few frames during which one will probably see missing objects.
  */
-public void setOrderIndependentTransparency(boolean oit, float initialSize)
-  {
-  mRenderWayOIT = oit;
+  public void setOrderIndependentTransparency(boolean oit, float initialSize)
+    {
+    mRenderWayOIT = oit;
 
-  if( initialSize>0.0f && initialSize<10.0f )
-    DistortedLibrary.setSSBOSize(initialSize);
-  }
+    if( initialSize>0.0f && initialSize<10.0f )
+      {
+      DistortedLibrary.setSSBOSize(initialSize);
+      }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
