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

Seems to be failing the dEQP-GLES2.functional.uniform_api tests relating to boolean arrays.

BUG=angleproject:1123

This reverts commit 892a6a4b17b35e89898be8b4605c1ee595d3ae13.

Change-Id: Ifc4ce3ca806ef88a02ac6f693334ac37ce098a88
Reviewed-on: https://chromium-review.googlesource.com/298520
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 d9962dc..13415a3 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -171,92 +171,8 @@
     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)
@@ -440,45 +356,47 @@
     mDirtySamplerMapping = false;
 
     // Retrieve sampler uniform values
-    for (const D3DUniform *d3dUniform : mD3DUniforms)
+    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
     {
-        if (!d3dUniform->dirty)
-            continue;
+        gl::LinkedUniform *targetUniform = mUniforms[uniformIndex];
 
-        if (!d3dUniform->isSampler())
-            continue;
-
-        int count = d3dUniform->elementCount();
-        const GLint(*v)[4] = reinterpret_cast<const GLint(*)[4]>(d3dUniform->data);
-
-        if (d3dUniform->isReferencedByFragmentShader())
+        if (targetUniform->dirty)
         {
-            unsigned int firstIndex = d3dUniform->psRegisterIndex;
-
-            for (int i = 0; i < count; i++)
+            if (gl::IsSamplerType(targetUniform->type))
             {
-                unsigned int samplerIndex = firstIndex + i;
+                int count = targetUniform->elementCount();
+                GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
 
-                if (samplerIndex < mSamplersPS.size())
+                if (targetUniform->isReferencedByFragmentShader())
                 {
-                    ASSERT(mSamplersPS[samplerIndex].active);
-                    mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
+                    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];
+                        }
+                    }
                 }
-            }
-        }
 
-        if (d3dUniform->isReferencedByVertexShader())
-        {
-            unsigned int firstIndex = d3dUniform->vsRegisterIndex;
-
-            for (int i = 0; i < count; i++)
-            {
-                unsigned int samplerIndex = firstIndex + i;
-
-                if (samplerIndex < mSamplersVS.size())
+                if (targetUniform->isReferencedByVertexShader())
                 {
-                    ASSERT(mSamplersVS[samplerIndex].active);
-                    mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
+                    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];
+                        }
+                    }
                 }
             }
         }
@@ -587,8 +505,6 @@
 
 LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
 {
-    reset();
-
     DeviceIdentifier binaryDeviceIdentifier = { 0 };
     stream->readBytes(reinterpret_cast<unsigned char*>(&binaryDeviceIdentifier), sizeof(DeviceIdentifier));
 
@@ -643,21 +559,79 @@
         return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
-    const auto &linkedUniforms = mData.getUniforms();
-    ASSERT(mD3DUniforms.empty());
+    mUniforms.resize(uniformCount);
     for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
     {
-        const gl::LinkedUniform &linkedUniform = linkedUniforms[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>();
 
-        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);
+        int offset = stream->readInt<int>();
+        int arrayStride = stream->readInt<int>();
+        int matrixStride = stream->readInt<int>();
+        bool isRowMajorMatrix = stream->readBool();
 
-        mD3DUniforms.push_back(d3dUniform);
+        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;
     }
 
     const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
@@ -831,18 +805,59 @@
     stream->writeInt(mUsedVertexSamplerRange);
     stream->writeInt(mUsedPixelSamplerRange);
 
-    stream->writeInt(mD3DUniforms.size());
-    for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
+    stream->writeInt(mUniforms.size());
+    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
     {
-        const D3DUniform &uniform = *mD3DUniforms[uniformIndex];
+        const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
 
-        // Type, name and arraySize are redundant, so aren't stored in the binary.
+        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);
+
         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++)
     {
@@ -1111,18 +1126,6 @@
 
 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();
 
@@ -1172,7 +1175,12 @@
 
     initSemanticIndex();
 
-    assignUniformRegisters();
+    if (!defineUniforms(infoLog, *data.caps))
+    {
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
+    }
+
+    defineUniformBlocks(*data.caps);
 
     gatherTransformFeedbackVaryings(linkedVaryings);
 
@@ -1192,96 +1200,24 @@
     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 (const D3DUniform *d3dUniform : mD3DUniforms)
+    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
     {
-        if (!d3dUniform->isSampler())
+        const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
+
+        if (!gl::IsSamplerType(uniform.type))
         {
-            if (d3dUniform->isReferencedByVertexShader())
+            if (uniform.isReferencedByVertexShader())
             {
-                vertexRegisters = std::max(vertexRegisters,
-                                           d3dUniform->vsRegisterIndex + d3dUniform->registerCount);
+                vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
             }
-            if (d3dUniform->isReferencedByFragmentShader())
+            if (uniform.isReferencedByFragmentShader())
             {
-                fragmentRegisters = std::max(
-                    fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount);
+                fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
             }
         }
     }
@@ -1294,15 +1230,15 @@
 {
     updateSamplerMapping();
 
-    gl::Error error = mRenderer->applyUniforms(*this, mD3DUniforms);
+    gl::Error error = mRenderer->applyUniforms(*this, mUniforms);
     if (error.isError())
     {
         return error;
     }
 
-    for (D3DUniform *d3dUniform : mD3DUniforms)
+    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
     {
-        d3dUniform->dirty = false;
+        mUniforms[uniformIndex]->dirty = false;
     }
 
     return gl::Error(GL_NO_ERROR);
@@ -1316,22 +1252,22 @@
     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();
-         uniformBlockIndex++)
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
     {
-        const gl::UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];
+        gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex];
         GLuint blockBinding            = mData.getUniformBlockBinding(uniformBlockIndex);
 
+        ASSERT(uniformBlock);
+
         // Unnecessary to apply an unreferenced standard or shared UBO
-        if (!uniformBlock.vertexStaticUse && !uniformBlock.fragmentStaticUse)
+        if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
         {
             continue;
         }
 
-        if (uniformBlock.vertexStaticUse)
+        if (uniformBlock->isReferencedByVertexShader())
         {
-            unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS;
+            unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
             ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
 
             if (mVertexUBOCache.size() <= registerIndex)
@@ -1343,9 +1279,9 @@
             mVertexUBOCache[registerIndex] = blockBinding;
         }
 
-        if (uniformBlock.fragmentStaticUse)
+        if (uniformBlock->isReferencedByFragmentShader())
         {
-            unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS;
+            unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
             ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
 
             if (mFragmentUBOCache.size() <= registerIndex)
@@ -1361,11 +1297,31 @@
     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()
 {
-    for (D3DUniform *d3dUniform : mD3DUniforms)
+    unsigned int numUniforms = static_cast<unsigned int>(mUniforms.size());
+    for (unsigned int index = 0; index < numUniforms; index++)
     {
-        d3dUniform->dirty = true;
+        mUniforms[index]->dirty = true;
     }
 }
 
@@ -1474,68 +1430,93 @@
     setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
 }
 
-void ProgramD3D::assignUniformRegisters()
+void ProgramD3D::getUniformfv(GLint location, GLfloat *params)
 {
-    const gl::Shader *vertexShader   = mData.getAttachedVertexShader();
-    const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
-
-    for (const sh::Uniform &vertexUniform : vertexShader->getUniforms())
-
-    {
-        if (vertexUniform.staticUse)
-        {
-            assignUniformRegistersBase(vertexShaderD3D, vertexUniform);
-        }
-    }
-
-    const gl::Shader *fragmentShader   = mData.getAttachedFragmentShader();
-    const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
-
-    for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms())
-    {
-        if (fragmentUniform.staticUse)
-        {
-            assignUniformRegistersBase(fragmentShaderD3D, fragmentUniform);
-        }
-    }
-
-    assignAllSamplerRegisters();
-    initializeUniformStorage();
+    getUniformv(location, params, GL_FLOAT);
 }
 
-void ProgramD3D::assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform)
+void ProgramD3D::getUniformiv(GLint location, GLint *params)
 {
-    if (uniform.isBuiltIn())
+    getUniformv(location, params, GL_INT);
+}
+
+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)
     {
-        assignUniformRegisters(shader, uniform, uniform.name, nullptr);
+        infoLog << "Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS ("
+                << caps.maxVertexUniformVectors << ").";
+        return false;
+    }
+
+    for (const sh::Uniform &uniform : vertexUniforms)
+    {
+        if (uniform.staticUse)
+        {
+            unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
+                vertexShaderD3D->getUniformRegister(uniform.name);
+            defineUniformBase(vertexShaderD3D, uniform, registerBase);
+        }
+    }
+
+    const gl::Shader *fragmentShader                 = mData.getAttachedFragmentShader();
+    const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader->getUniforms();
+    const ShaderD3D *fragmentShaderD3D               = GetImplAs<ShaderD3D>(fragmentShader);
+
+    if (fragmentUniforms.size() > caps.maxFragmentUniformVectors)
+    {
+        infoLog << "Vertex shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS ("
+                << caps.maxFragmentUniformVectors << ").";
+        return false;
+    }
+
+    for (const sh::Uniform &uniform : fragmentUniforms)
+    {
+        if (uniform.staticUse)
+        {
+            unsigned int registerBase = uniform.isBuiltIn() ? GL_INVALID_INDEX :
+                fragmentShaderD3D->getUniformRegister(uniform.name);
+            defineUniformBase(fragmentShaderD3D, uniform, registerBase);
+        }
+    }
+
+    // TODO(jmadill): move the validation part to gl::Program
+    if (!indexUniforms(infoLog, caps))
+    {
+        return false;
+    }
+
+    initializeUniformStorage();
+
+    return true;
+}
+
+void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister)
+{
+    if (uniformRegister == GL_INVALID_INDEX)
+    {
+        defineUniform(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(startRegister);
+    encoder.skipRegisters(uniformRegister);
 
-    assignUniformRegisters(shader, uniform, uniform.name, &encoder);
+    defineUniform(shader, uniform, uniform.name, &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)
+void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform,
+                               const std::string &fullName, sh::HLSLBlockEncoder *encoder)
 {
     if (uniform.isStruct())
     {
@@ -1551,64 +1532,82 @@
                 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
                 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
 
-                assignUniformRegisters(shader, field, fieldFullName, encoder);
+                defineUniform(shader, field, fieldFullName, encoder);
             }
 
             if (encoder)
                 encoder->exitAggregateType();
         }
-        return;
     }
-
-    // Not a struct. Arrays are treated as aggregate types.
-    if (uniform.isArray() && encoder)
+    else // Not a struct
     {
-        encoder->enterAggregateType();
-    }
+        // Arrays are treated as aggregate types
+        if (uniform.isArray() && encoder)
+        {
+            encoder->enterAggregateType();
+        }
 
-    // Advance the uniform offset, to track registers allocation for structs
-    sh::BlockMemberInfo blockInfo =
-        encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false)
-                : sh::BlockMemberInfo::getDefaultBlockInfo();
+        gl::LinkedUniform *linkedUniform = getUniformByName(fullName);
 
-    D3DUniform *d3dUniform = getD3DUniformByName(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();
 
-    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 (!linkedUniform)
+        {
+            linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
+                                                  -1, sh::BlockMemberInfo::getDefaultBlockInfo());
+            ASSERT(linkedUniform);
 
-        d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true);
-        mD3DUniforms.push_back(d3dUniform);
+            if (encoder)
+                linkedUniform->registerElement = static_cast<unsigned int>(
+                    sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
+            mUniforms.push_back(linkedUniform);
+        }
 
         if (encoder)
         {
-            d3dUniform->registerElement =
-                static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
+            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();
+        }
+
+        // Arrays are treated as aggregate types
+        if (uniform.isArray() && encoder)
+        {
+            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);
         }
     }
 
-    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();
+    const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
 
-        // Arrays are treated as aggregate types
-        if (uniform.isArray())
+    for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+    {
+        if (fragmentBlock.staticUse || fragmentBlock.layout != sh::BLOCKLAYOUT_PACKED)
         {
-            encoder->exitAggregateType();
+            defineUniformBlock(*fragmentShader, fragmentBlock, caps);
         }
     }
 }
@@ -1624,22 +1623,22 @@
 }
 
 template <typename T>
-void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType)
+void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
 {
     const int components = gl::VariableComponentCount(targetUniformType);
     const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType);
 
-    D3DUniform *targetUniform = getD3DUniformFromLocation(location);
+    gl::LinkedUniform *targetUniform = getUniformByLocation(location);
 
-    unsigned int elementCount = targetUniform->elementCount();
-    unsigned int arrayElement = mData.getUniformLocations()[location].element;
-    unsigned int count        = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
+    int elementCount = targetUniform->elementCount();
+
+    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
     if (targetUniform->type == targetUniformType)
     {
-        T *target = reinterpret_cast<T *>(targetUniform->data) + arrayElement * 4;
+        T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
 
-        for (unsigned int i = 0; i < count; i++)
+        for (int i = 0; i < count; i++)
         {
             T *dest = target + (i * 4);
             const T *source = v + (i * components);
@@ -1656,9 +1655,9 @@
     }
     else if (targetUniform->type == targetBoolType)
     {
-        GLint *boolParams = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
+        GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
 
-        for (unsigned int i = 0; i < count; i++)
+        for (int i = 0; i < count; i++)
         {
             GLint *dest = boolParams + (i * 4);
             const T *source = v + (i * components);
@@ -1673,15 +1672,15 @@
             }
         }
     }
-    else if (targetUniform->isSampler())
+    else if (gl::IsSamplerType(targetUniform->type))
     {
         ASSERT(targetUniformType == GL_INT);
 
-        GLint *target = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
+        GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
 
         bool wasDirty = targetUniform->dirty;
 
-        for (unsigned int i = 0; i < count; i++)
+        for (int i = 0; i < count; i++)
         {
             GLint *dest = target + (i * 4);
             const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
@@ -1769,23 +1768,17 @@
 }
 
 template <int cols, int rows>
-void ProgramD3D::setUniformMatrixfv(GLint location,
-                                    GLsizei countIn,
-                                    GLboolean transpose,
-                                    const GLfloat *value,
-                                    GLenum targetUniformType)
+void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
 {
-    D3DUniform *targetUniform = getD3DUniformFromLocation(location);
+    gl::LinkedUniform *targetUniform = getUniformByLocation(location);
 
-    unsigned int elementCount = targetUniform->elementCount();
-    unsigned int arrayElement = mData.getUniformLocations()[location].element;
-    unsigned int count        = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
+    int elementCount = targetUniform->elementCount();
 
+    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
     const unsigned int targetMatrixStride = (4 * rows);
-    GLfloat *target =
-        (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride);
+    GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
 
-    for (unsigned int i = 0; i < count; i++)
+    for (int i = 0; i < count; i++)
     {
         // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
         if (transpose == GL_FALSE)
@@ -1801,63 +1794,186 @@
     }
 }
 
-size_t ProgramD3D::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock,
-                                      BlockInfoMap *blockInfoOut)
+template <typename T>
+void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType)
 {
-    ASSERT(interfaceBlock.staticUse || interfaceBlock.layout == sh::BLOCKLAYOUT_PACKED);
+    gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
 
-    // define member uniforms
-    sh::Std140BlockEncoder std140Encoder;
-    sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
-    sh::BlockLayoutEncoder *encoder = nullptr;
-
-    if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
+    if (gl::IsMatrixType(targetUniform->type))
     {
-        encoder = &std140Encoder;
+        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));
     }
     else
     {
-        encoder = &hlslEncoder;
-    }
-
-    GetUniformBlockInfo(interfaceBlock.fields, "", encoder, interfaceBlock.isRowMajorLayout,
-                        blockInfoOut);
-
-    return encoder->getBlockSize();
-}
-
-void ProgramD3D::assignAllSamplerRegisters()
-{
-    for (const D3DUniform *d3dUniform : mD3DUniforms)
-    {
-        if (d3dUniform->isSampler())
+        unsigned int size = gl::VariableComponentCount(targetUniform->type);
+        switch (gl::VariableComponentType(targetUniform->type))
         {
-            assignSamplerRegisters(d3dUniform);
+          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();
         }
     }
 }
 
-void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform)
+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)
 {
-    ASSERT(d3dUniform->isSampler());
-    ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX ||
-           d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
-
-    if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX)
+    for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
     {
-        AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
-                       mSamplersVS, &mUsedVertexSamplerRange);
-    }
+        const VarT &field = fields[uniformIndex];
+        const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
 
-    if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
-    {
-        AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
-                       mSamplersPS, &mUsedPixelSamplerRange);
+        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) : "");
+                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);
+        }
     }
 }
 
-// static
-void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex,
+void ProgramD3D::defineUniformBlock(const gl::Shader &shader,
+                                    const sh::InterfaceBlock &interfaceBlock,
+                                    const gl::Caps &caps)
+{
+    const ShaderD3D* shaderD3D = GetImplAs<ShaderD3D>(&shader);
+
+    // create uniform block entries if they do not exist
+    if (getUniformBlockIndex(interfaceBlock.name) == 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);
+        }
+    }
+
+    if (interfaceBlock.staticUse)
+    {
+        // 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);
+        }
+    }
+}
+
+bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex,
                                 GLenum samplerType,
                                 unsigned int samplerCount,
                                 std::vector<Sampler> &outSamplers,
@@ -1867,18 +1983,103 @@
 
     do
     {
-        ASSERT(samplerIndex < outSamplers.size());
-        Sampler *sampler            = &outSamplers[samplerIndex];
-        sampler->active             = true;
-        sampler->textureType        = GetTextureType(samplerType);
-        sampler->logicalTextureUnit = 0;
-        *outUsedRange               = std::max(samplerIndex + 1, *outUsedRange);
+        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;
+        }
+
         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);
@@ -1893,8 +2094,6 @@
     mPixelShaderKey.clear();
     mUsesPointSize = false;
 
-    SafeDeleteContainer(mD3DUniforms);
-
     SafeDelete(mVertexUniformStorage);
     SafeDelete(mFragmentUniformStorage);
 
@@ -2004,9 +2203,4 @@
         }
     }
 }
-
-D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location)
-{
-    return mD3DUniforms[mData.getUniformLocations()[location].index];
-}
 }