ES31: Add BUFFER_VARIABLE and SHADER_STORAGE_BLOCK program interfaces

This patch collects the shader storage block members information.
It implements getShaderStorageBlockMemberInfo and getShaderStorageBlockSize
for OpenGL backend. Meanwhile, it implements BUFFER_VARIABLE and SHADER_STORAGE_BLOCK
interfaces for program query.

BUG=angleproject:1920
TEST=angle_end2end_tests:ProgramInterfaceTest*
     dEQP-GLES31.functional.layout_binding.ssbo*
     dEQP-GLES31.functional.compute.basic.empty
     dEQP-GLES31.functional.compute.basic.ssbo_rw*
     dEQP-GLES31.functional.compute.basic.ssbo_local_barrier*
     dEQP-GLES31.functional.compute.basic.copy_image_to_ssbo_small
     dEQP-GLES31.functional.compute.basic.copy_ssbo_multiple_groups
     dEQP-GLES31.functional.compute.basic.copy_ssbo_multiple_invocations
     dEQP-GLES31.functional.compute.basic.copy_ssbo_single_invocation
     dEQP-GLES31.functional.compute.basic.copy_ssbo_to_image_small
     dEQP-GLES31.functional.compute.basic.shared_var*
     dEQP-GLES31.functional.compute.basic.ubo_to_ssbo*
     dEQP-GLES31.functional.compute.basic.write_multiple_arr*
     dEQP-GLES31.functional.compute.shared_var.basic_type.*
     dEQP-GLES31.functional.compute.shared_var.work_group_size.*
     dEQP-GLES31.functional.atomic_counter.*

Change-Id: Ie8b81fde5a2e919aab77adb3d137c9ff2f193409
Reviewed-on: https://chromium-review.googlesource.com/712235
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp
index 80667d9..41172d6 100644
--- a/src/libANGLE/queryutils.cpp
+++ b/src/libANGLE/queryutils.cpp
@@ -539,10 +539,14 @@
         case GL_ATOMIC_COUNTER_BUFFER:
             return clampCast<GLint>(program->getState().getAtomicCounterBuffers().size());
 
+        case GL_BUFFER_VARIABLE:
+            return clampCast<GLint>(program->getState().getBufferVariables().size());
+
+        case GL_SHADER_STORAGE_BLOCK:
+            return clampCast<GLint>(program->getState().getShaderStorageBlocks().size());
+
         // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_TRANSFORM_FEEDBACK_VARYING:
-        case GL_BUFFER_VARIABLE:
-        case GL_SHADER_STORAGE_BLOCK:
             UNIMPLEMENTED();
             return 0;
 
@@ -586,10 +590,18 @@
                 FindMaxSize(program->getState().getUniformBlocks(), &InterfaceBlock::name);
             break;
 
+        case GL_BUFFER_VARIABLE:
+            maxNameLength =
+                FindMaxSize(program->getState().getBufferVariables(), &BufferVariable::name);
+            break;
+
+        case GL_SHADER_STORAGE_BLOCK:
+            maxNameLength =
+                FindMaxSize(program->getState().getShaderStorageBlocks(), &InterfaceBlock::name);
+            break;
+
         // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_TRANSFORM_FEEDBACK_VARYING:
-        case GL_BUFFER_VARIABLE:
-        case GL_SHADER_STORAGE_BLOCK:
             UNIMPLEMENTED();
             return 0;
 
@@ -612,10 +624,9 @@
             return FindMaxSize(program->getState().getAtomicCounterBuffers(),
                                &AtomicCounterBuffer::memberIndexes);
 
-        // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_SHADER_STORAGE_BLOCK:
-            UNIMPLEMENTED();
-            return 0;
+            return FindMaxSize(program->getState().getShaderStorageBlocks(),
+                               &InterfaceBlock::memberIndexes);
 
         default:
             UNREACHABLE();
@@ -747,6 +758,19 @@
     GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition);
 }
 
+void GetShaderStorageBlockResourceProperty(const Program *program,
+                                           GLuint blockIndex,
+                                           GLenum pname,
+                                           GLint *params,
+                                           GLsizei bufSize,
+                                           GLsizei *outputPosition)
+
+{
+    ASSERT(*outputPosition < bufSize);
+    const auto &block = program->getShaderStorageBlockByIndex(blockIndex);
+    GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition);
+}
+
 void GetAtomicCounterBufferResourceProperty(const Program *program,
                                             GLuint index,
                                             GLenum pname,
@@ -1383,6 +1407,57 @@
     }
 }
 
+GLint GetBufferVariableResourceProperty(const Program *program, GLuint index, const GLenum prop)
+{
+    const auto &bufferVariable = program->getBufferVariableByIndex(index);
+    switch (prop)
+    {
+        case GL_TYPE:
+            return clampCast<GLint>(bufferVariable.type);
+
+        case GL_ARRAY_SIZE:
+            return clampCast<GLint>(bufferVariable.elementCount());
+
+        case GL_BLOCK_INDEX:
+            return bufferVariable.bufferIndex;
+
+        case GL_NAME_LENGTH:
+            // ES31 spec p84: This counts the terminating null char.
+            return clampCast<GLint>(bufferVariable.name.size() + 1u);
+
+        case GL_OFFSET:
+            return bufferVariable.blockInfo.offset;
+
+        case GL_ARRAY_STRIDE:
+            return bufferVariable.blockInfo.arrayStride;
+
+        case GL_MATRIX_STRIDE:
+            return bufferVariable.blockInfo.matrixStride;
+
+        case GL_IS_ROW_MAJOR:
+            return static_cast<GLint>(bufferVariable.blockInfo.isRowMajorMatrix);
+
+        case GL_REFERENCED_BY_VERTEX_SHADER:
+            return bufferVariable.vertexStaticUse;
+
+        case GL_REFERENCED_BY_FRAGMENT_SHADER:
+            return bufferVariable.fragmentStaticUse;
+
+        case GL_REFERENCED_BY_COMPUTE_SHADER:
+            return bufferVariable.computeStaticUse;
+
+        case GL_TOP_LEVEL_ARRAY_SIZE:
+            return bufferVariable.topLevelArraySize;
+
+        case GL_TOP_LEVEL_ARRAY_STRIDE:
+            return bufferVariable.blockInfo.topLevelArrayStride;
+
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
+
 GLuint QueryProgramResourceIndex(const Program *program,
                                  GLenum programInterface,
                                  const GLchar *name)
@@ -1398,13 +1473,17 @@
         case GL_UNIFORM:
             return program->getState().getUniformIndexFromName(name);
 
+        case GL_BUFFER_VARIABLE:
+            return program->getState().getBufferVariableIndexFromName(name);
+
+        case GL_SHADER_STORAGE_BLOCK:
+            return program->getShaderStorageBlockIndex(name);
+
         case GL_UNIFORM_BLOCK:
             return program->getUniformBlockIndex(name);
 
         // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_TRANSFORM_FEEDBACK_VARYING:
-        case GL_BUFFER_VARIABLE:
-        case GL_SHADER_STORAGE_BLOCK:
             UNIMPLEMENTED();
             return GL_INVALID_INDEX;
 
@@ -1435,14 +1514,20 @@
             program->getUniformResourceName(index, bufSize, length, name);
             break;
 
+        case GL_BUFFER_VARIABLE:
+            program->getBufferVariableResourceName(index, bufSize, length, name);
+            break;
+
+        case GL_SHADER_STORAGE_BLOCK:
+            program->getActiveShaderStorageBlockName(index, bufSize, length, name);
+            break;
+
         case GL_UNIFORM_BLOCK:
             program->getActiveUniformBlockName(index, bufSize, length, name);
             break;
 
         // TODO(jie.a.chen@intel.com): more interfaces.
         case GL_TRANSFORM_FEEDBACK_VARYING:
-        case GL_BUFFER_VARIABLE:
-        case GL_SHADER_STORAGE_BLOCK:
             UNIMPLEMENTED();
             break;
 
@@ -1509,18 +1594,27 @@
                 params[i] = GetUniformResourceProperty(program, index, props[i]);
                 ++pos;
                 break;
+
+            case GL_BUFFER_VARIABLE:
+                params[i] = GetBufferVariableResourceProperty(program, index, props[i]);
+                ++pos;
+                break;
+
             case GL_UNIFORM_BLOCK:
                 GetUniformBlockResourceProperty(program, index, props[i], params, bufSize, &pos);
                 break;
 
+            case GL_SHADER_STORAGE_BLOCK:
+                GetShaderStorageBlockResourceProperty(program, index, props[i], params, bufSize,
+                                                      &pos);
+                break;
+
             case GL_ATOMIC_COUNTER_BUFFER:
                 GetAtomicCounterBufferResourceProperty(program, index, props[i], params, bufSize,
                                                        &pos);
                 break;
             // TODO(jie.a.chen@intel.com): more interfaces.
             case GL_TRANSFORM_FEEDBACK_VARYING:
-            case GL_BUFFER_VARIABLE:
-            case GL_SHADER_STORAGE_BLOCK:
                 UNIMPLEMENTED();
                 params[i] = GL_INVALID_VALUE;
                 break;