commit 12f45260defe4433190e204d5b8c06192a77c5c6
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Mar 27 20:56:22 2018 +0100

    First try at the SSBO (doesn't work - reads in the application don't pick up changes in the shader; crashes.

diff --git a/src/main/java/org/distorted/library/main/DistortedEffects.java b/src/main/java/org/distorted/library/main/DistortedEffects.java
index 66cc3ea..e47a74d 100644
--- a/src/main/java/org/distorted/library/main/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/main/DistortedEffects.java
@@ -53,6 +53,7 @@ public class DistortedEffects
   /// MAIN PROGRAM ///
   private static DistortedProgram mMainProgram;
   private static int mMainTextureH;
+  private static int mCountIndexH;
 
   /// BLIT PROGRAM ///
   private static DistortedProgram mBlitProgram;
@@ -120,6 +121,7 @@ public class DistortedEffects
     EffectQueueVertex.getUniforms(mainProgramH);
     EffectQueueMatrix.getUniforms(mainProgramH);
     mMainTextureH= GLES31.glGetUniformLocation( mainProgramH, "u_Texture");
+    mCountIndexH = GLES31.glGetUniformLocation( mainProgramH, "u_currentIndex");
 
     // BLIT PROGRAM ////////////////////////////////////
     final InputStream blitVertStream = resources.openRawResource(R.raw.blit_vertex_shader);
@@ -281,6 +283,9 @@ public class DistortedEffects
 
     mMainProgram.useProgram();
     GLES31.glUniform1i(mMainTextureH, 0);
+    GLES31.glUniform1i(mCountIndexH, surface.resetNewCounter() );
+
+    android.util.Log.d("surface", "SurfaceID "+ surface.getID()+" transparent fragments: "+ surface.returnCounter() );
 
     if( Distorted.GLSL >= 300 )
       {
diff --git a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
index 622aac9..3303d2e 100644
--- a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
@@ -39,7 +39,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Must be called from a thread holding OpenGL Context
 
-  void create()
+  void createSurface()
     {
     if( mColorCreated==NOT_CREATED_YET )
       {
@@ -135,7 +135,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Must be called from a thread holding OpenGL Context
 
-  void delete()
+  void deleteSurface()
     {
     if( mColorH[0]>0 )
       {
@@ -158,7 +158,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // called from onDestroy(); mark OpenGL assets as 'not created'
 
-  void recreate()
+  void recreateSurface()
     {
     if( mColorCreated!=DONT_CREATE )
       {
diff --git a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
index aeffd88..3e4ccd5 100644
--- a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
@@ -24,6 +24,8 @@ import android.opengl.Matrix;
 
 import org.distorted.library.effect.EffectQuality;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,10 +98,33 @@ public static final int DEBUG_FPS = 1;
 
   private int mDebugLevel;
 
+  ////////////////////////////////////////////////////////////////////////////////
+  // section dealing with Shader Storage Buffer Object (for counting transparency)
+  private static final int BUFFERING = 3;
+  private static int mBufferSize     =10;
+  private static DistortedObjectCounter mSurfaceCounter = new DistortedObjectCounter();
+  private static int[] mSSBO = new int[1];
+  private static ByteBuffer mSSBOBuffer;
+
+  static
+    {
+    mSSBO[0]    = -1;
+    mSSBOBuffer = ByteBuffer.allocateDirect(BUFFERING*mBufferSize*4).order(ByteOrder.nativeOrder());
+    }
+
+  private int mSurfaceID;
+  private int mLastIndex;
+
+  // end section
+  ////////////////////////////////////////////////////////////////////////////////
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   abstract void prepareDebug(long time);
   abstract void renderDebug(long time);
+  abstract void createSurface();
+  abstract void deleteSurface();
+  abstract void recreateSurface();
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -137,6 +162,78 @@ public static final int DEBUG_FPS = 1;
     createProjection();
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Must be called from a thread holding OpenGL Context
+
+  void create()
+    {
+    if( mSSBO[0]<0 )
+      {
+      GLES31.glGenBuffers(1,mSSBO,0);
+
+      // here bind the new SSBO and map it
+      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mSSBO[0]);
+      GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, BUFFERING*mBufferSize*4 , null, GLES31.GL_DYNAMIC_READ);
+      mSSBOBuffer = (ByteBuffer) GLES31.glMapBufferRange(GLES31.GL_SHADER_STORAGE_BUFFER, 0, BUFFERING*mBufferSize*4, GLES31.GL_MAP_WRITE_BIT | GLES31.GL_MAP_WRITE_BIT );
+      GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER,1, mSSBO[0]);
+      }
+
+    mSurfaceID = mSurfaceCounter.returnNext();
+
+    if( mSurfaceID>=mBufferSize )
+      {
+      // increase the size of mSSBOBuffer, copy over old values, remap.
+      // TODO (don't need this if there are never more than mBufferSize=10 Surfaces)
+      }
+
+    createSurface();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Must be called from a thread holding OpenGL Context
+
+  void delete()
+    {
+    mSurfaceCounter.release(mSurfaceID);
+    deleteSurface();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void recreate()
+    {
+    mSSBO[0] = -1;
+    mSurfaceCounter.releaseAll();
+    recreateSurface();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int resetNewCounter()
+    {
+    //mSSBOBuffer.putInt(BUFFERING*mSurfaceID+mLastIndex,0);
+    return BUFFERING*mSurfaceID + mLastIndex;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int returnOldCounter()
+    {
+    int ret = mSSBOBuffer.getInt(BUFFERING*mSurfaceID+mLastIndex);
+
+    mLastIndex++;
+    if( mLastIndex>=BUFFERING ) mLastIndex-=BUFFERING;
+
+    return ret;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int returnCounter()
+    {
+    return mSSBOBuffer.getInt(0);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void createProjection()
diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.java b/src/main/java/org/distorted/library/main/DistortedScreen.java
index 741f55d..efd73f5 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.java
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.java
@@ -56,9 +56,9 @@ public class DistortedScreen extends DistortedOutputSurface
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // here we don't manage underlying OpenGL assets ourselves
 
-  void create()   {}
-  void delete()   {}
-  void recreate() {}
+  void createSurface()   {}
+  void deleteSurface()   {}
+  void recreateSurface() {}
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/res/raw/main_fragment_shader.glsl b/src/main/res/raw/main_fragment_shader.glsl
index a66fd41..27b78c6 100644
--- a/src/main/res/raw/main_fragment_shader.glsl
+++ b/src/main/res/raw/main_fragment_shader.glsl
@@ -43,6 +43,14 @@ uniform vec4 fUniforms[2*NUM_FRAGMENT]; // i-th effect is 2 consecutive vec4's:
                                         // next describes the Region, i.e. area over which the effect is active.
 #endif    // NUM_FRAGMENT>0
 
+layout (std140,binding=1) buffer SSBO   // PER-SURFACE count of transparent fragments.
+  {                                     // Can be buffered, i.e. if we are for example
+  int count[];                          // triple-buffered, then surfaceID=N uses 3
+  };                                    // consecutive counts (N,N+1,N+2) during 3
+                                        // consecutive frames.
+uniform int u_currentIndex;             // Index into the count[] array we are supposed to be using
+                                        // during this very invocation.
+
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 void main()                    		
@@ -65,5 +73,7 @@ void main()
     }
 #endif
 
+  count[0]=17;
+
   FRAG_COLOR = vec4(color.rgb * (1.0 + 7.0*v_Normal.z) * 0.125, color.a);
   }
\ No newline at end of file
