Link atomic counters to buffers

Gather counters from each shader and group them according the
layout qualifier 'binding' into each buffer.

BUG=angleproject:1729
TEST=angle_end2end_tests:AtomicCounterBufferTest

Change-Id: I8d0cd0d2bf65be37c035b0e1540481c8bee0bae4
diff --git a/src/libANGLE/MemoryProgramCache.cpp b/src/libANGLE/MemoryProgramCache.cpp
index 8fa1c49..eccd509 100644
--- a/src/libANGLE/MemoryProgramCache.cpp
+++ b/src/libANGLE/MemoryProgramCache.cpp
@@ -49,6 +49,37 @@
     var->structName = stream->readString();
 }
 
+void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
+{
+    stream->writeInt(var.binding);
+    stream->writeInt(var.dataSize);
+
+    stream->writeInt(var.vertexStaticUse);
+    stream->writeInt(var.fragmentStaticUse);
+    stream->writeInt(var.computeStaticUse);
+
+    stream->writeInt(var.memberIndexes.size());
+    for (unsigned int memberCounterIndex : var.memberIndexes)
+    {
+        stream->writeInt(memberCounterIndex);
+    }
+}
+
+void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
+{
+    var->binding           = stream->readInt<int>();
+    var->dataSize          = stream->readInt<unsigned int>();
+    var->vertexStaticUse   = stream->readBool();
+    var->fragmentStaticUse = stream->readBool();
+    var->computeStaticUse  = stream->readBool();
+
+    unsigned int numMembers = stream->readInt<unsigned int>();
+    for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
+    {
+        var->memberIndexes.push_back(stream->readInt<unsigned int>());
+    }
+}
+
 class HashStream final : angle::NonCopyable
 {
   public:
@@ -158,7 +189,7 @@
         LinkedUniform uniform;
         LoadShaderVar(&stream, &uniform);
 
-        uniform.blockIndex                 = stream.readInt<int>();
+        uniform.bufferIndex                = stream.readInt<int>();
         uniform.blockInfo.offset           = stream.readInt<int>();
         uniform.blockInfo.arrayStride      = stream.readInt<int>();
         uniform.blockInfo.matrixStride     = stream.readInt<int>();
@@ -191,21 +222,22 @@
         stream.readString(&uniformBlock.name);
         stream.readBool(&uniformBlock.isArray);
         stream.readInt(&uniformBlock.arrayElement);
-        stream.readInt(&uniformBlock.binding);
-        stream.readInt(&uniformBlock.dataSize);
-        stream.readBool(&uniformBlock.vertexStaticUse);
-        stream.readBool(&uniformBlock.fragmentStaticUse);
 
-        unsigned int numMembers = stream.readInt<unsigned int>();
-        for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
-        {
-            uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
-        }
+        LoadShaderVariableBuffer(&stream, &uniformBlock);
 
         state->mUniformBlocks.push_back(uniformBlock);
 
         state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
     }
+    unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
+    ASSERT(state->mAtomicCounterBuffers.empty());
+    for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
+    {
+        AtomicCounterBuffer atomicCounterBuffer;
+        LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
+
+        state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
+    }
 
     unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
 
@@ -286,6 +318,10 @@
         state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount));
     }
 
+    unsigned int atomicCounterRangeLow  = stream.readInt<unsigned int>();
+    unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
+    state->mAtomicCounterUniformRange   = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
+
     return program->getImplementation()->load(context, infoLog, &stream);
 }
 
@@ -335,7 +371,7 @@
 
         // FIXME: referenced
 
-        stream.writeInt(uniform.blockIndex);
+        stream.writeInt(uniform.bufferIndex);
         stream.writeInt(uniform.blockInfo.offset);
         stream.writeInt(uniform.blockInfo.arrayStride);
         stream.writeInt(uniform.blockInfo.matrixStride);
@@ -358,17 +394,14 @@
         stream.writeString(uniformBlock.name);
         stream.writeInt(uniformBlock.isArray);
         stream.writeInt(uniformBlock.arrayElement);
-        stream.writeInt(uniformBlock.binding);
-        stream.writeInt(uniformBlock.dataSize);
 
-        stream.writeInt(uniformBlock.vertexStaticUse);
-        stream.writeInt(uniformBlock.fragmentStaticUse);
+        WriteShaderVariableBuffer(&stream, uniformBlock);
+    }
 
-        stream.writeInt(uniformBlock.memberUniformIndexes.size());
-        for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
-        {
-            stream.writeInt(memberUniformIndex);
-        }
+    stream.writeInt(state.mAtomicCounterBuffers.size());
+    for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
+    {
+        WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
     }
 
     // Warn the app layer if saving a binary with unsupported transform feedback.
@@ -437,6 +470,9 @@
         stream.writeInt(imageBinding.elementCount);
     }
 
+    stream.writeInt(state.getAtomicCounterUniformRange().low());
+    stream.writeInt(state.getAtomicCounterUniformRange().high());
+
     program->getImplementation()->save(context, &stream);
 
     ASSERT(binaryOut);