commit 5f35f1cbc1021d1ecb0ae10c80e2e1f021afca22
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Jun 16 13:19:48 2020 +0100

    Only insert the 'Mali r12' FBO queue fix if we actually are running on a Mali GPU with driver version <22. (then FBOQueue=4 - unless we manually overide this down to 1 - else, always 1)

diff --git a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
index 2351509..a0f7fa8 100644
--- a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
@@ -37,6 +37,14 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
   void create()
     {
+    if( mNumFBOs==DistortedLibrary.WAIT_FOR_FBO_QUEUE_SIZE )
+      {
+      // only now we know how many FBOs there should be
+      mNumFBOs = DistortedLibrary.getQueueSize();
+      allocateColor();
+      allocateStuffDependantOnNumFBOS();
+      }
+
     //////////////////////////////////////////////////////////////
     // COLOR
 
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index e560726..6b64066 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -47,6 +47,8 @@ import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -97,16 +99,22 @@ public class DistortedLibrary
    */
   public static final int CLONE_CHILDREN= 0x20;
 
+  /**
+   * When creating a DistortedScreen (which needs to have mFBOQueueSize FBOs attached), pass this
+   * constant for 'numOfFBOs' and the number of backing FBOs will be taken from 'mFBOQueueSize'
+   * (the value of which is most likely unknown at the time of creation of the Screen)
+   */
+  public static final int WAIT_FOR_FBO_QUEUE_SIZE = -1;
   /**
    * Work around bugs in ARM Mali driver by, instead to a single FBO, rendering to a circular queue
-   * of FBO_QUEUE_SIZE FBOs. (otherwise we sometimes get a 'full pipeline flush' and the end result
+   * of mFBOQueueSize FBOs. (otherwise we sometimes get a 'full pipeline flush' and the end result
    * might be missing part of the Objects)
    *
-   * This bug only exists on Mali driver r12.
+   * This bug only exists on Mali driver r12. (or more precisely it's there in r12 but fixed in r22)
    *
    * https://community.arm.com/graphics/f/discussions/10285/opengl-es-3-1-on-mali-t880-flashes
    */
-  static final int FBO_QUEUE_SIZE = 3;
+  private static int mFBOQueueSize;
 
   private static boolean mInitialized=false;
 
@@ -150,15 +158,13 @@ public class DistortedLibrary
 
   /// OIT SSBO BUFFER ///
   private static int[] mLinkedListSSBO = new int[1];
-  private static int[] mAtomicCounter = new int[DistortedLibrary.FBO_QUEUE_SIZE];
+  private static int[] mAtomicCounter;
   private static int   mCurrBuffer;
 
   static
     {
     mLinkedListSSBO[0]= -1;
     mCurrBuffer       =  0;
-
-    for(int i = 0; i< DistortedLibrary.FBO_QUEUE_SIZE; i++)  mAtomicCounter[i] = -1;
     }
 
   ///////////////////////////////////////////////////////////////
@@ -646,11 +652,13 @@ public class DistortedLibrary
     {
     int counter = 0;
 
-    if( mAtomicCounter[0]<0 )
+    if( mAtomicCounter==null )
       {
-      GLES30.glGenBuffers(DistortedLibrary.FBO_QUEUE_SIZE,mAtomicCounter,0);
+      mAtomicCounter = new int[mFBOQueueSize];
+
+      GLES30.glGenBuffers(mFBOQueueSize,mAtomicCounter,0);
 
-      for(int i = 0; i< DistortedLibrary.FBO_QUEUE_SIZE; i++)
+      for(int i=0; i<mFBOQueueSize; i++)
         {
         GLES30.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[i]);
         GLES30.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES30.GL_DYNAMIC_DRAW);
@@ -666,7 +674,7 @@ public class DistortedLibrary
       counter = printPreviousBuffer();
       }
 
-    if( ++mCurrBuffer>= DistortedLibrary.FBO_QUEUE_SIZE ) mCurrBuffer = 0;
+    if( ++mCurrBuffer>=mFBOQueueSize ) mCurrBuffer = 0;
 
     GLES30.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
     zeroBuffer();
@@ -785,28 +793,54 @@ public class DistortedLibrary
     mBufferSize = size;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static int getQueueSize()
+    {
+    return mFBOQueueSize;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // ARM Mali driver r12 has problems when we keep swapping many FBOs (fixed in r22)
 // PowerVR GE8100 / GE8300 compiler fails to compile OIT programs.
 
-  private static void detectBuggyDrivers()
+  private static void detectBuggyDriversAndSetQueueSize(int queueSize)
     {
     String vendor  = GLES30.glGetString(GLES30.GL_VENDOR);
     String version = GLES30.glGetString(GLES30.GL_VERSION);
     String renderer= GLES30.glGetString(GLES30.GL_RENDERER);
 
-    /*
-    android.util.Log.e("DISTORTED", "GLSL Version "+GLES30.glGetString(GLES31.GL_SHADING_LANGUAGE_VERSION));
-    android.util.Log.e("DISTORTED", "GL Version "  +GLES30.glGetString(GLES31.GL_VERSION));
-    android.util.Log.e("DISTORTED", "GL Vendor "   +GLES30.glGetString(GLES31.GL_VENDOR));
-    android.util.Log.e("DISTORTED", "GL Renderer " +GLES30.glGetString(GLES31.GL_RENDERER));
-    */
+    mFBOQueueSize = 1;
 
     if( vendor.contains("ARM") )
       {
-      if( version.contains("r12") )
+      try
         {
-        Log.e("DISTORTED", "You are running this on a ARM Mali driver r12.\nThis is a buggy driver, please update to r22. Problems with flashing expected.");
+        String regex = ".*r(\\d+)p\\d.*";
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(version);
+
+        if( matcher.find() )
+          {
+          String driverVersion = matcher.group(1);
+
+          if( driverVersion!=null )
+            {
+            int drvVersion = Integer.parseInt(driverVersion);
+
+            if( drvVersion<22 )
+              {
+              Log.e("DISTORTED", "You are running this on a ARM Mali driver r"+driverVersion+".\n" +
+                    "This is a buggy driver, please update to r22. Inserting workaround which uses a lot of memory.");
+
+              mFBOQueueSize = queueSize;
+              }
+            }
+          }
+        }
+      catch(Exception ex)
+        {
+        android.util.Log.e("library", "exception trying to pattern match version: "+ex.toString());
         }
       }
     else if( vendor.contains("Imagination") )
@@ -860,10 +894,25 @@ public class DistortedLibrary
  * I.e. best called from GLSurfaceView.onCreate().
  * <p>
  * Needs to be called from a thread holding the OpenGL context.
- *   
+ *
  * @param context Context of the App using the library - used to open up Resources and read Shader code.
  */
   public static void onCreate(final Context context) throws Exception
+    {
+    onCreate(context,4);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * When OpenGL context gets created, call this method so that the library can initialise its internal data structures.
+ * I.e. best called from GLSurfaceView.onCreate().
+ * <p>
+ * Needs to be called from a thread holding the OpenGL context.
+ *   
+ * @param context Context of the App using the library - used to open up Resources and read Shader code.
+ * @param queueSize the size of the FBO queue, a workaround for the bug on Mali drivers.
+ */
+  public static void onCreate(final Context context, int queueSize) throws Exception
     {
     final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
@@ -888,7 +937,7 @@ public class DistortedLibrary
     mInitialized = true;
     mOITCompilationSuccessful = false;
 
-    detectBuggyDrivers();
+    detectBuggyDriversAndSetQueueSize(queueSize);
 
     EffectMessageSender.startSending();
 
@@ -961,8 +1010,7 @@ public class DistortedLibrary
     InternalObject.onPause();
 
     mLinkedListSSBO[0]= -1;
-
-    for(int i = 0; i< DistortedLibrary.FBO_QUEUE_SIZE; i++) mAtomicCounter[i] = -1;
+    mAtomicCounter = null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.java b/src/main/java/org/distorted/library/main/DistortedScreen.java
index 0055195..6c4129f 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.java
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.java
@@ -65,6 +65,7 @@ public class DistortedScreen extends DistortedFramebuffer
   private static MatrixEffectMove mMoveEffect = new MatrixEffectMove(mMoveVector);
   ///// END DEBUGGING //////////////////////////
 
+  private int mQueueSize;
   private int mCurRenderedFBO;    // During the first FBO_QUEUE_SIZE frames, we blit the very first
   private int mToBeBlittedFBO;    // FBO one we have rendered. Then, we keep blitting the one we
   private boolean mFirstCircle;   // rendered FBO_QUEUE_SIZE ago.
@@ -79,12 +80,13 @@ public class DistortedScreen extends DistortedFramebuffer
  */
   public DistortedScreen()
     {
-    super(DistortedLibrary.FBO_QUEUE_SIZE,1,BOTH_DEPTH_STENCIL, TYPE_SYST, 1,1);
+    super(DistortedLibrary.WAIT_FOR_FBO_QUEUE_SIZE,1,BOTH_DEPTH_STENCIL, TYPE_SYST, 1,1);
     mDebugMode = DEBUG_MODE_NONE;
     mCurRenderedFBO = 0;
     mToBeBlittedFBO = 0;
     mFirstCircle = true;
     mDebugAllocated = false;
+    mQueueSize = -1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -177,12 +179,17 @@ public class DistortedScreen extends DistortedFramebuffer
       DistortedLibrary.drawPriv(debugEffects, debugMesh, this, time);
       }
 
-    if( ++mCurRenderedFBO>= DistortedLibrary.FBO_QUEUE_SIZE )
+    if( mQueueSize<=0 )
+      {
+      mQueueSize = DistortedLibrary.getQueueSize();
+      }
+
+    if( ++mCurRenderedFBO>=mQueueSize )
       {
       mCurRenderedFBO = 0;
       if (mFirstCircle) mFirstCircle = false;
       }
-    if( !mFirstCircle && ++mToBeBlittedFBO>= DistortedLibrary.FBO_QUEUE_SIZE )
+    if( !mFirstCircle && ++mToBeBlittedFBO>=mQueueSize )
       {
       mToBeBlittedFBO=0;
       }
diff --git a/src/main/java/org/distorted/library/main/InternalOutputSurface.java b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
index 018053b..9f25922 100644
--- a/src/main/java/org/distorted/library/main/InternalOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
@@ -43,6 +43,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
   static final float DEFAULT_NEAR=  0.1f;
 
   private float mFOV;
+  private int mTmpFBO;
 
   private long[] mTime;
   private float mClearR, mClearG, mClearB, mClearA, mClearDepth;
@@ -71,12 +72,6 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     mRenderWayOIT = false;
     mCurrFBO      = 0;
 
-    mDepthStencilH = new int[numfbos];
-    mFBOH          = new int[numfbos];
-
-    mTime = new long[numfbos];
-    for(int i=0; i<mNumFBOs;i++) mTime[i]=0;
-
     mRealWidth = mWidth = width;
     mRealHeight= mHeight= height;
 
@@ -88,9 +83,6 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     mDepthStencilCreated= (depthStencil== NO_DEPTH_NO_STENCIL ? DONT_CREATE:NOT_CREATED_YET);
     mDepthStencil = depthStencil;
 
-    mFBOH[0]         = fbo;
-    mDepthStencilH[0]= 0;
-
     mClearR = 0.0f;
     mClearG = 0.0f;
     mClearB = 0.0f;
@@ -104,9 +96,29 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
     mChildren = new InternalChildrenList(this);
 
+    mTmpFBO = fbo;
+
+    allocateStuffDependantOnNumFBOS();
     createProjection();
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void allocateStuffDependantOnNumFBOS()
+    {
+    if( mNumFBOs>0 )
+      {
+      mDepthStencilH   = new int[mNumFBOs];
+      mDepthStencilH[0]= 0;
+
+      mFBOH   = new int[mNumFBOs];
+      mFBOH[0]= mTmpFBO;
+
+      mTime = new long[mNumFBOs];
+      for(int i=0; i<mNumFBOs;i++) mTime[i]=0;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void createProjection()
@@ -156,11 +168,12 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     final float CLEAR_D = 1.0f;
     final int   CLEAR_S = 0;
 
+    final int queueSize = DistortedLibrary.getQueueSize();
     float mipmap=1.0f;
 
     for (int j=0; j<quality; j++) 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] = new DistortedFramebuffer(queueSize,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);
@@ -172,7 +185,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     GLES30.glClearDepthf(CLEAR_D);
     GLES30.glClearStencil(CLEAR_S);
 
-    for(int k = 0; k< DistortedLibrary.FBO_QUEUE_SIZE; k++)
+    for(int k=0; k<queueSize; k++)
       {
       GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mBuffer[quality].mFBOH[k]);
       GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k+1], 0);
diff --git a/src/main/java/org/distorted/library/main/InternalSurface.java b/src/main/java/org/distorted/library/main/InternalSurface.java
index a149865..6949bc4 100644
--- a/src/main/java/org/distorted/library/main/InternalSurface.java
+++ b/src/main/java/org/distorted/library/main/InternalSurface.java
@@ -41,6 +41,13 @@ abstract class InternalSurface extends InternalObject
     mNumColors    = numcolors;
     mColorCreated = create;
 
+    allocateColor();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void allocateColor()
+    {
     int total = mNumFBOs*mNumColors;
 
     if( total>0 )
