Program: Clean up UBO info gathering.

The data size & block member info was getting messy, so clean up
how we query this from the Impl layer.

Also remove the register information from gl::UniformBlock, moving
it into the D3D-only world.

BUG=angleproject:1172

Change-Id: I40af658ebbd6b7c1a4251906a387ebcbb621cf77
Reviewed-on: https://chromium-review.googlesource.com/304150
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 0a182ae..446defd 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -527,6 +527,22 @@
         mD3DUniforms.push_back(d3dUniform);
     }
 
+    const unsigned int blockCount = stream->readInt<unsigned int>();
+    if (stream->error())
+    {
+        infoLog << "Invalid program binary.";
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
+    }
+
+    ASSERT(mD3DUniformBlocks.empty());
+    for (unsigned int blockIndex = 0; blockIndex < blockCount; ++blockIndex)
+    {
+        D3DUniformBlock uniformBlock;
+        stream->readInt(&uniformBlock.psRegisterIndex);
+        stream->readInt(&uniformBlock.vsRegisterIndex);
+        mD3DUniformBlocks.push_back(uniformBlock);
+    }
+
     const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
     mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
     for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
@@ -697,15 +713,20 @@
     stream->writeInt(mUsedPixelSamplerRange);
 
     stream->writeInt(mD3DUniforms.size());
-    for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
+    for (const D3DUniform *uniform : mD3DUniforms)
     {
-        const D3DUniform &uniform = *mD3DUniforms[uniformIndex];
-
         // Type, name and arraySize are redundant, so aren't stored in the binary.
-        stream->writeInt(uniform.psRegisterIndex);
-        stream->writeInt(uniform.vsRegisterIndex);
-        stream->writeInt(uniform.registerCount);
-        stream->writeInt(uniform.registerElement);
+        stream->writeInt(uniform->psRegisterIndex);
+        stream->writeInt(uniform->vsRegisterIndex);
+        stream->writeInt(uniform->registerCount);
+        stream->writeInt(uniform->registerElement);
+    }
+
+    stream->writeInt(mD3DUniformBlocks.size());
+    for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
+    {
+        stream->writeInt(uniformBlock.psRegisterIndex);
+        stream->writeInt(uniformBlock.vsRegisterIndex);
     }
 
     stream->writeInt(mTransformFeedbackLinkedVaryings.size());
@@ -1047,6 +1068,8 @@
         return result;
     }
 
+    initUniformBlockInfo();
+
     return LinkResult(true, gl::Error(GL_NO_ERROR));
 }
 
@@ -1056,24 +1079,20 @@
     return GL_TRUE;
 }
 
-void ProgramD3D::gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
-                                        std::vector<gl::LinkedUniform> *uniforms)
+void ProgramD3D::initUniformBlockInfo()
 {
     const gl::Shader *vertexShader = mData.getAttachedVertexShader();
 
-    BlockInfoMap blockInfo;
-    std::map<std::string, size_t> blockDataSizes;
-
     for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
     {
         if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
             continue;
 
-        if (blockDataSizes.count(vertexBlock.name) > 0)
+        if (mBlockDataSizes.count(vertexBlock.name) > 0)
             continue;
 
-        size_t dataSize                  = defineUniformBlock(vertexBlock, &blockInfo);
-        blockDataSizes[vertexBlock.name] = dataSize;
+        size_t dataSize                   = getUniformBlockInfo(vertexBlock);
+        mBlockDataSizes[vertexBlock.name] = dataSize;
     }
 
     const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
@@ -1083,48 +1102,43 @@
         if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
             continue;
 
-        if (blockDataSizes.count(fragmentBlock.name) > 0)
+        if (mBlockDataSizes.count(fragmentBlock.name) > 0)
             continue;
 
-        size_t dataSize                    = defineUniformBlock(fragmentBlock, &blockInfo);
-        blockDataSizes[fragmentBlock.name] = dataSize;
+        size_t dataSize                     = getUniformBlockInfo(fragmentBlock);
+        mBlockDataSizes[fragmentBlock.name] = dataSize;
     }
+}
 
-    // Copy block info out to uniforms.
-    for (gl::LinkedUniform &linkedUniform : *uniforms)
-    {
-        const auto &infoEntry = blockInfo.find(linkedUniform.name);
-
-        if (infoEntry != blockInfo.end())
-        {
-            linkedUniform.blockInfo = infoEntry->second;
-        }
-    }
+void ProgramD3D::assignUniformBlockRegisters()
+{
+    mD3DUniformBlocks.clear();
 
     // Assign registers and update sizes.
-    const ShaderD3D *vertexShaderD3D   = GetImplAs<ShaderD3D>(vertexShader);
-    const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
+    const ShaderD3D *vertexShaderD3D   = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader());
+    const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader());
 
-    for (gl::UniformBlock &uniformBlock : *uniformBlocks)
+    for (const gl::UniformBlock &uniformBlock : mData.getUniformBlocks())
     {
         unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
 
+        D3DUniformBlock d3dUniformBlock;
+
         if (uniformBlock.vertexStaticUse)
         {
             unsigned int baseRegister =
                 vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
-            uniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement;
+            d3dUniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement;
         }
 
         if (uniformBlock.fragmentStaticUse)
         {
             unsigned int baseRegister =
                 fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
-            uniformBlock.psRegisterIndex = baseRegister + uniformBlockElement;
+            d3dUniformBlock.psRegisterIndex = baseRegister + uniformBlockElement;
         }
 
-        ASSERT(blockDataSizes.count(uniformBlock.name) == 1);
-        uniformBlock.dataSize = static_cast<unsigned int>(blockDataSizes[uniformBlock.name]);
+        mD3DUniformBlocks.push_back(d3dUniformBlock);
     }
 }
 
@@ -1174,26 +1188,36 @@
 
 gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data)
 {
+    if (mData.getUniformBlocks().empty())
+    {
+        return gl::Error(GL_NO_ERROR);
+    }
+
+    // Lazy init.
+    if (mD3DUniformBlocks.empty())
+    {
+        assignUniformBlockRegisters();
+    }
+
     mVertexUBOCache.clear();
     mFragmentUBOCache.clear();
 
     const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
     const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
 
-    const auto &uniformBlocks = mData.getUniformBlocks();
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size();
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size();
          uniformBlockIndex++)
     {
-        const gl::UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];
-        GLuint blockBinding            = mData.getUniformBlockBinding(uniformBlockIndex);
+        const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex];
+        GLuint blockBinding                 = mData.getUniformBlockBinding(uniformBlockIndex);
 
         // Unnecessary to apply an unreferenced standard or shared UBO
-        if (!uniformBlock.vertexStaticUse && !uniformBlock.fragmentStaticUse)
+        if (!uniformBlock.vertexStaticUse() && !uniformBlock.fragmentStaticUse())
         {
             continue;
         }
 
-        if (uniformBlock.vertexStaticUse)
+        if (uniformBlock.vertexStaticUse())
         {
             unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS;
             ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
@@ -1207,7 +1231,7 @@
             mVertexUBOCache[registerIndex] = blockBinding;
         }
 
-        if (uniformBlock.fragmentStaticUse)
+        if (uniformBlock.fragmentStaticUse())
         {
             unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS;
             ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
@@ -1338,7 +1362,8 @@
     setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
 }
 
-void ProgramD3D::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/,
+                                        GLuint /*uniformBlockBinding*/)
 {
 }
 
@@ -1677,8 +1702,7 @@
     }
 }
 
-size_t ProgramD3D::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock,
-                                      BlockInfoMap *blockInfoOut)
+size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock)
 {
     ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
 
@@ -1697,7 +1721,7 @@
     }
 
     GetUniformBlockInfo(interfaceBlock.fields, "", encoder, interfaceBlock.isRowMajorLayout,
-                        blockInfoOut);
+                        &mBlockInfo);
 
     return encoder->getBlockSize();
 }
@@ -1769,6 +1793,7 @@
     mUsesPointSize = false;
 
     SafeDeleteContainer(mD3DUniforms);
+    mD3DUniformBlocks.clear();
 
     SafeDelete(mVertexUniformStorage);
     SafeDelete(mFragmentUniformStorage);
@@ -1884,4 +1909,34 @@
 {
     return mD3DUniforms[mData.getUniformLocations()[location].index];
 }
+
+bool ProgramD3D::getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const
+{
+    std::string baseName = blockName;
+    gl::ParseAndStripArrayIndex(&baseName);
+
+    auto sizeIter = mBlockDataSizes.find(baseName);
+    if (sizeIter == mBlockDataSizes.end())
+    {
+        *sizeOut = 0;
+        return false;
+    }
+
+    *sizeOut = sizeIter->second;
+    return true;
+}
+
+bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName,
+                                           sh::BlockMemberInfo *memberInfoOut) const
+{
+    auto infoIter = mBlockInfo.find(memberUniformName);
+    if (infoIter == mBlockInfo.end())
+    {
+        *memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
+        return false;
+    }
+
+    *memberInfoOut = infoIter->second;
+    return true;
+}
 }