Re^5-land "Move Uniform and UBO info to the gl::Program layer."

This data was previously stored entirely in the Impl level. Move
as much as possible to the GL level, using a read-only view in the
Impl level. Some information in D3D-specific, and should be stored
separately in the Impl.

This patch has a lot of refactoring that splits the D3D and GL info,
and moves as much validation as possible to the GL layer, where it
is shared between the back-ends.

Re-land with fix for dEQP unused uniforms. The fix involves storing
a local copy of all uniform data in the GL layer. This will also
let us validate sampler indexes during draw calls at the GL layer.

Re-re-land with a fix for multiply defined symbols on Clang.

Re-re-re-land with a fix for boolean uniforms and Uniform{1234}f.

Re^4-land with a fix for boolean uniform arrays and UBO uniforms.

Re^5-land with a fix for a test warning on Linux.

BUG=angleproject:1123
TEST=end2end_tests, bots, dEQP GLES3.ubo and GLES2.uniform_api

Change-Id: I03afcd446d9e74573c4d4c712ed7407b91d8001c
Reviewed-on: https://chromium-review.googlesource.com/299180
Reviewed-by: 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 13415a3..cfa7f8a 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -171,8 +171,92 @@
     return packedVaryings;
 }
 
+template <typename VarT>
+void GetUniformBlockInfo(const std::vector<VarT> &fields,
+                         const std::string &prefix,
+                         sh::BlockLayoutEncoder *encoder,
+                         bool inRowMajorLayout,
+                         std::map<std::string, sh::BlockMemberInfo> *blockInfoOut)
+{
+    for (const VarT &field : fields)
+    {
+        const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
+
+        if (field.isStruct())
+        {
+            bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
+
+            for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+            {
+                encoder->enterAggregateType();
+
+                const std::string uniformElementName =
+                    fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
+                GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout,
+                                    blockInfoOut);
+
+                encoder->exitAggregateType();
+            }
+        }
+        else
+        {
+            bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
+            (*blockInfoOut)[fieldName] =
+                encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
+        }
+    }
+}
+
 }  // anonymous namespace
 
+D3DUniform::D3DUniform(GLenum typeIn,
+                       const std::string &nameIn,
+                       unsigned int arraySizeIn,
+                       bool defaultBlock)
+    : type(typeIn),
+      name(nameIn),
+      arraySize(arraySizeIn),
+      data(nullptr),
+      dirty(true),
+      psRegisterIndex(GL_INVALID_INDEX),
+      vsRegisterIndex(GL_INVALID_INDEX),
+      registerCount(0),
+      registerElement(0)
+{
+    // We use data storage for default block uniforms to cache values that are sent to D3D during
+    // rendering
+    // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only)
+    if (defaultBlock)
+    {
+        size_t bytes = gl::VariableInternalSize(type) * elementCount();
+        data = new uint8_t[bytes];
+        memset(data, 0, bytes);
+
+        // TODO(jmadill): is this correct with non-square matrices?
+        registerCount = gl::VariableRowCount(type) * elementCount();
+    }
+}
+
+D3DUniform::~D3DUniform()
+{
+    SafeDeleteArray(data);
+}
+
+bool D3DUniform::isSampler() const
+{
+    return gl::IsSamplerType(type);
+}
+
+bool D3DUniform::isReferencedByVertexShader() const
+{
+    return vsRegisterIndex != GL_INVALID_INDEX;
+}
+
+bool D3DUniform::isReferencedByFragmentShader() const
+{
+    return psRegisterIndex != GL_INVALID_INDEX;
+}
+
 ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout,
                                                const Signature &signature,
                                                ShaderExecutableD3D *shaderExecutable)
@@ -356,47 +440,45 @@
     mDirtySamplerMapping = false;
 
     // Retrieve sampler uniform values
-    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+    for (const D3DUniform *d3dUniform : mD3DUniforms)
     {
-        gl::LinkedUniform *targetUniform = mUniforms[uniformIndex];
+        if (!d3dUniform->dirty)
+            continue;
 
-        if (targetUniform->dirty)
+        if (!d3dUniform->isSampler())
+            continue;
+
+        int count = d3dUniform->elementCount();
+        const GLint(*v)[4] = reinterpret_cast<const GLint(*)[4]>(d3dUniform->data);
+
+        if (d3dUniform->isReferencedByFragmentShader())
         {
-            if (gl::IsSamplerType(targetUniform->type))
+            unsigned int firstIndex = d3dUniform->psRegisterIndex;
+
+            for (int i = 0; i < count; i++)
             {
-                int count = targetUniform->elementCount();
-                GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
+                unsigned int samplerIndex = firstIndex + i;
 
-                if (targetUniform->isReferencedByFragmentShader())
+                if (samplerIndex < mSamplersPS.size())
                 {
-                    unsigned int firstIndex = targetUniform->psRegisterIndex;
-
-                    for (int i = 0; i < count; i++)
-                    {
-                        unsigned int samplerIndex = firstIndex + i;
-
-                        if (samplerIndex < mSamplersPS.size())
-                        {
-                            ASSERT(mSamplersPS[samplerIndex].active);
-                            mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
-                        }
-                    }
+                    ASSERT(mSamplersPS[samplerIndex].active);
+                    mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
                 }
+            }
+        }
 
-                if (targetUniform->isReferencedByVertexShader())
+        if (d3dUniform->isReferencedByVertexShader())
+        {
+            unsigned int firstIndex = d3dUniform->vsRegisterIndex;
+
+            for (int i = 0; i < count; i++)
+            {
+                unsigned int samplerIndex = firstIndex + i;
+
+                if (samplerIndex < mSamplersVS.size())
                 {
-                    unsigned int firstIndex = targetUniform->vsRegisterIndex;
-
-                    for (int i = 0; i < count; i++)
-                    {
-                        unsigned int samplerIndex = firstIndex + i;
-
-                        if (samplerIndex < mSamplersVS.size())
-                        {
-                            ASSERT(mSamplersVS[samplerIndex].active);
-                            mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
-                        }
-                    }
+                    ASSERT(mSamplersVS[samplerIndex].active);
+                    mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
                 }
             }
         }
@@ -505,6 +587,8 @@
 
 LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
 {
+    reset();
+
     DeviceIdentifier binaryDeviceIdentifier = { 0 };
     stream->readBytes(reinterpret_cast<unsigned char*>(&binaryDeviceIdentifier), sizeof(DeviceIdentifier));
 
@@ -559,79 +643,21 @@
         return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
-    mUniforms.resize(uniformCount);
+    const auto &linkedUniforms = mData.getUniforms();
+    ASSERT(mD3DUniforms.empty());
     for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
     {
-        GLenum type = stream->readInt<GLenum>();
-        GLenum precision = stream->readInt<GLenum>();
-        std::string name = stream->readString();
-        unsigned int arraySize = stream->readInt<unsigned int>();
-        int blockIndex = stream->readInt<int>();
+        const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex];
 
-        int offset = stream->readInt<int>();
-        int arrayStride = stream->readInt<int>();
-        int matrixStride = stream->readInt<int>();
-        bool isRowMajorMatrix = stream->readBool();
+        D3DUniform *d3dUniform =
+            new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize,
+                           linkedUniform.isInDefaultBlock());
+        stream->readInt(&d3dUniform->psRegisterIndex);
+        stream->readInt(&d3dUniform->vsRegisterIndex);
+        stream->readInt(&d3dUniform->registerCount);
+        stream->readInt(&d3dUniform->registerElement);
 
-        const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
-
-        gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
-
-        stream->readInt(&uniform->psRegisterIndex);
-        stream->readInt(&uniform->vsRegisterIndex);
-        stream->readInt(&uniform->registerCount);
-        stream->readInt(&uniform->registerElement);
-
-        mUniforms[uniformIndex] = uniform;
-    }
-
-    const unsigned int uniformIndexCount = stream->readInt<unsigned int>();
-    if (stream->error())
-    {
-        infoLog << "Invalid program binary.";
-        return LinkResult(false, gl::Error(GL_NO_ERROR));
-    }
-
-    for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
-    {
-        GLuint location;
-        stream->readInt(&location);
-
-        gl::VariableLocation variable;
-        stream->readString(&variable.name);
-        stream->readInt(&variable.element);
-        stream->readInt(&variable.index);
-
-        mUniformIndex[location] = variable;
-    }
-
-    unsigned int uniformBlockCount = stream->readInt<unsigned int>();
-    if (stream->error())
-    {
-        infoLog << "Invalid program binary.";
-        return LinkResult(false, gl::Error(GL_NO_ERROR));
-    }
-
-    mUniformBlocks.resize(uniformBlockCount);
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
-    {
-        std::string name = stream->readString();
-        unsigned int elementIndex = stream->readInt<unsigned int>();
-        unsigned int dataSize = stream->readInt<unsigned int>();
-
-        gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize);
-
-        stream->readInt(&uniformBlock->psRegisterIndex);
-        stream->readInt(&uniformBlock->vsRegisterIndex);
-
-        unsigned int numMembers = stream->readInt<unsigned int>();
-        uniformBlock->memberUniformIndexes.resize(numMembers);
-        for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
-        {
-            stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
-        }
-
-        mUniformBlocks[uniformBlockIndex] = uniformBlock;
+        mD3DUniforms.push_back(d3dUniform);
     }
 
     const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
@@ -805,59 +831,18 @@
     stream->writeInt(mUsedVertexSamplerRange);
     stream->writeInt(mUsedPixelSamplerRange);
 
-    stream->writeInt(mUniforms.size());
-    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+    stream->writeInt(mD3DUniforms.size());
+    for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
     {
-        const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
+        const D3DUniform &uniform = *mD3DUniforms[uniformIndex];
 
-        stream->writeInt(uniform.type);
-        stream->writeInt(uniform.precision);
-        stream->writeString(uniform.name);
-        stream->writeInt(uniform.arraySize);
-        stream->writeInt(uniform.blockIndex);
-
-        stream->writeInt(uniform.blockInfo.offset);
-        stream->writeInt(uniform.blockInfo.arrayStride);
-        stream->writeInt(uniform.blockInfo.matrixStride);
-        stream->writeInt(uniform.blockInfo.isRowMajorMatrix);
-
+        // 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(mUniformIndex.size());
-    for (const auto &uniform : mUniformIndex)
-    {
-        GLuint location = uniform.first;
-        stream->writeInt(location);
-
-        const gl::VariableLocation &variable = uniform.second;
-        stream->writeString(variable.name);
-        stream->writeInt(variable.element);
-        stream->writeInt(variable.index);
-    }
-
-    stream->writeInt(mUniformBlocks.size());
-    for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
-    {
-        const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
-
-        stream->writeString(uniformBlock.name);
-        stream->writeInt(uniformBlock.elementIndex);
-        stream->writeInt(uniformBlock.dataSize);
-
-        stream->writeInt(uniformBlock.memberUniformIndexes.size());
-        for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
-        {
-            stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
-        }
-
-        stream->writeInt(uniformBlock.psRegisterIndex);
-        stream->writeInt(uniformBlock.vsRegisterIndex);
-    }
-
     stream->writeInt(mTransformFeedbackLinkedVaryings.size());
     for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
     {
@@ -1126,6 +1111,18 @@
 
 LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
 {
+    reset();
+
+    // TODO(jmadill): structures containing samplers
+    for (const gl::LinkedUniform &linkedUniform : mData.getUniforms())
+    {
+        if (linkedUniform.isSampler() && linkedUniform.isField())
+        {
+            infoLog << "Structures containing samplers not currently supported in D3D.";
+            return LinkResult(false, gl::Error(GL_NO_ERROR));
+        }
+    }
+
     const gl::Shader *vertexShader   = mData.getAttachedVertexShader();
     const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
 
@@ -1175,12 +1172,7 @@
 
     initSemanticIndex();
 
-    if (!defineUniforms(infoLog, *data.caps))
-    {
-        return LinkResult(false, gl::Error(GL_NO_ERROR));
-    }
-
-    defineUniformBlocks(*data.caps);
+    assignUniformRegisters();
 
     gatherTransformFeedbackVaryings(linkedVaryings);
 
@@ -1200,24 +1192,96 @@
     return validateSamplers(infoLog, caps);
 }
 
+void ProgramD3D::gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+                                        std::vector<gl::LinkedUniform> *uniforms)
+{
+    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)
+            continue;
+
+        size_t dataSize                  = defineUniformBlock(vertexBlock, &blockInfo);
+        blockDataSizes[vertexBlock.name] = dataSize;
+    }
+
+    const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+
+    for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+    {
+        if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
+            continue;
+
+        if (blockDataSizes.count(fragmentBlock.name) > 0)
+            continue;
+
+        size_t dataSize                    = defineUniformBlock(fragmentBlock, &blockInfo);
+        blockDataSizes[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;
+        }
+    }
+
+    // Assign registers and update sizes.
+    const ShaderD3D *vertexShaderD3D   = GetImplAs<ShaderD3D>(vertexShader);
+    const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
+
+    for (gl::UniformBlock &uniformBlock : *uniformBlocks)
+    {
+        unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
+
+        if (uniformBlock.vertexStaticUse)
+        {
+            unsigned int baseRegister =
+                vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+            uniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement;
+        }
+
+        if (uniformBlock.fragmentStaticUse)
+        {
+            unsigned int baseRegister =
+                fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+            uniformBlock.psRegisterIndex = baseRegister + uniformBlockElement;
+        }
+
+        ASSERT(blockDataSizes.count(uniformBlock.name) == 1);
+        uniformBlock.dataSize = static_cast<unsigned int>(blockDataSizes[uniformBlock.name]);
+    }
+}
+
 void ProgramD3D::initializeUniformStorage()
 {
     // Compute total default block size
     unsigned int vertexRegisters = 0;
     unsigned int fragmentRegisters = 0;
-    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+    for (const D3DUniform *d3dUniform : mD3DUniforms)
     {
-        const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
-        if (!gl::IsSamplerType(uniform.type))
+        if (!d3dUniform->isSampler())
         {
-            if (uniform.isReferencedByVertexShader())
+            if (d3dUniform->isReferencedByVertexShader())
             {
-                vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
+                vertexRegisters = std::max(vertexRegisters,
+                                           d3dUniform->vsRegisterIndex + d3dUniform->registerCount);
             }
-            if (uniform.isReferencedByFragmentShader())
+            if (d3dUniform->isReferencedByFragmentShader())
             {
-                fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
+                fragmentRegisters = std::max(
+                    fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount);
             }
         }
     }
@@ -1230,15 +1294,15 @@
 {
     updateSamplerMapping();
 
-    gl::Error error = mRenderer->applyUniforms(*this, mUniforms);
+    gl::Error error = mRenderer->applyUniforms(*this, mD3DUniforms);
     if (error.isError())
     {
         return error;
     }
 
-    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+    for (D3DUniform *d3dUniform : mD3DUniforms)
     {
-        mUniforms[uniformIndex]->dirty = false;
+        d3dUniform->dirty = false;
     }
 
     return gl::Error(GL_NO_ERROR);
@@ -1252,22 +1316,22 @@
     const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
     const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
 
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
+    const auto &uniformBlocks = mData.getUniformBlocks();
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size();
+         uniformBlockIndex++)
     {
-        gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex];
+        const gl::UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];
         GLuint blockBinding            = mData.getUniformBlockBinding(uniformBlockIndex);
 
-        ASSERT(uniformBlock);
-
         // Unnecessary to apply an unreferenced standard or shared UBO
-        if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
+        if (!uniformBlock.vertexStaticUse && !uniformBlock.fragmentStaticUse)
         {
             continue;
         }
 
-        if (uniformBlock->isReferencedByVertexShader())
+        if (uniformBlock.vertexStaticUse)
         {
-            unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
+            unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS;
             ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
 
             if (mVertexUBOCache.size() <= registerIndex)
@@ -1279,9 +1343,9 @@
             mVertexUBOCache[registerIndex] = blockBinding;
         }
 
-        if (uniformBlock->isReferencedByFragmentShader())
+        if (uniformBlock.fragmentStaticUse)
         {
-            unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
+            unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS;
             ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
 
             if (mFragmentUBOCache.size() <= registerIndex)
@@ -1297,31 +1361,11 @@
     return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache);
 }
 
-void ProgramD3D::assignUniformBlockRegister(gl::UniformBlock *uniformBlock,
-                                            GLenum shader,
-                                            unsigned int registerIndex,
-                                            const gl::Caps &caps)
-{
-    // Validation done in the GL-level Program.
-    if (shader == GL_VERTEX_SHADER)
-    {
-        uniformBlock->vsRegisterIndex = registerIndex;
-        ASSERT(registerIndex < caps.maxVertexUniformBlocks);
-    }
-    else if (shader == GL_FRAGMENT_SHADER)
-    {
-        uniformBlock->psRegisterIndex = registerIndex;
-        ASSERT(registerIndex < caps.maxFragmentUniformBlocks);
-    }
-    else UNREACHABLE();
-}
-
 void ProgramD3D::dirtyAllUniforms()
 {
-    unsigned int numUniforms = static_cast<unsigned int>(mUniforms.size());
-    for (unsigned int index = 0; index < numUniforms; index++)
+    for (D3DUniform *d3dUniform : mD3DUniforms)
     {
-        mUniforms[index]->dirty = true;
+        d3dUniform->dirty = true;
     }
 }
 
@@ -1430,93 +1474,68 @@
     setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
 }
 
-void ProgramD3D::getUniformfv(GLint location, GLfloat *params)
+void ProgramD3D::assignUniformRegisters()
 {
-    getUniformv(location, params, GL_FLOAT);
-}
+    const gl::Shader *vertexShader   = mData.getAttachedVertexShader();
+    const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
 
-void ProgramD3D::getUniformiv(GLint location, GLint *params)
-{
-    getUniformv(location, params, GL_INT);
-}
+    for (const sh::Uniform &vertexUniform : vertexShader->getUniforms())
 
-void ProgramD3D::getUniformuiv(GLint location, GLuint *params)
-{
-    getUniformv(location, params, GL_UNSIGNED_INT);
-}
-
-bool ProgramD3D::defineUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
-{
-    const gl::Shader *vertexShader                 = mData.getAttachedVertexShader();
-    const std::vector<sh::Uniform> &vertexUniforms = vertexShader->getUniforms();
-    const ShaderD3D *vertexShaderD3D               = GetImplAs<ShaderD3D>(vertexShader);
-
-    if (vertexUniforms.size() > caps.maxVertexUniformVectors)
     {
-        infoLog << "Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS ("
-                << caps.maxVertexUniformVectors << ").";
-        return false;
-    }
-
-    for (const sh::Uniform &uniform : vertexUniforms)
-    {
-        if (uniform.staticUse)
+        if (vertexUniform.staticUse)
         {
-            unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
-                vertexShaderD3D->getUniformRegister(uniform.name);
-            defineUniformBase(vertexShaderD3D, uniform, registerBase);
+            assignUniformRegistersBase(vertexShaderD3D, vertexUniform);
         }
     }
 
-    const gl::Shader *fragmentShader                 = mData.getAttachedFragmentShader();
-    const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader->getUniforms();
-    const ShaderD3D *fragmentShaderD3D               = GetImplAs<ShaderD3D>(fragmentShader);
+    const gl::Shader *fragmentShader   = mData.getAttachedFragmentShader();
+    const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
 
-    if (fragmentUniforms.size() > caps.maxFragmentUniformVectors)
+    for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms())
     {
-        infoLog << "Vertex shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS ("
-                << caps.maxFragmentUniformVectors << ").";
-        return false;
-    }
-
-    for (const sh::Uniform &uniform : fragmentUniforms)
-    {
-        if (uniform.staticUse)
+        if (fragmentUniform.staticUse)
         {
-            unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
-                fragmentShaderD3D->getUniformRegister(uniform.name);
-            defineUniformBase(fragmentShaderD3D, uniform, registerBase);
+            assignUniformRegistersBase(fragmentShaderD3D, fragmentUniform);
         }
     }
 
-    // TODO(jmadill): move the validation part to gl::Program
-    if (!indexUniforms(infoLog, caps))
-    {
-        return false;
-    }
-
+    assignAllSamplerRegisters();
     initializeUniformStorage();
-
-    return true;
 }
 
-void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister)
+void ProgramD3D::assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform)
 {
-    if (uniformRegister == GL_INVALID_INDEX)
+    if (uniform.isBuiltIn())
     {
-        defineUniform(shader, uniform, uniform.name, nullptr);
+        assignUniformRegisters(shader, uniform, uniform.name, nullptr);
         return;
     }
 
+    unsigned int startRegister = shader->getUniformRegister(uniform.name);
     ShShaderOutput outputType = shader->getCompilerOutputType();
     sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
-    encoder.skipRegisters(uniformRegister);
+    encoder.skipRegisters(startRegister);
 
-    defineUniform(shader, uniform, uniform.name, &encoder);
+    assignUniformRegisters(shader, uniform, uniform.name, &encoder);
 }
 
-void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform,
-                               const std::string &fullName, sh::HLSLBlockEncoder *encoder)
+D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
+{
+    for (D3DUniform *d3dUniform : mD3DUniforms)
+    {
+        if (d3dUniform->name == name)
+        {
+            return d3dUniform;
+        }
+    }
+
+    return nullptr;
+}
+
+void ProgramD3D::assignUniformRegisters(const ShaderD3D *shader,
+                                        const sh::ShaderVariable &uniform,
+                                        const std::string &fullName,
+                                        sh::HLSLBlockEncoder *encoder)
 {
     if (uniform.isStruct())
     {
@@ -1532,86 +1551,68 @@
                 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
                 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
 
-                defineUniform(shader, field, fieldFullName, encoder);
+                assignUniformRegisters(shader, field, fieldFullName, encoder);
             }
 
             if (encoder)
                 encoder->exitAggregateType();
         }
+        return;
     }
-    else // Not a struct
+
+    // Not a struct. Arrays are treated as aggregate types.
+    if (uniform.isArray() && encoder)
     {
-        // Arrays are treated as aggregate types
-        if (uniform.isArray() && encoder)
-        {
-            encoder->enterAggregateType();
-        }
+        encoder->enterAggregateType();
+    }
 
-        gl::LinkedUniform *linkedUniform = getUniformByName(fullName);
+    // Advance the uniform offset, to track registers allocation for structs
+    sh::BlockMemberInfo blockInfo =
+        encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false)
+                : sh::BlockMemberInfo::getDefaultBlockInfo();
 
-        // Advance the uniform offset, to track registers allocation for structs
-        sh::BlockMemberInfo blockInfo = encoder ?
-            encoder->encodeType(uniform.type, uniform.arraySize, false) :
-            sh::BlockMemberInfo::getDefaultBlockInfo();
+    D3DUniform *d3dUniform = getD3DUniformByName(fullName);
 
-        if (!linkedUniform)
-        {
-            linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
-                                                  -1, sh::BlockMemberInfo::getDefaultBlockInfo());
-            ASSERT(linkedUniform);
+    if (!d3dUniform)
+    {
+        // We're building the list twice, make sure we use the same indexing. Special case
+        // built-ins.
+        ASSERT(fullName.compare(0, 3, "gl_") == 0 ||
+               mData.getUniformIndex(fullName) == static_cast<GLint>(mD3DUniforms.size()));
 
-            if (encoder)
-                linkedUniform->registerElement = static_cast<unsigned int>(
-                    sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
-            mUniforms.push_back(linkedUniform);
-        }
+        d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true);
+        mD3DUniforms.push_back(d3dUniform);
 
         if (encoder)
         {
-            if (shader->getShaderType() == GL_FRAGMENT_SHADER)
-            {
-                linkedUniform->psRegisterIndex =
-                    static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
-            }
-            else if (shader->getShaderType() == GL_VERTEX_SHADER)
-            {
-                linkedUniform->vsRegisterIndex =
-                    static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
-            }
-            else UNREACHABLE();
+            d3dUniform->registerElement =
+                static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
         }
+    }
+
+    if (encoder)
+    {
+        unsigned int reg =
+            static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
+        if (shader->getShaderType() == GL_FRAGMENT_SHADER)
+        {
+            d3dUniform->psRegisterIndex = reg;
+        }
+        else if (shader->getShaderType() == GL_VERTEX_SHADER)
+        {
+            d3dUniform->vsRegisterIndex = reg;
+        }
+        else
+            UNREACHABLE();
 
         // Arrays are treated as aggregate types
-        if (uniform.isArray() && encoder)
+        if (uniform.isArray())
         {
             encoder->exitAggregateType();
         }
     }
 }
 
-void ProgramD3D::defineUniformBlocks(const gl::Caps &caps)
-{
-    const gl::Shader *vertexShader = mData.getAttachedVertexShader();
-
-    for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
-    {
-        if (vertexBlock.staticUse || vertexBlock.layout != sh::BLOCKLAYOUT_PACKED)
-        {
-            defineUniformBlock(*vertexShader, vertexBlock, caps);
-        }
-    }
-
-    const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
-
-    for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
-    {
-        if (fragmentBlock.staticUse || fragmentBlock.layout != sh::BLOCKLAYOUT_PACKED)
-        {
-            defineUniformBlock(*fragmentShader, fragmentBlock, caps);
-        }
-    }
-}
-
 template <typename T>
 static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
 {
@@ -1623,22 +1624,22 @@
 }
 
 template <typename T>
-void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
+void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType)
 {
     const int components = gl::VariableComponentCount(targetUniformType);
     const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType);
 
-    gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+    D3DUniform *targetUniform = getD3DUniformFromLocation(location);
 
-    int elementCount = targetUniform->elementCount();
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+    unsigned int elementCount = targetUniform->elementCount();
+    unsigned int arrayElement = mData.getUniformLocations()[location].element;
+    unsigned int count        = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
 
     if (targetUniform->type == targetUniformType)
     {
-        T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
+        T *target = reinterpret_cast<T *>(targetUniform->data) + arrayElement * 4;
 
-        for (int i = 0; i < count; i++)
+        for (unsigned int i = 0; i < count; i++)
         {
             T *dest = target + (i * 4);
             const T *source = v + (i * components);
@@ -1655,9 +1656,9 @@
     }
     else if (targetUniform->type == targetBoolType)
     {
-        GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+        GLint *boolParams = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
 
-        for (int i = 0; i < count; i++)
+        for (unsigned int i = 0; i < count; i++)
         {
             GLint *dest = boolParams + (i * 4);
             const T *source = v + (i * components);
@@ -1672,15 +1673,15 @@
             }
         }
     }
-    else if (gl::IsSamplerType(targetUniform->type))
+    else if (targetUniform->isSampler())
     {
         ASSERT(targetUniformType == GL_INT);
 
-        GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+        GLint *target = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
 
         bool wasDirty = targetUniform->dirty;
 
-        for (int i = 0; i < count; i++)
+        for (unsigned int i = 0; i < count; i++)
         {
             GLint *dest = target + (i * 4);
             const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
@@ -1768,17 +1769,23 @@
 }
 
 template <int cols, int rows>
-void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
+void ProgramD3D::setUniformMatrixfv(GLint location,
+                                    GLsizei countIn,
+                                    GLboolean transpose,
+                                    const GLfloat *value,
+                                    GLenum targetUniformType)
 {
-    gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+    D3DUniform *targetUniform = getD3DUniformFromLocation(location);
 
-    int elementCount = targetUniform->elementCount();
+    unsigned int elementCount = targetUniform->elementCount();
+    unsigned int arrayElement = mData.getUniformLocations()[location].element;
+    unsigned int count        = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
     const unsigned int targetMatrixStride = (4 * rows);
-    GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
+    GLfloat *target =
+        (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride);
 
-    for (int i = 0; i < count; i++)
+    for (unsigned int i = 0; i < count; i++)
     {
         // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
         if (transpose == GL_FALSE)
@@ -1794,186 +1801,63 @@
     }
 }
 
-template <typename T>
-void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType)
+size_t ProgramD3D::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock,
+                                      BlockInfoMap *blockInfoOut)
 {
-    gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
 
-    if (gl::IsMatrixType(targetUniform->type))
+    // define member uniforms
+    sh::Std140BlockEncoder std140Encoder;
+    sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
+    sh::BlockLayoutEncoder *encoder = nullptr;
+
+    if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
     {
-        const int rows = gl::VariableRowCount(targetUniform->type);
-        const int cols = gl::VariableColumnCount(targetUniform->type);
-        transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
-    }
-    else if (uniformType == gl::VariableComponentType(targetUniform->type))
-    {
-        unsigned int size = gl::VariableComponentCount(targetUniform->type);
-        memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
-                size * sizeof(T));
+        encoder = &std140Encoder;
     }
     else
     {
-        unsigned int size = gl::VariableComponentCount(targetUniform->type);
-        switch (gl::VariableComponentType(targetUniform->type))
-        {
-          case GL_BOOL:
-            {
-                GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                for (unsigned int i = 0; i < size; i++)
-                {
-                    params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
-                }
-            }
-            break;
-
-          case GL_FLOAT:
-            {
-                GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                for (unsigned int i = 0; i < size; i++)
-                {
-                    params[i] = static_cast<T>(roundf(floatParams[i]));
-                }
-            }
-            break;
-
-          case GL_INT:
-            {
-                GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                for (unsigned int i = 0; i < size; i++)
-                {
-                    params[i] = static_cast<T>(intParams[i]);
-                }
-            }
-            break;
-
-          case GL_UNSIGNED_INT:
-            {
-                GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                for (unsigned int i = 0; i < size; i++)
-                {
-                    params[i] = static_cast<T>(uintParams[i]);
-                }
-            }
-            break;
-
-          default: UNREACHABLE();
-        }
+        encoder = &hlslEncoder;
     }
+
+    GetUniformBlockInfo(interfaceBlock.fields, "", encoder, interfaceBlock.isRowMajorLayout,
+                        blockInfoOut);
+
+    return encoder->getBlockSize();
 }
 
-template <typename VarT>
-void ProgramD3D::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
-                                           sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
-                                           bool inRowMajorLayout)
+void ProgramD3D::assignAllSamplerRegisters()
 {
-    for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
+    for (const D3DUniform *d3dUniform : mD3DUniforms)
     {
-        const VarT &field = fields[uniformIndex];
-        const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
-
-        if (field.isStruct())
+        if (d3dUniform->isSampler())
         {
-            bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
-
-            for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
-            {
-                encoder->enterAggregateType();
-
-                const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
-                defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
-
-                encoder->exitAggregateType();
-            }
-        }
-        else
-        {
-            bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
-
-            sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
-
-            gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
-                                                          blockIndex, memberInfo);
-
-            // add to uniform list, but not index, since uniform block uniforms have no location
-            blockUniformIndexes->push_back(static_cast<GLenum>(mUniforms.size()));
-            mUniforms.push_back(newUniform);
+            assignSamplerRegisters(d3dUniform);
         }
     }
 }
 
-void ProgramD3D::defineUniformBlock(const gl::Shader &shader,
-                                    const sh::InterfaceBlock &interfaceBlock,
-                                    const gl::Caps &caps)
+void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform)
 {
-    const ShaderD3D* shaderD3D = GetImplAs<ShaderD3D>(&shader);
+    ASSERT(d3dUniform->isSampler());
+    ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX ||
+           d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
 
-    // create uniform block entries if they do not exist
-    if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
+    if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX)
     {
-        std::vector<unsigned int> blockUniformIndexes;
-        const unsigned int blockIndex = static_cast<unsigned int>(mUniformBlocks.size());
-
-        // define member uniforms
-        sh::BlockLayoutEncoder *encoder = NULL;
-
-        if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
-        {
-            encoder = new sh::Std140BlockEncoder;
-        }
-        else
-        {
-            encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
-        }
-        ASSERT(encoder);
-
-        defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
-
-        unsigned int dataSize = static_cast<unsigned int>(encoder->getBlockSize());
-
-        // create all the uniform blocks
-        if (interfaceBlock.arraySize > 0)
-        {
-            for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
-            {
-                gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
-                newUniformBlock->memberUniformIndexes = blockUniformIndexes;
-                mUniformBlocks.push_back(newUniformBlock);
-            }
-        }
-        else
-        {
-            gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
-            newUniformBlock->memberUniformIndexes = blockUniformIndexes;
-            mUniformBlocks.push_back(newUniformBlock);
-        }
+        AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+                       mSamplersVS, &mUsedVertexSamplerRange);
     }
 
-    if (interfaceBlock.staticUse)
+    if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
     {
-        // Assign registers to the uniform blocks
-        const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
-        const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
-        ASSERT(blockIndex != GL_INVALID_INDEX);
-        ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
-
-        unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
-
-        for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
-        {
-            gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
-            ASSERT(uniformBlock->name == interfaceBlock.name);
-
-            assignUniformBlockRegister(uniformBlock, shader.getType(),
-                                       interfaceBlockRegister + uniformBlockElement, caps);
-        }
+        AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+                       mSamplersPS, &mUsedPixelSamplerRange);
     }
 }
 
-bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex,
+// static
+void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex,
                                 GLenum samplerType,
                                 unsigned int samplerCount,
                                 std::vector<Sampler> &outSamplers,
@@ -1983,103 +1867,18 @@
 
     do
     {
-        if (samplerIndex < outSamplers.size())
-        {
-            Sampler& sampler = outSamplers[samplerIndex];
-            sampler.active = true;
-            sampler.textureType = GetTextureType(samplerType);
-            sampler.logicalTextureUnit = 0;
-            *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
-        }
-        else
-        {
-            return false;
-        }
-
+        ASSERT(samplerIndex < outSamplers.size());
+        Sampler *sampler            = &outSamplers[samplerIndex];
+        sampler->active             = true;
+        sampler->textureType        = GetTextureType(samplerType);
+        sampler->logicalTextureUnit = 0;
+        *outUsedRange               = std::max(samplerIndex + 1, *outUsedRange);
         samplerIndex++;
     } while (samplerIndex < startSamplerIndex + samplerCount);
-
-    return true;
-}
-
-bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps)
-{
-    ASSERT(gl::IsSamplerType(uniform.type));
-    ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
-
-    if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
-    {
-        if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
-                            &mUsedVertexSamplerRange))
-        {
-            infoLog << "Vertex shader sampler count exceeds the maximum vertex texture units ("
-                    << mSamplersVS.size() << ").";
-            return false;
-        }
-
-        unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors;
-        if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
-        {
-            infoLog << "Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS ("
-                    << caps.maxVertexUniformVectors << ").";
-            return false;
-        }
-    }
-
-    if (uniform.psRegisterIndex != GL_INVALID_INDEX)
-    {
-        if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
-                            &mUsedPixelSamplerRange))
-        {
-            infoLog << "Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
-                    << mSamplersPS.size() << ").";
-            return false;
-        }
-
-        unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors;
-        if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
-        {
-            infoLog << "Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS ("
-                    << caps.maxFragmentUniformVectors << ").";
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
-{
-    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
-    {
-        const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
-        if (gl::IsSamplerType(uniform.type))
-        {
-            if (!indexSamplerUniform(uniform, infoLog, caps))
-            {
-                return false;
-            }
-        }
-
-        for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
-        {
-            if (!uniform.isBuiltIn())
-            {
-                // Assign in-order uniform locations
-                mUniformIndex[static_cast<GLuint>(mUniformIndex.size())] = gl::VariableLocation(
-                    uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex));
-            }
-        }
-    }
-
-    return true;
 }
 
 void ProgramD3D::reset()
 {
-    ProgramImpl::reset();
-
     SafeDeleteContainer(mVertexExecutables);
     SafeDeleteContainer(mPixelExecutables);
     SafeDelete(mGeometryExecutable);
@@ -2094,6 +1893,8 @@
     mPixelShaderKey.clear();
     mUsesPointSize = false;
 
+    SafeDeleteContainer(mD3DUniforms);
+
     SafeDelete(mVertexUniformStorage);
     SafeDelete(mFragmentUniformStorage);
 
@@ -2203,4 +2004,9 @@
         }
     }
 }
+
+D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location)
+{
+    return mD3DUniforms[mData.getUniformLocations()[location].index];
+}
 }