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/common/mathutil.h b/src/common/mathutil.h
index fb16a1c..332ba3d 100644
--- a/src/common/mathutil.h
+++ b/src/common/mathutil.h
@@ -69,13 +69,13 @@
 template <typename DestT, typename SrcT>
 inline DestT clampCast(SrcT value)
 {
+    // This assumes SrcT can properly represent DestT::min/max
+    // Unfortunately we can't use META_ASSERT without C++11 constexpr support
+    ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::min())) == std::numeric_limits<DestT>::min());
+    ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::max())) == std::numeric_limits<DestT>::max());
+
     SrcT lo = static_cast<SrcT>(std::numeric_limits<DestT>::min());
     SrcT hi = static_cast<SrcT>(std::numeric_limits<DestT>::max());
-
-    // This assumes SrcT can properly represent DestT::min/max. Checking this is a bit tricky,
-    // especially given floating point representations.
-    ASSERT(lo < hi);
-
     return static_cast<DestT>(value > lo ? (value > hi ? hi : value) : lo);
 }
 
diff --git a/src/compiler/translator/blocklayout.h b/src/compiler/translator/blocklayout.h
index 0d0a2ed..96d3740 100644
--- a/src/compiler/translator/blocklayout.h
+++ b/src/compiler/translator/blocklayout.h
@@ -26,8 +26,6 @@
 
 struct COMPILER_EXPORT BlockMemberInfo
 {
-    BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {}
-
     BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
         : offset(offset),
           arrayStride(arrayStride),
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 81bbe76..30386f7 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -22,7 +22,6 @@
 #include "libANGLE/features.h"
 #include "libANGLE/renderer/Renderer.h"
 #include "libANGLE/renderer/ProgramImpl.h"
-#include "libANGLE/queryconversions.h"
 
 namespace gl
 {
@@ -47,133 +46,8 @@
     return subscript;
 }
 
-void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
-{
-    stream->writeInt(var.type);
-    stream->writeInt(var.precision);
-    stream->writeString(var.name);
-    stream->writeString(var.mappedName);
-    stream->writeInt(var.arraySize);
-    stream->writeInt(var.staticUse);
-    stream->writeString(var.structName);
-    ASSERT(var.fields.empty());
 }
 
-void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
-{
-    var->type       = stream->readInt<GLenum>();
-    var->precision  = stream->readInt<GLenum>();
-    var->name       = stream->readString();
-    var->mappedName = stream->readString();
-    var->arraySize  = stream->readInt<unsigned int>();
-    var->staticUse  = stream->readBool();
-    var->structName = stream->readString();
-}
-
-template <typename VarT>
-void DefineUniformBlockMembers(const std::vector<VarT> &fields,
-                               const std::string &prefix,
-                               int blockIndex,
-                               std::vector<LinkedUniform> *uniformsOut)
-{
-    for (const VarT &field : fields)
-    {
-        const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
-
-        if (field.isStruct())
-        {
-            for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
-            {
-                const std::string uniformElementName =
-                    fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
-                DefineUniformBlockMembers(field.fields, uniformElementName, blockIndex,
-                                          uniformsOut);
-            }
-        }
-        else
-        {
-            // TODO(jmadill): record row-majorness?
-            // Block layout is recorded in the Impl.
-            LinkedUniform newUniform(field.type, field.precision, fieldName, field.arraySize,
-                                     blockIndex, sh::BlockMemberInfo::getDefaultBlockInfo());
-
-            // Since block uniforms have no location, we don't need to store them in the uniform
-            // locations list.
-            uniformsOut->push_back(newUniform);
-        }
-    }
-}
-
-// This simplified cast function doesn't need to worry about advanced concepts like
-// depth range values, or casting to bool.
-template <typename DestT, typename SrcT>
-DestT UniformStateQueryCast(SrcT value);
-
-// From-Float-To-Integer Casts
-template <>
-GLint UniformStateQueryCast(GLfloat value)
-{
-    return clampCast<GLint>(roundf(value));
-}
-
-template <>
-GLuint UniformStateQueryCast(GLfloat value)
-{
-    return clampCast<GLuint>(roundf(value));
-}
-
-// From-Integer-to-Integer Casts
-template <>
-GLint UniformStateQueryCast(GLuint value)
-{
-    return clampCast<GLint>(value);
-}
-
-template <>
-GLuint UniformStateQueryCast(GLint value)
-{
-    return clampCast<GLuint>(value);
-}
-
-// From-Boolean-to-Anything Casts
-template <>
-GLfloat UniformStateQueryCast(GLboolean value)
-{
-    return (value == GL_TRUE ? 1.0f : 0.0f);
-}
-
-template <>
-GLint UniformStateQueryCast(GLboolean value)
-{
-    return (value == GL_TRUE ? 1 : 0);
-}
-
-template <>
-GLuint UniformStateQueryCast(GLboolean value)
-{
-    return (value == GL_TRUE ? 1u : 0u);
-}
-
-// Default to static_cast
-template <typename DestT, typename SrcT>
-DestT UniformStateQueryCast(SrcT value)
-{
-    return static_cast<DestT>(value);
-}
-
-template <typename SrcT, typename DestT>
-void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
-{
-    const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(srcPointer);
-
-    for (int comp = 0; comp < components; ++comp)
-    {
-        dataOut[comp] = UniformStateQueryCast<DestT>(typedSrcPointer[comp]);
-    }
-}
-
-}  // anonymous namespace
-
 AttributeBindings::AttributeBindings()
 {
 }
@@ -288,68 +162,6 @@
     }
 }
 
-const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const
-{
-    for (const LinkedUniform &linkedUniform : mUniforms)
-    {
-        if (linkedUniform.name == name)
-        {
-            return &linkedUniform;
-        }
-    }
-
-    return nullptr;
-}
-
-GLint Program::Data::getUniformLocation(const std::string &name) const
-{
-    size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = gl::ParseUniformName(name, &subscript);
-
-    for (size_t location = 0; location < mUniformLocations.size(); ++location)
-    {
-        const VariableLocation &uniformLocation = mUniformLocations[location];
-        const LinkedUniform &uniform            = mUniforms[uniformLocation.index];
-
-        if (uniform.name == baseName)
-        {
-            if ((uniform.isArray() && uniformLocation.element == subscript) ||
-                (subscript == GL_INVALID_INDEX))
-            {
-                return static_cast<GLint>(location);
-            }
-        }
-    }
-
-    return -1;
-}
-
-GLuint Program::Data::getUniformIndex(const std::string &name) const
-{
-    size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = gl::ParseUniformName(name, &subscript);
-
-    // The app is not allowed to specify array indices other than 0 for arrays of basic types
-    if (subscript != 0 && subscript != GL_INVALID_INDEX)
-    {
-        return GL_INVALID_INDEX;
-    }
-
-    for (size_t index = 0; index < mUniforms.size(); index++)
-    {
-        const LinkedUniform &uniform = mUniforms[index];
-        if (uniform.name == baseName)
-        {
-            if (uniform.isArray() || subscript == GL_INVALID_INDEX)
-            {
-                return static_cast<GLuint>(index);
-            }
-        }
-    }
-
-    return GL_INVALID_INDEX;
-}
-
 Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
     : mProgram(factory->createProgram(mData)),
       mValidated(false),
@@ -507,7 +319,6 @@
     }
 
     gatherTransformFeedbackVaryings(mergedVaryings);
-    mProgram->gatherUniformBlockInfo(&mData.mUniformBlocks, &mData.mUniforms);
 
     mLinked = true;
     return gl::Error(GL_NO_ERROR);
@@ -547,11 +358,10 @@
     mData.mAttributes.clear();
     mData.mActiveAttribLocationsMask.reset();
     mData.mTransformFeedbackVaryingVars.clear();
-    mData.mUniforms.clear();
-    mData.mUniformLocations.clear();
-    mData.mUniformBlocks.clear();
     mData.mOutputVariables.clear();
 
+    mProgram->reset();
+
     mValidated = false;
 
     mLinked = false;
@@ -605,66 +415,15 @@
     for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
     {
         sh::Attribute attrib;
-        LoadShaderVar(&stream, &attrib);
-        attrib.location = stream.readInt<int>();
+        attrib.type      = stream.readInt<GLenum>();
+        attrib.precision = stream.readInt<GLenum>();
+        attrib.name      = stream.readString();
+        attrib.arraySize = stream.readInt<GLint>();
+        attrib.location  = stream.readInt<int>();
+        attrib.staticUse = stream.readBool();
         mData.mAttributes.push_back(attrib);
     }
 
-    unsigned int uniformCount = stream.readInt<unsigned int>();
-    ASSERT(mData.mUniforms.empty());
-    for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
-    {
-        LinkedUniform uniform;
-        LoadShaderVar(&stream, &uniform);
-
-        uniform.blockIndex                 = stream.readInt<int>();
-        uniform.blockInfo.offset           = stream.readInt<int>();
-        uniform.blockInfo.arrayStride      = stream.readInt<int>();
-        uniform.blockInfo.matrixStride     = stream.readInt<int>();
-        uniform.blockInfo.isRowMajorMatrix = stream.readBool();
-
-        mData.mUniforms.push_back(uniform);
-    }
-
-    const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
-    ASSERT(mData.mUniformLocations.empty());
-    for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
-         uniformIndexIndex++)
-    {
-        VariableLocation variable;
-        stream.readString(&variable.name);
-        stream.readInt(&variable.element);
-        stream.readInt(&variable.index);
-
-        mData.mUniformLocations.push_back(variable);
-    }
-
-    unsigned int uniformBlockCount = stream.readInt<unsigned int>();
-    ASSERT(mData.mUniformBlocks.empty());
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
-         ++uniformBlockIndex)
-    {
-        UniformBlock uniformBlock;
-        stream.readString(&uniformBlock.name);
-        stream.readBool(&uniformBlock.isArray);
-        stream.readInt(&uniformBlock.arrayElement);
-        stream.readInt(&uniformBlock.dataSize);
-        stream.readBool(&uniformBlock.vertexStaticUse);
-        stream.readBool(&uniformBlock.fragmentStaticUse);
-
-        unsigned int numMembers = stream.readInt<unsigned int>();
-        for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
-        {
-            uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
-        }
-
-        // TODO(jmadill): Make D3D-only
-        stream.readInt(&uniformBlock.psRegisterIndex);
-        stream.readInt(&uniformBlock.vsRegisterIndex);
-
-        mData.mUniformBlocks.push_back(uniformBlock);
-    }
-
     stream.readInt(&mData.mTransformFeedbackBufferMode);
 
     unsigned int outputVarCount = stream.readInt<unsigned int>();
@@ -708,52 +467,12 @@
     stream.writeInt(mData.mAttributes.size());
     for (const sh::Attribute &attrib : mData.mAttributes)
     {
-        WriteShaderVar(&stream, attrib);
+        stream.writeInt(attrib.type);
+        stream.writeInt(attrib.precision);
+        stream.writeString(attrib.name);
+        stream.writeInt(attrib.arraySize);
         stream.writeInt(attrib.location);
-    }
-
-    stream.writeInt(mData.mUniforms.size());
-    for (const gl::LinkedUniform &uniform : mData.mUniforms)
-    {
-        WriteShaderVar(&stream, uniform);
-
-        // FIXME: referenced
-
-        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(mData.mUniformLocations.size());
-    for (const auto &variable : mData.mUniformLocations)
-    {
-        stream.writeString(variable.name);
-        stream.writeInt(variable.element);
-        stream.writeInt(variable.index);
-    }
-
-    stream.writeInt(mData.mUniformBlocks.size());
-    for (const UniformBlock &uniformBlock : mData.mUniformBlocks)
-    {
-        stream.writeString(uniformBlock.name);
-        stream.writeInt(uniformBlock.isArray);
-        stream.writeInt(uniformBlock.arrayElement);
-        stream.writeInt(uniformBlock.dataSize);
-
-        stream.writeInt(uniformBlock.vertexStaticUse);
-        stream.writeInt(uniformBlock.fragmentStaticUse);
-
-        stream.writeInt(uniformBlock.memberUniformIndexes.size());
-        for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
-        {
-            stream.writeInt(memberUniformIndex);
-        }
-
-        // TODO(jmadill): make D3D-only
-        stream.writeInt(uniformBlock.psRegisterIndex);
-        stream.writeInt(uniformBlock.vsRegisterIndex);
+        stream.writeInt(attrib.staticUse);
     }
 
     stream.writeInt(mData.mTransformFeedbackBufferMode);
@@ -1009,14 +728,13 @@
 {
     if (mLinked)
     {
-        // index must be smaller than getActiveUniformCount()
-        ASSERT(index < mData.mUniforms.size());
-        const LinkedUniform &uniform = mData.mUniforms[index];
+        ASSERT(index < mProgram->getUniforms().size());   // index must be smaller than getActiveUniformCount()
+        LinkedUniform *uniform = mProgram->getUniforms()[index];
 
         if (bufsize > 0)
         {
-            std::string string = uniform.name;
-            if (uniform.isArray())
+            std::string string = uniform->name;
+            if (uniform->isArray())
             {
                 string += "[0]";
             }
@@ -1030,8 +748,8 @@
             }
         }
 
-        *size = uniform.elementCount();
-        *type = uniform.type;
+        *size = uniform->elementCount();
+        *type = uniform->type;
     }
     else
     {
@@ -1054,7 +772,7 @@
 {
     if (mLinked)
     {
-        return static_cast<GLint>(mData.mUniforms.size());
+        return static_cast<GLint>(mProgram->getUniforms().size());
     }
     else
     {
@@ -1064,16 +782,17 @@
 
 GLint Program::getActiveUniformMaxLength()
 {
-    size_t maxLength = 0;
+    int maxLength = 0;
 
     if (mLinked)
     {
-        for (const LinkedUniform &uniform : mData.mUniforms)
+        unsigned int numUniforms = static_cast<unsigned int>(mProgram->getUniforms().size());
+        for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
         {
-            if (!uniform.name.empty())
+            if (!mProgram->getUniforms()[uniformIndex]->name.empty())
             {
-                size_t length = uniform.name.length() + 1u;
-                if (uniform.isArray())
+                int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
+                if (mProgram->getUniforms()[uniformIndex]->isArray())
                 {
                     length += 3;  // Counting in "[0]".
                 }
@@ -1082,13 +801,12 @@
         }
     }
 
-    return static_cast<GLint>(maxLength);
+    return maxLength;
 }
 
 GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
 {
-    ASSERT(static_cast<size_t>(index) < mData.mUniforms.size());
-    const gl::LinkedUniform &uniform = mData.mUniforms[index];
+    const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
     switch (pname)
     {
       case GL_UNIFORM_TYPE:         return static_cast<GLint>(uniform.type);
@@ -1108,165 +826,149 @@
 
 bool Program::isValidUniformLocation(GLint location) const
 {
-    ASSERT(rx::IsIntegerCastSafe<GLint>(mData.mUniformLocations.size()));
-    return (location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
+    const auto &uniformIndices = mProgram->getUniformIndices();
+    ASSERT(rx::IsIntegerCastSafe<GLint>(uniformIndices.size()));
+    return (location >= 0 && uniformIndices.find(location) != uniformIndices.end());
 }
 
-const LinkedUniform &Program::getUniformByLocation(GLint location) const
+LinkedUniform *Program::getUniformByLocation(GLint location) const
 {
-    ASSERT(location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
-    return mData.mUniforms[mData.mUniformLocations[location].index];
+    return mProgram->getUniformByLocation(location);
 }
 
-GLint Program::getUniformLocation(const std::string &name) const
+LinkedUniform *Program::getUniformByName(const std::string &name) const
 {
-    return mData.getUniformLocation(name);
+    return mProgram->getUniformByName(name);
 }
 
-GLuint Program::getUniformIndex(const std::string &name) const
+GLint Program::getUniformLocation(const std::string &name)
 {
-    return mData.getUniformIndex(name);
+    return mProgram->getUniformLocation(name);
+}
+
+GLuint Program::getUniformIndex(const std::string &name)
+{
+    return mProgram->getUniformIndex(name);
 }
 
 void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
 {
-    setUniformInternal(location, count * 1, v);
     mProgram->setUniform1fv(location, count, v);
 }
 
 void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
 {
-    setUniformInternal(location, count * 2, v);
     mProgram->setUniform2fv(location, count, v);
 }
 
 void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
 {
-    setUniformInternal(location, count * 3, v);
     mProgram->setUniform3fv(location, count, v);
 }
 
 void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
 {
-    setUniformInternal(location, count * 4, v);
     mProgram->setUniform4fv(location, count, v);
 }
 
 void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
 {
-    setUniformInternal(location, count * 1, v);
     mProgram->setUniform1iv(location, count, v);
 }
 
 void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
 {
-    setUniformInternal(location, count * 2, v);
     mProgram->setUniform2iv(location, count, v);
 }
 
 void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
 {
-    setUniformInternal(location, count * 3, v);
     mProgram->setUniform3iv(location, count, v);
 }
 
 void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
 {
-    setUniformInternal(location, count * 4, v);
     mProgram->setUniform4iv(location, count, v);
 }
 
 void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
 {
-    setUniformInternal(location, count * 1, v);
     mProgram->setUniform1uiv(location, count, v);
 }
 
 void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
 {
-    setUniformInternal(location, count * 2, v);
     mProgram->setUniform2uiv(location, count, v);
 }
 
 void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
 {
-    setUniformInternal(location, count * 3, v);
     mProgram->setUniform3uiv(location, count, v);
 }
 
 void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
 {
-    setUniformInternal(location, count * 4, v);
     mProgram->setUniform4uiv(location, count, v);
 }
 
 void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<2, 2>(location, count, transpose, v);
     mProgram->setUniformMatrix2fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<3, 3>(location, count, transpose, v);
     mProgram->setUniformMatrix3fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<4, 4>(location, count, transpose, v);
     mProgram->setUniformMatrix4fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<2, 3>(location, count, transpose, v);
     mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<2, 4>(location, count, transpose, v);
     mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<3, 2>(location, count, transpose, v);
     mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<3, 4>(location, count, transpose, v);
     mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<4, 2>(location, count, transpose, v);
     mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
 }
 
 void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
 {
-    setMatrixUniformInternal<4, 3>(location, count, transpose, v);
     mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
 }
 
 void Program::getUniformfv(GLint location, GLfloat *v)
 {
-    getUniformInternal(location, v);
+    mProgram->getUniformfv(location, v);
 }
 
 void Program::getUniformiv(GLint location, GLint *v)
 {
-    getUniformInternal(location, v);
+    mProgram->getUniformiv(location, v);
 }
 
 void Program::getUniformuiv(GLint location, GLuint *v)
 {
-    getUniformInternal(location, v);
+    mProgram->getUniformuiv(location, v);
 }
 
 void Program::flagForDeletion()
@@ -1305,23 +1007,22 @@
 
 GLuint Program::getActiveUniformBlockCount()
 {
-    return static_cast<GLuint>(mData.mUniformBlocks.size());
+    return static_cast<GLuint>(mProgram->getUniformBlocks().size());
 }
 
 void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
 {
-    ASSERT(uniformBlockIndex <
-           mData.mUniformBlocks.size());  // index must be smaller than getActiveUniformBlockCount()
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
 
-    const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
 
     if (bufSize > 0)
     {
         std::string string = uniformBlock.name;
 
-        if (uniformBlock.isArray)
+        if (uniformBlock.isArrayElement())
         {
-            string += ArrayString(uniformBlock.arrayElement);
+            string += ArrayString(uniformBlock.elementIndex);
         }
 
         strncpy(uniformBlockName, string.c_str(), bufSize);
@@ -1336,10 +1037,9 @@
 
 void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
 {
-    ASSERT(uniformBlockIndex <
-           mData.mUniformBlocks.size());  // index must be smaller than getActiveUniformBlockCount()
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
 
-    const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
 
     switch (pname)
     {
@@ -1347,8 +1047,7 @@
         *params = static_cast<GLint>(uniformBlock.dataSize);
         break;
       case GL_UNIFORM_BLOCK_NAME_LENGTH:
-          *params =
-              static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
+        *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
         break;
       case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
         *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
@@ -1362,10 +1061,10 @@
         }
         break;
       case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
-          *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
+        *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
         break;
       case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
-          *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
+        *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
         break;
       default: UNREACHABLE();
     }
@@ -1377,16 +1076,17 @@
 
     if (mLinked)
     {
-        unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
+        unsigned int numUniformBlocks =
+            static_cast<unsigned int>(mProgram->getUniformBlocks().size());
         for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
         {
-            const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
+            const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
             if (!uniformBlock.name.empty())
             {
                 const int length = static_cast<int>(uniformBlock.name.length()) + 1;
 
                 // Counting in "[0]".
-                const int arrayLength = (uniformBlock.isArray ? 3 : 0);
+                const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
 
                 maxLength = std::max(length + arrayLength, maxLength);
             }
@@ -1398,32 +1098,12 @@
 
 GLuint Program::getUniformBlockIndex(const std::string &name)
 {
-    size_t subscript     = GL_INVALID_INDEX;
-    std::string baseName = gl::ParseUniformName(name, &subscript);
-
-    unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
-    for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
-    {
-        const gl::UniformBlock &uniformBlock = mData.mUniformBlocks[blockIndex];
-        if (uniformBlock.name == baseName)
-        {
-            const bool arrayElementZero =
-                (subscript == GL_INVALID_INDEX &&
-                 (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
-            if (subscript == uniformBlock.arrayElement || arrayElementZero)
-            {
-                return blockIndex;
-            }
-        }
-    }
-
-    return GL_INVALID_INDEX;
+    return mProgram->getUniformBlockIndex(name);
 }
 
-const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
+const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
 {
-    ASSERT(index < static_cast<GLuint>(mData.mUniformBlocks.size()));
-    return mData.mUniformBlocks[index];
+    return mProgram->getUniformBlockByIndex(index);
 }
 
 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
@@ -1563,17 +1243,17 @@
     return true;
 }
 
-bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
+bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps & /*caps*/) const
 {
     const std::vector<sh::Uniform> &vertexUniforms   = mData.mAttachedVertexShader->getUniforms();
     const std::vector<sh::Uniform> &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms();
 
     // Check that uniforms defined in the vertex and fragment shaders are identical
-    std::map<std::string, LinkedUniform> linkedUniforms;
+    std::map<std::string, const sh::Uniform *> linkedUniforms;
 
     for (const sh::Uniform &vertexUniform : vertexUniforms)
     {
-        linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
+        linkedUniforms[vertexUniform.name] = &vertexUniform;
     }
 
     for (const sh::Uniform &fragmentUniform : fragmentUniforms)
@@ -1581,45 +1261,19 @@
         auto entry = linkedUniforms.find(fragmentUniform.name);
         if (entry != linkedUniforms.end())
         {
-            LinkedUniform *vertexUniform   = &entry->second;
-            const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
-            if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
+            const sh::Uniform &vertexUniform = *entry->second;
+            const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
+            if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
             {
                 return false;
             }
         }
     }
 
-    // Flatten the uniforms list (nested fields) into a simple list (no nesting).
-    // Also check the maximum uniform vector and sampler counts.
-    if (!flattenUniformsAndCheckCaps(caps, infoLog))
-    {
-        return false;
-    }
-
-    indexUniforms();
-
+    // TODO(jmadill): check sampler uniforms with caps
     return true;
 }
 
-void Program::indexUniforms()
-{
-    for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++)
-    {
-        const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex];
-
-        for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
-        {
-            if (!uniform.isBuiltIn())
-            {
-                // Assign in-order uniform locations
-                mData.mUniformLocations.push_back(gl::VariableLocation(
-                    uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex)));
-            }
-        }
-    }
-}
-
 bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
 {
     if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
@@ -1799,8 +1453,6 @@
         }
     }
 
-    gatherInterfaceBlockInfo();
-
     return true;
 }
 
@@ -2078,288 +1730,4 @@
         }
     }
 }
-
-bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
-{
-    const gl::Shader *vertexShader = mData.getAttachedVertexShader();
-    VectorAndSamplerCount vsCounts;
-
-    for (const sh::Uniform &uniform : vertexShader->getUniforms())
-    {
-        if (uniform.staticUse)
-        {
-            vsCounts += flattenUniform(uniform, uniform.name);
-        }
-    }
-
-    if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
-    {
-        infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
-                << caps.maxVertexUniformVectors << ").";
-        return false;
-    }
-
-    if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
-    {
-        infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
-                << caps.maxVertexTextureImageUnits << ").";
-        return false;
-    }
-
-    const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
-    VectorAndSamplerCount fsCounts;
-
-    for (const sh::Uniform &uniform : fragmentShader->getUniforms())
-    {
-        if (uniform.staticUse)
-        {
-            fsCounts += flattenUniform(uniform, uniform.name);
-        }
-    }
-
-    if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
-    {
-        infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
-                << caps.maxFragmentUniformVectors << ").";
-        return false;
-    }
-
-    if (fsCounts.samplerCount > caps.maxTextureImageUnits)
-    {
-        infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
-                << caps.maxTextureImageUnits << ").";
-        return false;
-    }
-
-    return true;
-}
-
-Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
-                                                       const std::string &fullName)
-{
-    VectorAndSamplerCount vectorAndSamplerCount;
-
-    if (uniform.isStruct())
-    {
-        for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
-        {
-            const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
-
-            for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
-            {
-                const sh::ShaderVariable &field  = uniform.fields[fieldIndex];
-                const std::string &fieldFullName = (fullName + elementString + "." + field.name);
-
-                vectorAndSamplerCount += flattenUniform(field, fieldFullName);
-            }
-        }
-
-        return vectorAndSamplerCount;
-    }
-
-    // Not a struct
-    if (mData.getUniformByName(fullName) == nullptr)
-    {
-        gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
-                                        uniform.arraySize, -1,
-                                        sh::BlockMemberInfo::getDefaultBlockInfo());
-        linkedUniform.staticUse = true;
-        mData.mUniforms.push_back(linkedUniform);
-    }
-
-    vectorAndSamplerCount.vectorCount =
-        (VariableRegisterCount(uniform.type) * uniform.elementCount());
-    vectorAndSamplerCount.samplerCount = (IsSamplerType(uniform.type) ? uniform.elementCount() : 0);
-
-    return vectorAndSamplerCount;
-}
-
-void Program::gatherInterfaceBlockInfo()
-{
-    std::set<std::string> visitedList;
-
-    const gl::Shader *vertexShader = mData.getAttachedVertexShader();
-
-    ASSERT(mData.mUniformBlocks.empty());
-    for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
-    {
-        // Only 'packed' blocks are allowed to be considered inacive.
-        if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
-            continue;
-
-        if (visitedList.count(vertexBlock.name) > 0)
-            continue;
-
-        defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
-        visitedList.insert(vertexBlock.name);
-    }
-
-    const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
-
-    for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
-    {
-        // Only 'packed' blocks are allowed to be considered inacive.
-        if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
-            continue;
-
-        if (visitedList.count(fragmentBlock.name) > 0)
-        {
-            for (gl::UniformBlock &block : mData.mUniformBlocks)
-            {
-                if (block.name == fragmentBlock.name)
-                {
-                    block.fragmentStaticUse = fragmentBlock.staticUse;
-                }
-            }
-
-            continue;
-        }
-
-        defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
-        visitedList.insert(fragmentBlock.name);
-    }
-}
-
-void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
-{
-    std::string baseName;
-    if (!interfaceBlock.instanceName.empty() && interfaceBlock.arraySize == 0)
-    {
-        baseName = interfaceBlock.instanceName;
-    }
-
-    int blockIndex                = static_cast<int>(mData.mUniformBlocks.size());
-    size_t firstBlockUniformIndex = mData.mUniforms.size();
-    DefineUniformBlockMembers(interfaceBlock.fields, baseName, blockIndex, &mData.mUniforms);
-    size_t lastBlockUniformIndex = mData.mUniforms.size();
-
-    std::vector<unsigned int> blockUniformIndexes;
-    for (size_t blockUniformIndex = firstBlockUniformIndex;
-         blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
-    {
-        blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
-    }
-
-    if (interfaceBlock.arraySize > 0)
-    {
-        for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
-        {
-            UniformBlock block(interfaceBlock.name, true, arrayElement);
-            block.memberUniformIndexes = blockUniformIndexes;
-
-            if (shaderType == GL_VERTEX_SHADER)
-            {
-                block.vertexStaticUse = interfaceBlock.staticUse;
-            }
-            else
-            {
-                ASSERT(shaderType == GL_FRAGMENT_SHADER);
-                block.fragmentStaticUse = interfaceBlock.staticUse;
-            }
-
-            mData.mUniformBlocks.push_back(block);
-        }
-    }
-    else
-    {
-        UniformBlock block(interfaceBlock.name, false, 0);
-        block.memberUniformIndexes = blockUniformIndexes;
-
-        if (shaderType == GL_VERTEX_SHADER)
-        {
-            block.vertexStaticUse = interfaceBlock.staticUse;
-        }
-        else
-        {
-            ASSERT(shaderType == GL_FRAGMENT_SHADER);
-            block.fragmentStaticUse = interfaceBlock.staticUse;
-        }
-
-        mData.mUniformBlocks.push_back(block);
-    }
-}
-
-template <typename T>
-void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
-{
-    const VariableLocation &locationInfo = mData.mUniformLocations[location];
-    LinkedUniform *linkedUniform         = &mData.mUniforms[locationInfo.index];
-    uint8_t *destPointer                 = linkedUniform->getDataPtrToElement(locationInfo.element);
-
-    if (VariableComponentType(linkedUniform->type) == GL_BOOL)
-    {
-        // Do a cast conversion for boolean types. From the spec:
-        // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
-        GLboolean *destAsBool = reinterpret_cast<GLboolean *>(destPointer);
-        for (GLsizei component = 0; component < count; ++component)
-        {
-            destAsBool[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
-        }
-    }
-    else
-    {
-        memcpy(destPointer, v, sizeof(T) * count);
-    }
-}
-
-template <size_t cols, size_t rows, typename T>
-void Program::setMatrixUniformInternal(GLint location,
-                                       GLsizei count,
-                                       GLboolean transpose,
-                                       const T *v)
-{
-    if (!transpose)
-    {
-        setUniformInternal(location, count * cols * rows, v);
-        return;
-    }
-
-    // Perform a transposing copy.
-    const VariableLocation &locationInfo = mData.mUniformLocations[location];
-    LinkedUniform *linkedUniform         = &mData.mUniforms[locationInfo.index];
-    T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
-    for (size_t row = 0; row < rows; ++row)
-    {
-        for (size_t col = 0; col < cols; ++col)
-        {
-            destPtr[col * rows + row] = v[row * cols + col];
-        }
-    }
-}
-
-template <typename DestT>
-void Program::getUniformInternal(GLint location, DestT *dataOut) const
-{
-    const VariableLocation &locationInfo = mData.mUniformLocations[location];
-    const LinkedUniform &uniform         = mData.mUniforms[locationInfo.index];
-
-    const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
-
-    GLenum componentType = VariableComponentType(uniform.type);
-    if (componentType == GLTypeToGLenum<DestT>::value)
-    {
-        memcpy(dataOut, srcPointer, uniform.getElementSize());
-        return;
-    }
-
-    int components = VariableComponentCount(uniform.type);
-
-    switch (componentType)
-    {
-        case GL_INT:
-            UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
-            break;
-        case GL_UNSIGNED_INT:
-            UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
-            break;
-        case GL_BOOL:
-            UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
-            break;
-        case GL_FLOAT:
-            UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
-            break;
-        default:
-            UNREACHABLE();
-    }
-}
 }
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 3dd7c46..b95d5b8 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -189,16 +189,6 @@
         {
             return mOutputVariables;
         }
-        const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
-        const std::vector<VariableLocation> &getUniformLocations() const
-        {
-            return mUniformLocations;
-        }
-        const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
-
-        const LinkedUniform *getUniformByName(const std::string &name) const;
-        GLint getUniformLocation(const std::string &name) const;
-        GLuint getUniformIndex(const std::string &name) const;
 
       private:
         friend class Program;
@@ -215,12 +205,10 @@
         std::vector<sh::Attribute> mAttributes;
         std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
 
-        std::vector<LinkedUniform> mUniforms;
-        std::vector<VariableLocation> mUniformLocations;
-        std::vector<UniformBlock> mUniformBlocks;
-
         // TODO(jmadill): use unordered/hash map when available
         std::map<int, VariableLocation> mOutputVariables;
+
+        // TODO(jmadill): move more state into Data.
     };
 
     Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle);
@@ -263,10 +251,11 @@
     GLint getActiveUniformMaxLength();
     GLint getActiveUniformi(GLuint index, GLenum pname) const;
     bool isValidUniformLocation(GLint location) const;
-    const LinkedUniform &getUniformByLocation(GLint location) const;
+    LinkedUniform *getUniformByLocation(GLint location) const;
+    LinkedUniform *getUniformByName(const std::string &name) const;
 
-    GLint getUniformLocation(const std::string &name) const;
-    GLuint getUniformIndex(const std::string &name) const;
+    GLint getUniformLocation(const std::string &name);
+    GLuint getUniformIndex(const std::string &name);
     void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
     void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
     void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
@@ -303,7 +292,7 @@
     void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
     GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
 
-    const UniformBlock &getUniformBlockByIndex(GLuint index) const;
+    const UniformBlock *getUniformBlockByIndex(GLuint index) const;
 
     void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);
     void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;
@@ -341,8 +330,7 @@
     static bool linkVaryings(InfoLog &infoLog,
                              const Shader *vertexShader,
                              const Shader *fragmentShader);
-    bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
-    void indexUniforms();
+    bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) const;
     bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
                                     const sh::InterfaceBlock &fragmentInterfaceBlock);
 
@@ -364,40 +352,6 @@
     std::vector<const sh::Varying *> getMergedVaryings() const;
     void linkOutputVariables();
 
-    bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
-
-    struct VectorAndSamplerCount
-    {
-        VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {}
-        VectorAndSamplerCount(const VectorAndSamplerCount &other) = default;
-        VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default;
-
-        VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other)
-        {
-            vectorCount += other.vectorCount;
-            samplerCount += other.samplerCount;
-            return *this;
-        }
-
-        unsigned int vectorCount;
-        unsigned int samplerCount;
-    };
-
-    VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform,
-                                         const std::string &fullName);
-
-    void gatherInterfaceBlockInfo();
-    void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
-
-    template <typename T>
-    void setUniformInternal(GLint location, GLsizei count, const T *v);
-
-    template <size_t cols, size_t rows, typename T>
-    void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v);
-
-    template <typename DestT>
-    void getUniformInternal(GLint location, DestT *dataOut) const;
-
     Data mData;
     rx::ProgramImpl *mProgram;
 
diff --git a/src/libANGLE/Uniform.cpp b/src/libANGLE/Uniform.cpp
index 3a20f4c..24e7f11 100644
--- a/src/libANGLE/Uniform.cpp
+++ b/src/libANGLE/Uniform.cpp
@@ -13,51 +13,55 @@
 namespace gl
 {
 
-LinkedUniform::LinkedUniform()
-    : blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
+LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
+                             const int blockIndex, const sh::BlockMemberInfo &blockInfo)
+    : type(type),
+      precision(precision),
+      name(name),
+      arraySize(arraySize),
+      blockIndex(blockIndex),
+      blockInfo(blockInfo),
+      data(NULL),
+      dirty(true),
+      psRegisterIndex(GL_INVALID_INDEX),
+      vsRegisterIndex(GL_INVALID_INDEX),
+      registerCount(0),
+      registerElement(0)
 {
-}
-
-LinkedUniform::LinkedUniform(GLenum typeIn,
-                             GLenum precisionIn,
-                             const std::string &nameIn,
-                             unsigned int arraySizeIn,
-                             const int blockIndexIn,
-                             const sh::BlockMemberInfo &blockInfoIn)
-    : blockIndex(blockIndexIn), blockInfo(blockInfoIn)
-{
-    type      = typeIn;
-    precision = precisionIn;
-    name      = nameIn;
-    arraySize = arraySizeIn;
-}
-
-LinkedUniform::LinkedUniform(const sh::Uniform &uniform)
-    : sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
-{
-}
-
-LinkedUniform::LinkedUniform(const LinkedUniform &uniform)
-    : sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo)
-{
-    // This function is not intended to be called during runtime.
-    ASSERT(uniform.mLazyData.empty());
-}
-
-LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform)
-{
-    // This function is not intended to be called during runtime.
-    ASSERT(uniform.mLazyData.empty());
-
-    sh::Uniform::operator=(uniform);
-    blockIndex           = uniform.blockIndex;
-    blockInfo            = uniform.blockInfo;
-
-    return *this;
+    // 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 (isInDefaultBlock())
+    {
+        size_t bytes = dataSize();
+        data = new unsigned char[bytes];
+        memset(data, 0, bytes);
+        registerCount = VariableRowCount(type) * elementCount();
+    }
 }
 
 LinkedUniform::~LinkedUniform()
 {
+    delete[] data;
+}
+
+bool LinkedUniform::isArray() const
+{
+    return arraySize > 0;
+}
+
+unsigned int LinkedUniform::elementCount() const
+{
+    return arraySize > 0 ? arraySize : 1;
+}
+
+bool LinkedUniform::isReferencedByVertexShader() const
+{
+    return vsRegisterIndex != GL_INVALID_INDEX;
+}
+
+bool LinkedUniform::isReferencedByFragmentShader() const
+{
+    return psRegisterIndex != GL_INVALID_INDEX;
 }
 
 bool LinkedUniform::isInDefaultBlock() const
@@ -68,30 +72,7 @@
 size_t LinkedUniform::dataSize() const
 {
     ASSERT(type != GL_STRUCT_ANGLEX);
-    if (mLazyData.empty())
-    {
-        mLazyData.resize(VariableExternalSize(type) * elementCount());
-        ASSERT(!mLazyData.empty());
-    }
-
-    return mLazyData.size();
-}
-
-uint8_t *LinkedUniform::data()
-{
-    if (mLazyData.empty())
-    {
-        // dataSize() will init the data store.
-        size_t size = dataSize();
-        memset(mLazyData.data(), 0, size);
-    }
-
-    return mLazyData.data();
-}
-
-const uint8_t *LinkedUniform::data() const
-{
-    return const_cast<LinkedUniform *>(this)->data();
+    return VariableInternalSize(type) * elementCount();
 }
 
 bool LinkedUniform::isSampler() const
@@ -99,48 +80,33 @@
     return IsSamplerType(type);
 }
 
-bool LinkedUniform::isField() const
+bool LinkedUniform::isBuiltIn() const
 {
-    return name.find('.') != std::string::npos;
+    return name.compare(0, 3, "gl_") == 0;
 }
 
-size_t LinkedUniform::getElementSize() const
-{
-    return VariableExternalSize(type);
-}
-
-uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex)
-{
-    ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize));
-    return data() + getElementSize() * elementIndex;
-}
-
-const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const
-{
-    return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex);
-}
-
-UniformBlock::UniformBlock()
-    : isArray(false),
-      arrayElement(0),
-      dataSize(0),
-      vertexStaticUse(false),
-      fragmentStaticUse(false),
+UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize)
+    : name(name),
+      elementIndex(elementIndex),
+      dataSize(dataSize),
       psRegisterIndex(GL_INVALID_INDEX),
       vsRegisterIndex(GL_INVALID_INDEX)
 {
 }
 
-UniformBlock::UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn)
-    : name(nameIn),
-      isArray(isArrayIn),
-      arrayElement(arrayElementIn),
-      dataSize(0),
-      vertexStaticUse(false),
-      fragmentStaticUse(false),
-      psRegisterIndex(GL_INVALID_INDEX),
-      vsRegisterIndex(GL_INVALID_INDEX)
+bool UniformBlock::isArrayElement() const
 {
+    return elementIndex != GL_INVALID_INDEX;
+}
+
+bool UniformBlock::isReferencedByVertexShader() const
+{
+    return vsRegisterIndex != GL_INVALID_INDEX;
+}
+
+bool UniformBlock::isReferencedByFragmentShader() const
+{
+    return psRegisterIndex != GL_INVALID_INDEX;
 }
 
 }
diff --git a/src/libANGLE/Uniform.h b/src/libANGLE/Uniform.h
index 040c978..b73fc9d 100644
--- a/src/libANGLE/Uniform.h
+++ b/src/libANGLE/Uniform.h
@@ -12,7 +12,6 @@
 
 #include "angle_gl.h"
 #include "common/debug.h"
-#include "common/MemoryBuffer.h"
 #include "compiler/translator/blocklayout.h"
 #include "libANGLE/angletypes.h"
 
@@ -20,47 +19,53 @@
 {
 
 // Helper struct representing a single shader uniform
-struct LinkedUniform : public sh::Uniform
+struct LinkedUniform : angle::NonCopyable
 {
-    LinkedUniform();
     LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo);
-    LinkedUniform(const sh::Uniform &uniform);
-    LinkedUniform(const LinkedUniform &uniform);
-    LinkedUniform &operator=(const LinkedUniform &uniform);
+
     ~LinkedUniform();
 
-    size_t dataSize() const;
-    uint8_t *data();
-    const uint8_t *data() const;
-    bool isSampler() const;
+    bool isArray() const;
+    unsigned int elementCount() const;
+    bool isReferencedByVertexShader() const;
+    bool isReferencedByFragmentShader() const;
     bool isInDefaultBlock() const;
-    bool isField() const;
-    size_t getElementSize() const;
-    uint8_t *getDataPtrToElement(size_t elementIndex);
-    const uint8_t *getDataPtrToElement(size_t elementIndex) const;
+    size_t dataSize() const;
+    bool isSampler() const;
+    bool isBuiltIn() const;
 
-    int blockIndex;
-    sh::BlockMemberInfo blockInfo;
+    const GLenum type;
+    const GLenum precision;
+    const std::string name;
+    const unsigned int arraySize;
+    const int blockIndex;
+    const sh::BlockMemberInfo blockInfo;
 
-  private:
-    mutable rx::MemoryBuffer mLazyData;
+    unsigned char *data;
+    bool dirty;
+
+    unsigned int psRegisterIndex;
+    unsigned int vsRegisterIndex;
+    unsigned int registerCount;
+
+    // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms
+    // inside aggregate types, which are packed according C-like structure rules.
+    unsigned int registerElement;
 };
 
 // Helper struct representing a single shader uniform block
-struct UniformBlock
+struct UniformBlock : angle::NonCopyable
 {
-    UniformBlock();
-    UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn);
-    UniformBlock(const UniformBlock &other) = default;
-    UniformBlock &operator=(const UniformBlock &other) = default;
+    // use GL_INVALID_INDEX for non-array elements
+    UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize);
 
-    std::string name;
-    bool isArray;
-    unsigned int arrayElement;
-    unsigned int dataSize;
+    bool isArrayElement() const;
+    bool isReferencedByVertexShader() const;
+    bool isReferencedByFragmentShader() const;
 
-    bool vertexStaticUse;
-    bool fragmentStaticUse;
+    const std::string name;
+    const unsigned int elementIndex;
+    const unsigned int dataSize;
 
     std::vector<unsigned int> memberUniformIndexes;
 
diff --git a/src/libANGLE/queryconversions.cpp b/src/libANGLE/queryconversions.cpp
index 5633ce4..d18a8e1 100644
--- a/src/libANGLE/queryconversions.cpp
+++ b/src/libANGLE/queryconversions.cpp
@@ -6,24 +6,32 @@
 
 // queryconversions.cpp: Implementation of state query cast conversions
 
-#include "libANGLE/queryconversions.h"
-
 #include "libANGLE/Context.h"
 #include "common/utilities.h"
 
 namespace gl
 {
 
-namespace
-{
+// Helper class for converting a GL type to a GLenum:
+// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
+// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
 
-GLint64 ExpandFloatToInteger(GLfloat value)
+template <typename GLType>
+struct CastStateValueEnum { static GLenum mEnumForType; };
+
+template <> GLenum CastStateValueEnum<GLint>::mEnumForType      = GL_INT;
+template <> GLenum CastStateValueEnum<GLuint>::mEnumForType     = GL_UNSIGNED_INT;
+template <> GLenum CastStateValueEnum<GLboolean>::mEnumForType  = GL_BOOL;
+template <> GLenum CastStateValueEnum<GLint64>::mEnumForType    = GL_INT_64_ANGLEX;
+template <> GLenum CastStateValueEnum<GLfloat>::mEnumForType    = GL_FLOAT;
+
+static GLint64 ExpandFloatToInteger(GLfloat value)
 {
     return static_cast<GLint64>((static_cast<double>(0xFFFFFFFFULL) * value - 1.0) / 2.0);
 }
 
 template <typename QueryT>
-QueryT ClampToQueryRange(GLint64 value)
+static QueryT ClampToQueryRange(GLint64 value)
 {
     const GLint64 min = static_cast<GLint64>(std::numeric_limits<QueryT>::min());
     const GLint64 max = static_cast<GLint64>(std::numeric_limits<QueryT>::max());
@@ -33,8 +41,8 @@
 template <typename QueryT, typename NativeT>
 QueryT CastStateValueToInt(GLenum pname, NativeT value)
 {
-    GLenum queryType  = GLTypeToGLenum<QueryT>::value;
-    GLenum nativeType = GLTypeToGLenum<NativeT>::value;
+    GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
+    GLenum nativeType = CastStateValueEnum<NativeT>::mEnumForType;
 
     if (nativeType == GL_FLOAT)
     {
@@ -64,37 +72,18 @@
 template <typename QueryT, typename NativeT>
 QueryT CastStateValue(GLenum pname, NativeT value)
 {
-    GLenum queryType = GLTypeToGLenum<QueryT>::value;
+    GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
 
     switch (queryType)
     {
-        case GL_INT:
-            return CastStateValueToInt<QueryT, NativeT>(pname, value);
-        case GL_INT_64_ANGLEX:
-            return CastStateValueToInt<QueryT, NativeT>(pname, value);
-        case GL_FLOAT:
-            return static_cast<QueryT>(value);
-        case GL_BOOL:
-            return static_cast<QueryT>(value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
-        default:
-            UNREACHABLE();
-            return 0;
+      case GL_INT:              return CastStateValueToInt<QueryT, NativeT>(pname, value);
+      case GL_INT_64_ANGLEX:    return CastStateValueToInt<QueryT, NativeT>(pname, value);
+      case GL_FLOAT:            return static_cast<QueryT>(value);
+      case GL_BOOL:             return static_cast<QueryT>(value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
+      default: UNREACHABLE();   return 0;
     }
 }
 
-}  // anonymous namespace
-
-template <>
-GLenum GLTypeToGLenum<GLint>::value = GL_INT;
-template <>
-GLenum GLTypeToGLenum<GLuint>::value = GL_UNSIGNED_INT;
-template <>
-GLenum GLTypeToGLenum<GLboolean>::value = GL_BOOL;
-template <>
-GLenum GLTypeToGLenum<GLint64>::value = GL_INT_64_ANGLEX;
-template <>
-GLenum GLTypeToGLenum<GLfloat>::value = GL_FLOAT;
-
 template <typename QueryT>
 void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
                      unsigned int numParams, QueryT *outParams)
diff --git a/src/libANGLE/queryconversions.h b/src/libANGLE/queryconversions.h
index e0fdbe1..da7047f 100644
--- a/src/libANGLE/queryconversions.h
+++ b/src/libANGLE/queryconversions.h
@@ -6,25 +6,8 @@
 
 // queryconversions.h: Declaration of state query cast conversions
 
-#ifndef LIBANGLE_QUERY_CONVERSIONS_H_
-#define LIBANGLE_QUERY_CONVERSIONS_H_
-
-#include "angle_gl.h"
-#include "common/angleutils.h"
-
 namespace gl
 {
-class Context;
-
-// Helper class for converting a GL type to a GLenum:
-// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
-// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
-
-template <typename GLType>
-struct GLTypeToGLenum
-{
-    static GLenum value;
-};
 
 // The GL state query API types are: bool, int, uint, float, int64
 template <typename QueryT>
@@ -32,5 +15,3 @@
                      unsigned int numParams, QueryT *outParams);
 
 }
-
-#endif  // LIBANGLE_QUERY_CONVERSIONS_H_
diff --git a/src/libANGLE/renderer/ProgramImpl.cpp b/src/libANGLE/renderer/ProgramImpl.cpp
new file mode 100644
index 0000000..051ef16
--- /dev/null
+++ b/src/libANGLE/renderer/ProgramImpl.cpp
@@ -0,0 +1,137 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
+
+#include "libANGLE/renderer/ProgramImpl.h"
+
+#include "common/utilities.h"
+
+namespace rx
+{
+
+LinkResult::LinkResult(bool linkSuccess, const gl::Error &error)
+    : linkSuccess(linkSuccess),
+      error(error)
+{
+}
+
+ProgramImpl::ProgramImpl(const gl::Program::Data &data) : mData(data)
+{
+}
+
+ProgramImpl::~ProgramImpl()
+{
+    // Ensure that reset was called by the inherited class during destruction
+    ASSERT(mUniformIndex.size() == 0);
+}
+
+gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const
+{
+    ASSERT(location >= 0 && mUniformIndex.find(location) != mUniformIndex.end());
+    return mUniforms[mUniformIndex.at(location).index];
+}
+
+gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const
+{
+    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+    {
+        if (mUniforms[uniformIndex]->name == name)
+        {
+            return mUniforms[uniformIndex];
+        }
+    }
+
+    return NULL;
+}
+
+gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const
+{
+    ASSERT(blockIndex < mUniformBlocks.size());
+    return mUniformBlocks[blockIndex];
+}
+
+GLint ProgramImpl::getUniformLocation(const std::string &name) const
+{
+    size_t subscript = GL_INVALID_INDEX;
+    std::string baseName = gl::ParseUniformName(name, &subscript);
+
+    for (const auto &info : mUniformIndex)
+    {
+        GLuint location = info.first;
+        const gl::VariableLocation &uniform = info.second;
+
+        if (uniform.name == baseName)
+        {
+            const bool isArray = mUniforms[uniform.index]->isArray();
+
+            if ((isArray && uniform.element == subscript) ||
+                (subscript == GL_INVALID_INDEX))
+            {
+                return location;
+            }
+        }
+    }
+
+    return -1;
+}
+
+GLuint ProgramImpl::getUniformIndex(const std::string &name) const
+{
+    size_t subscript = GL_INVALID_INDEX;
+    std::string baseName = gl::ParseUniformName(name, &subscript);
+
+    // The app is not allowed to specify array indices other than 0 for arrays of basic types
+    if (subscript != 0 && subscript != GL_INVALID_INDEX)
+    {
+        return GL_INVALID_INDEX;
+    }
+
+    unsigned int numUniforms = static_cast<unsigned int>(mUniforms.size());
+    for (unsigned int index = 0; index < numUniforms; index++)
+    {
+        if (mUniforms[index]->name == baseName)
+        {
+            if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
+            {
+                return index;
+            }
+        }
+    }
+
+    return GL_INVALID_INDEX;
+}
+
+GLuint ProgramImpl::getUniformBlockIndex(const std::string &name) const
+{
+    size_t subscript = GL_INVALID_INDEX;
+    std::string baseName = gl::ParseUniformName(name, &subscript);
+
+    unsigned int numUniformBlocks = static_cast<unsigned int>(mUniformBlocks.size());
+    for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
+    {
+        const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
+        if (uniformBlock.name == baseName)
+        {
+            const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
+            if (subscript == uniformBlock.elementIndex || arrayElementZero)
+            {
+                return blockIndex;
+            }
+        }
+    }
+
+    return GL_INVALID_INDEX;
+}
+
+void ProgramImpl::reset()
+{
+    SafeDeleteContainer(mUniforms);
+    mUniformIndex.clear();
+    SafeDeleteContainer(mUniformBlocks);
+}
+
+}
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index 47fb9be..94da0c7 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -23,17 +23,16 @@
 
 struct LinkResult
 {
-    LinkResult(bool linkSuccess, const gl::Error &error) : linkSuccess(linkSuccess), error(error) {}
-
     bool linkSuccess;
     gl::Error error;
+    LinkResult(bool linkSuccess, const gl::Error &error);
 };
 
 class ProgramImpl : angle::NonCopyable
 {
   public:
-    ProgramImpl(const gl::Program::Data &data) : mData(data) {}
-    virtual ~ProgramImpl() {}
+    ProgramImpl(const gl::Program::Data &data);
+    virtual ~ProgramImpl();
 
     virtual int getShaderVersion() const = 0;
 
@@ -66,16 +65,41 @@
     virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
     virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
 
+    virtual void getUniformfv(GLint location, GLfloat *params) = 0;
+    virtual void getUniformiv(GLint location, GLint *params) = 0;
+    virtual void getUniformuiv(GLint location, GLuint *params) = 0;
+
     // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to
     // determine if they can be removed from this interface.
     virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0;
 
-    // Gather uniform block active uniform indices, and uniform block offset info.
-    virtual void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
-                                        std::vector<gl::LinkedUniform> *uniforms) = 0;
+    const std::vector<gl::LinkedUniform*> &getUniforms() const { return mUniforms; }
+    const std::map<GLuint, gl::VariableLocation> &getUniformIndices() const { return mUniformIndex; }
+    const std::vector<gl::UniformBlock*> &getUniformBlocks() const { return mUniformBlocks; }
+
+    std::vector<gl::LinkedUniform*> &getUniforms() { return mUniforms; }
+    std::map<GLuint, gl::VariableLocation> &getUniformIndices() { return mUniformIndex; }
+    std::vector<gl::UniformBlock*> &getUniformBlocks() { return mUniformBlocks; }
+
+    gl::LinkedUniform *getUniformByLocation(GLint location) const;
+    gl::LinkedUniform *getUniformByName(const std::string &name) const;
+    gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const;
+
+    GLint getUniformLocation(const std::string &name) const;
+    GLuint getUniformIndex(const std::string &name) const;
+    GLuint getUniformBlockIndex(const std::string &name) const;
+
+    virtual void reset();
 
   protected:
     const gl::Program::Data &mData;
+
+    std::vector<gl::LinkedUniform*> mUniforms;
+
+    // TODO: use a hash map
+    std::map<GLuint, gl::VariableLocation> mUniformIndex;
+
+    std::vector<gl::UniformBlock*> mUniformBlocks;
 };
 
 }
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];
-}
 }
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index 5e86516..6efc654 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -20,6 +20,13 @@
 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
 #include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
 
+namespace gl
+{
+struct LinkedUniform;
+struct VariableLocation;
+struct VertexFormat;
+}
+
 namespace rx
 {
 class RendererD3D;
@@ -32,43 +39,6 @@
 #define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
 #endif
 
-// Helper struct representing a single shader uniform
-struct D3DUniform
-{
-    D3DUniform(GLenum typeIn,
-               const std::string &nameIn,
-               unsigned int arraySizeIn,
-               bool defaultBlock);
-    ~D3DUniform();
-
-    bool isSampler() const;
-    unsigned int elementCount() const { return std::max(1u, arraySize); }
-    bool isReferencedByVertexShader() const;
-    bool isReferencedByFragmentShader() const;
-
-    // Duplicated from the GL layer
-    GLenum type;
-    std::string name;
-    unsigned int arraySize;
-
-    // Pointer to a system copy of the data.
-    // TODO(jmadill): remove this in favor of gl::LinkedUniform::data().
-    uint8_t *data;
-
-    // Has the data been updated since the last sync?
-    bool dirty;
-
-    // Register information.
-    unsigned int vsRegisterIndex;
-    unsigned int psRegisterIndex;
-    unsigned int registerCount;
-
-    // Register "elements" are used for uniform structs in ES3, to appropriately identify single
-    // uniforms
-    // inside aggregate types, which are packed according C-like structure rules.
-    unsigned int registerElement;
-};
-
 class ProgramD3D : public ProgramImpl
 {
   public:
@@ -103,12 +73,13 @@
     LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override;
     GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
 
-    void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
-                                std::vector<gl::LinkedUniform> *uniforms) override;
-
     void initializeUniformStorage();
     gl::Error applyUniforms();
     gl::Error applyUniformBuffers(const gl::Data &data);
+    void assignUniformBlockRegister(gl::UniformBlock *uniformBlock,
+                                    GLenum shader,
+                                    unsigned int registerIndex,
+                                    const gl::Caps &caps);
     void dirtyAllUniforms();
 
     void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
@@ -133,9 +104,15 @@
     void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
     void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 
+    void getUniformfv(GLint location, GLfloat *params);
+    void getUniformiv(GLint location, GLint *params);
+    void getUniformuiv(GLint location, GLuint *params);
+
     const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; }
     const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; }
 
+    void reset();
+
     unsigned int getSerial() const;
 
     void sortAttributesByLayout(const std::vector<TranslatedAttribute> &unsortedAttributes,
@@ -198,24 +175,19 @@
         GLenum textureType;
     };
 
-    typedef std::map<std::string, sh::BlockMemberInfo> BlockInfoMap;
+    bool defineUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
+    void defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister);
+    void defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, const std::string &fullName,
+                       sh::HLSLBlockEncoder *encoder);
+    bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps);
+    bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
+    static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount,
+                               std::vector<Sampler> &outSamplers, GLuint *outUsedRange);
 
-    void assignUniformRegisters();
-    void assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform);
-    void assignUniformRegisters(const ShaderD3D *shader,
-                                const sh::ShaderVariable &uniform,
-                                const std::string &fullName,
-                                sh::HLSLBlockEncoder *encoder);
-    void assignAllSamplerRegisters();
-    void assignSamplerRegisters(const D3DUniform *d3dUniform);
-
-    static void AssignSamplers(unsigned int startSamplerIndex,
-                               GLenum samplerType,
-                               unsigned int samplerCount,
-                               std::vector<Sampler> &outSamplers,
-                               GLuint *outUsedRange);
-
-    size_t defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, BlockInfoMap *blockInfoOut);
+    void defineUniformBlocks(const gl::Caps &caps);
+    void defineUniformBlock(const gl::Shader &shader,
+                            const sh::InterfaceBlock &interfaceBlock,
+                            const gl::Caps &caps);
 
     template <typename T>
     void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType);
@@ -223,19 +195,23 @@
     template <int cols, int rows>
     void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType);
 
+    template <typename T>
+    void getUniformv(GLint location, T *params, GLenum uniformType);
+
+    template <typename VarT>
+    void defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
+                                   sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
+                                   bool inRowMajorLayout);
+
     LinkResult compileProgramExecutables(gl::InfoLog &infoLog,
                                          int registers,
                                          const std::vector<PackedVarying> &packedVaryings);
 
     void gatherTransformFeedbackVaryings(const std::vector<gl::LinkedVarying> &varyings);
-    D3DUniform *getD3DUniformByName(const std::string &name);
-    D3DUniform *getD3DUniformFromLocation(GLint location);
 
     void initSemanticIndex();
     void initAttributesByLayout();
 
-    void reset();
-
     RendererD3D *mRenderer;
     DynamicHLSL *mDynamicHLSL;
 
@@ -283,7 +259,6 @@
     gl::InputLayout mCachedInputLayout;
 
     std::vector<gl::LinkedVarying> mTransformFeedbackLinkedVaryings;
-    std::vector<D3DUniform *> mD3DUniforms;
 
     static unsigned int issueSerial();
     static unsigned int mCurrentSerial;
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index 87bbadd..f2629dd 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -37,10 +37,8 @@
 
 namespace rx
 {
-struct D3DUniform;
 class ImageD3D;
 class IndexBuffer;
-class ProgramD3D;
 class RenderTargetD3D;
 class ShaderExecutableD3D;
 class SwapChainD3D;
@@ -159,8 +157,7 @@
                                    const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard,
                                    bool transformFeedbackActive) = 0;
-    virtual gl::Error applyUniforms(const ProgramD3D &programD3D,
-                                    const std::vector<D3DUniform *> &uniformArray) = 0;
+    virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
     virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo) = 0;
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo) = 0;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 6c4000f..46a6af3 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -2093,8 +2093,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D,
-                                    const std::vector<D3DUniform *> &uniformArray)
+gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
 {
     unsigned int totalRegisterCountVS = 0;
     unsigned int totalRegisterCountPS = 0;
@@ -2102,25 +2101,26 @@
     bool vertexUniformsDirty = false;
     bool pixelUniformsDirty = false;
 
-    for (const D3DUniform *uniform : uniformArray)
+    for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
     {
-        if (uniform->isReferencedByVertexShader() && !uniform->isSampler())
+        const gl::LinkedUniform &uniform = *uniformArray[uniformIndex];
+
+        if (uniform.isReferencedByVertexShader() && !uniform.isSampler())
         {
-            totalRegisterCountVS += uniform->registerCount;
-            vertexUniformsDirty = (vertexUniformsDirty || uniform->dirty);
+            totalRegisterCountVS += uniform.registerCount;
+            vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty);
         }
 
-        if (uniform->isReferencedByFragmentShader() && !uniform->isSampler())
+        if (uniform.isReferencedByFragmentShader() && !uniform.isSampler())
         {
-            totalRegisterCountPS += uniform->registerCount;
-            pixelUniformsDirty = (pixelUniformsDirty || uniform->dirty);
+            totalRegisterCountPS += uniform.registerCount;
+            pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty);
         }
     }
 
-    const UniformStorage11 *vertexUniformStorage =
-        GetAs<UniformStorage11>(&programD3D.getVertexUniformStorage());
-    const UniformStorage11 *fragmentUniformStorage =
-        GetAs<UniformStorage11>(&programD3D.getFragmentUniformStorage());
+    const ProgramD3D *programD3D = GetAs<ProgramD3D>(&program);
+    const UniformStorage11 *vertexUniformStorage = GetAs<UniformStorage11>(&programD3D->getVertexUniformStorage());
+    const UniformStorage11 *fragmentUniformStorage = GetAs<UniformStorage11>(&programD3D->getFragmentUniformStorage());
     ASSERT(vertexUniformStorage);
     ASSERT(fragmentUniformStorage);
 
@@ -2148,26 +2148,26 @@
         mapPS = (float(*)[4])map.pData;
     }
 
-    for (const D3DUniform *uniform : uniformArray)
+    for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
     {
-        if (uniform->isSampler())
-            continue;
+        gl::LinkedUniform *uniform = uniformArray[uniformIndex];
 
-        unsigned int componentCount = (4 - uniform->registerElement);
-
-        // we assume that uniforms from structs are arranged in struct order in our uniforms list.
-        // otherwise we would overwrite previously written regions of memory.
-
-        if (uniform->isReferencedByVertexShader() && mapVS)
+        if (!uniform->isSampler())
         {
-            memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data,
-                   uniform->registerCount * sizeof(float) * componentCount);
-        }
+            unsigned int componentCount = (4 - uniform->registerElement);
 
-        if (uniform->isReferencedByFragmentShader() && mapPS)
-        {
-            memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data,
-                   uniform->registerCount * sizeof(float) * componentCount);
+            // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would
+            // overwrite previously written regions of memory.
+
+            if (uniform->isReferencedByVertexShader() && mapVS)
+            {
+                memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
+            }
+
+            if (uniform->isReferencedByFragmentShader() && mapPS)
+            {
+                memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
+            }
         }
     }
 
@@ -2253,7 +2253,7 @@
     }
 
     // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary
-    if (programD3D.usesGeometryShader())
+    if (programD3D->usesGeometryShader())
     {
         // needed for the point sprite geometry shader
         if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 2bce423..6260add 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -137,8 +137,7 @@
                            bool rasterizerDiscard,
                            bool transformFeedbackActive) override;
 
-    gl::Error applyUniforms(const ProgramD3D &programD3D,
-                            const std::vector<D3DUniform *> &uniformArray) override;
+    virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
     virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo);
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
     void applyTransformFeedbackBuffers(const gl::State &state) override;
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 61dec0a..8c59545 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -1910,45 +1910,46 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D,
-                                   const std::vector<D3DUniform *> &uniformArray)
+gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
 {
-    for (const D3DUniform *targetUniform : uniformArray)
+    for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
     {
-        if (!targetUniform->dirty)
-            continue;
+        gl::LinkedUniform *targetUniform = uniformArray[uniformIndex];
 
-        GLfloat *f = (GLfloat *)targetUniform->data;
-        GLint *i   = (GLint *)targetUniform->data;
-
-        switch (targetUniform->type)
+        if (targetUniform->dirty)
         {
-            case GL_SAMPLER_2D:
-            case GL_SAMPLER_CUBE:
+            GLfloat *f = (GLfloat*)targetUniform->data;
+            GLint *i = (GLint*)targetUniform->data;
+
+            switch (targetUniform->type)
+            {
+              case GL_SAMPLER_2D:
+              case GL_SAMPLER_CUBE:
                 break;
-            case GL_BOOL:
-            case GL_BOOL_VEC2:
-            case GL_BOOL_VEC3:
-            case GL_BOOL_VEC4:
+              case GL_BOOL:
+              case GL_BOOL_VEC2:
+              case GL_BOOL_VEC3:
+              case GL_BOOL_VEC4:
                 applyUniformnbv(targetUniform, i);
                 break;
-            case GL_FLOAT:
-            case GL_FLOAT_VEC2:
-            case GL_FLOAT_VEC3:
-            case GL_FLOAT_VEC4:
-            case GL_FLOAT_MAT2:
-            case GL_FLOAT_MAT3:
-            case GL_FLOAT_MAT4:
+              case GL_FLOAT:
+              case GL_FLOAT_VEC2:
+              case GL_FLOAT_VEC3:
+              case GL_FLOAT_VEC4:
+              case GL_FLOAT_MAT2:
+              case GL_FLOAT_MAT3:
+              case GL_FLOAT_MAT4:
                 applyUniformnfv(targetUniform, f);
                 break;
-            case GL_INT:
-            case GL_INT_VEC2:
-            case GL_INT_VEC3:
-            case GL_INT_VEC4:
+              case GL_INT:
+              case GL_INT_VEC2:
+              case GL_INT_VEC3:
+              case GL_INT_VEC4:
                 applyUniformniv(targetUniform, i);
                 break;
-            default:
+              default:
                 UNREACHABLE();
+            }
         }
     }
 
@@ -1963,7 +1964,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v)
+void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v)
 {
     if (targetUniform->isReferencedByFragmentShader())
     {
@@ -1976,7 +1977,7 @@
     }
 }
 
-void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v)
 {
     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -1992,7 +1993,7 @@
     applyUniformnfv(targetUniform, (GLfloat*)vector);
 }
 
-void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v)
 {
     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 95d9a52..2cd84fc 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -32,12 +32,10 @@
 {
 class Blit9;
 class IndexDataManager;
-class ProgramD3D;
 class StreamingIndexBufferInterface;
 class StaticIndexBufferInterface;
 class VertexDataManager;
 struct ClearParameters;
-struct D3DUniform;
 struct TranslatedAttribute;
 
 enum D3D9InitError
@@ -113,8 +111,7 @@
                            const gl::Framebuffer *framebuffer,
                            bool rasterizerDiscard,
                            bool transformFeedbackActive) override;
-    gl::Error applyUniforms(const ProgramD3D &programD3D,
-                            const std::vector<D3DUniform *> &uniformArray) override;
+    virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
     virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo);
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
@@ -261,9 +258,9 @@
 
     void release();
 
-    void applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v);
-    void applyUniformniv(const D3DUniform *targetUniform, const GLint *v);
-    void applyUniformnbv(const D3DUniform *targetUniform, const GLint *v);
+    void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v);
+    void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v);
+    void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v);
 
     gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
     gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index bae8389..3a70ae9 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -115,41 +115,68 @@
     }
 
     // Query the uniform information
-    ASSERT(mUniformRealLocationMap.empty());
-    const auto &uniforms = mData.getUniforms();
-    for (const gl::VariableLocation &entry : mData.getUniformLocations())
+    // TODO: A lot of this logic should be done at the gl::Program level
+    GLint activeUniformMaxLength = 0;
+    mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength);
+
+    std::vector<GLchar> uniformNameBuffer(activeUniformMaxLength);
+
+    GLint uniformCount = 0;
+    mFunctions->getProgramiv(mProgramID, GL_ACTIVE_UNIFORMS, &uniformCount);
+    for (GLint i = 0; i < uniformCount; i++)
     {
-        // From the spec:
-        // "Locations for sequential array indices are not required to be sequential."
-        const gl::LinkedUniform &uniform = uniforms[entry.index];
-        std::stringstream fullNameStr;
-        fullNameStr << uniform.name;
-        if (uniform.isArray())
+        GLsizei uniformNameLength = 0;
+        GLint uniformSize = 0;
+        GLenum uniformType = GL_NONE;
+        mFunctions->getActiveUniform(mProgramID, i, static_cast<GLsizei>(uniformNameBuffer.size()),
+                                     &uniformNameLength, &uniformSize, &uniformType,
+                                     &uniformNameBuffer[0]);
+
+        size_t subscript = 0;
+        std::string uniformName = gl::ParseUniformName(std::string(&uniformNameBuffer[0], uniformNameLength), &subscript);
+
+        bool isArray = uniformSize > 1 || subscript != GL_INVALID_INDEX;
+
+        for (size_t arrayIndex = 0; arrayIndex < static_cast<size_t>(uniformSize); arrayIndex++)
         {
-            fullNameStr << "[" << entry.element << "]";
+            std::string locationName = uniformName;
+            if (isArray)
+            {
+                locationName += "[" + Str(static_cast<int>(arrayIndex)) + "]";
+            }
+
+            GLint location = mFunctions->getUniformLocation(mProgramID, locationName.c_str());
+            if (location >= 0)
+            {
+                mUniformIndex[location] =
+                    gl::VariableLocation(uniformName, static_cast<unsigned int>(arrayIndex),
+                                         static_cast<unsigned int>(mUniforms.size()));
+
+                // If the uniform is a sampler, track it in the sampler bindings array
+                if (gl::IsSamplerType(uniformType))
+                {
+                    SamplerLocation samplerLoc;
+                    samplerLoc.samplerIndex = mSamplerBindings.size();
+                    samplerLoc.arrayIndex = arrayIndex;
+                    mSamplerUniformMap[location] = samplerLoc;
+                }
+            }
         }
-        const std::string &fullName = fullNameStr.str();
 
-        GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
-        mUniformRealLocationMap.push_back(realLocation);
-    }
+        // ANGLE uses 0 to identify an non-array uniform.
+        unsigned int arraySize = isArray ? static_cast<unsigned int>(uniformSize) : 0;
 
-    mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX);
-
-    for (size_t uniformId = 0; uniformId < uniforms.size(); ++uniformId)
-    {
-        const gl::LinkedUniform &linkedUniform = uniforms[uniformId];
-
-        if (!linkedUniform.isSampler() || !linkedUniform.staticUse)
-            continue;
-
-        mUniformIndexToSamplerIndex[uniformId] = mSamplerBindings.size();
+        // TODO: determine uniform precision
+        mUniforms.push_back(new gl::LinkedUniform(uniformType, GL_NONE, uniformName, arraySize, -1, sh::BlockMemberInfo::getDefaultBlockInfo()));
 
         // If uniform is a sampler type, insert it into the mSamplerBindings array
-        SamplerBindingGL samplerBinding;
-        samplerBinding.textureType = gl::SamplerTypeToTextureType(linkedUniform.type);
-        samplerBinding.boundTextureUnits.resize(linkedUniform.elementCount(), 0);
-        mSamplerBindings.push_back(samplerBinding);
+        if (gl::IsSamplerType(uniformType))
+        {
+            SamplerBindingGL samplerBinding;
+            samplerBinding.textureType = gl::SamplerTypeToTextureType(uniformType);
+            samplerBinding.boundTextureUnits.resize(uniformSize, 0);
+            mSamplerBindings.push_back(samplerBinding);
+        }
     }
 
     return LinkResult(true, gl::Error(GL_NO_ERROR));
@@ -164,61 +191,59 @@
 void ProgramGL::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform1fv(uniLoc(location), count, v);
+    mFunctions->uniform1fv(location, count, v);
 }
 
 void ProgramGL::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform2fv(uniLoc(location), count, v);
+    mFunctions->uniform2fv(location, count, v);
 }
 
 void ProgramGL::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform3fv(uniLoc(location), count, v);
+    mFunctions->uniform3fv(location, count, v);
 }
 
 void ProgramGL::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform4fv(uniLoc(location), count, v);
+    mFunctions->uniform4fv(location, count, v);
 }
 
 void ProgramGL::setUniform1iv(GLint location, GLsizei count, const GLint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform1iv(uniLoc(location), count, v);
+    mFunctions->uniform1iv(location, count, v);
 
-    const gl::VariableLocation &locationEntry = mData.getUniformLocations()[location];
-
-    size_t samplerIndex = mUniformIndexToSamplerIndex[locationEntry.index];
-    if (samplerIndex != GL_INVALID_INDEX)
+    auto iter = mSamplerUniformMap.find(location);
+    if (iter != mSamplerUniformMap.end())
     {
-        std::vector<GLuint> &boundTextureUnits = mSamplerBindings[samplerIndex].boundTextureUnits;
+        const SamplerLocation &samplerLoc = iter->second;
+        std::vector<GLuint> &boundTextureUnits = mSamplerBindings[samplerLoc.samplerIndex].boundTextureUnits;
 
-        size_t copyCount =
-            std::max<size_t>(count, boundTextureUnits.size() - locationEntry.element);
-        std::copy(v, v + copyCount, boundTextureUnits.begin() + locationEntry.element);
+        size_t copyCount = std::max<size_t>(count, boundTextureUnits.size() - samplerLoc.arrayIndex);
+        std::copy(v, v + copyCount, boundTextureUnits.begin() + samplerLoc.arrayIndex);
     }
 }
 
 void ProgramGL::setUniform2iv(GLint location, GLsizei count, const GLint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform2iv(uniLoc(location), count, v);
+    mFunctions->uniform2iv(location, count, v);
 }
 
 void ProgramGL::setUniform3iv(GLint location, GLsizei count, const GLint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform3iv(uniLoc(location), count, v);
+    mFunctions->uniform3iv(location, count, v);
 }
 
 void ProgramGL::setUniform4iv(GLint location, GLsizei count, const GLint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform4iv(uniLoc(location), count, v);
+    mFunctions->uniform4iv(location, count, v);
 }
 
 void ProgramGL::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
@@ -230,73 +255,88 @@
 void ProgramGL::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform2uiv(uniLoc(location), count, v);
+    mFunctions->uniform2uiv(location, count, v);
 }
 
 void ProgramGL::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform3uiv(uniLoc(location), count, v);
+    mFunctions->uniform3uiv(location, count, v);
 }
 
 void ProgramGL::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniform4uiv(uniLoc(location), count, v);
+    mFunctions->uniform4uiv(location, count, v);
 }
 
 void ProgramGL::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix2fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix2fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix3fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix3fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix4fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix4fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix2x3fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix2x3fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix3x2fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix3x2fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix2x4fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix2x4fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix4x2fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix4x2fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix3x4fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix3x4fv(location, count, transpose, value);
 }
 
 void ProgramGL::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 {
     mStateManager->useProgram(mProgramID);
-    mFunctions->uniformMatrix4x3fv(uniLoc(location), count, transpose, value);
+    mFunctions->uniformMatrix4x3fv(location, count, transpose, value);
+}
+
+void ProgramGL::getUniformfv(GLint location, GLfloat *params)
+{
+    mFunctions->getUniformfv(mProgramID, location, params);
+}
+
+void ProgramGL::getUniformiv(GLint location, GLint *params)
+{
+    mFunctions->getUniformiv(mProgramID, location, params);
+}
+
+void ProgramGL::getUniformuiv(GLint location, GLuint *params)
+{
+    mFunctions->getUniformuiv(mProgramID, location, params);
 }
 
 bool ProgramGL::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps)
@@ -307,9 +347,10 @@
 
 void ProgramGL::reset()
 {
-    mUniformRealLocationMap.clear();
+    ProgramImpl::reset();
+
+    mSamplerUniformMap.clear();
     mSamplerBindings.clear();
-    mUniformIndexToSamplerIndex.clear();
 }
 
 GLuint ProgramGL::getProgramID() const
@@ -322,9 +363,4 @@
     return mSamplerBindings;
 }
 
-void ProgramGL::gatherUniformBlockInfo(std::vector<gl::UniformBlock> * /*uniformBlocks*/,
-                                       std::vector<gl::LinkedUniform> * /*uniforms*/)
-{
-    // TODO(jmadill): Gather uniform block layout info, and data sizes.
-}
 }
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 9cc0a14..e83d7da 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -62,31 +62,32 @@
     void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
     void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
 
+    void getUniformfv(GLint location, GLfloat *params) override;
+    void getUniformiv(GLint location, GLint *params) override;
+    void getUniformuiv(GLint location, GLuint *params) override;
+
     bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) override;
 
-    void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
-                                std::vector<gl::LinkedUniform> *uniforms) override;
+    void reset() override;
 
     GLuint getProgramID() const;
     const std::vector<SamplerBindingGL> &getAppliedSamplerUniforms() const;
 
   private:
-    void reset();
-
-    // Helper function, makes it simpler to type.
-    GLint uniLoc(GLint glLocation) const { return mUniformRealLocationMap[glLocation]; }
-
     const FunctionsGL *mFunctions;
     StateManagerGL *mStateManager;
 
-    std::vector<GLint> mUniformRealLocationMap;
+    // A map from uniform location to index of mSamplerBindings and array index of the uniform
+    struct SamplerLocation
+    {
+        size_t samplerIndex;
+        size_t arrayIndex;
+    };
+    std::map<GLint, SamplerLocation> mSamplerUniformMap;
 
     // An array of the samplers that are used by the program
     std::vector<SamplerBindingGL> mSamplerBindings;
 
-    // A map from a mData.getUniforms() index to a mSamplerBindings index.
-    std::vector<size_t> mUniformIndexToSamplerIndex;
-
     GLuint mProgramID;
 };
 
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index b858d6f..ed642a7 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1096,11 +1096,8 @@
     return true;
 }
 
-static bool ValidateUniformCommonBase(gl::Context *context,
-                                      GLenum targetUniformType,
-                                      GLint location,
-                                      GLsizei count,
-                                      const LinkedUniform **uniformOut)
+static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
+                                      GLint location, GLsizei count, LinkedUniform **uniformOut)
 {
     if (count < 0)
     {
@@ -1127,16 +1124,16 @@
         return false;
     }
 
-    const LinkedUniform &uniform = program->getUniformByLocation(location);
+    LinkedUniform *uniform = program->getUniformByLocation(location);
 
     // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-    if (!uniform.isArray() && count > 1)
+    if (!uniform->isArray() && count > 1)
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
     }
 
-    *uniformOut = &uniform;
+    *uniformOut = uniform;
     return true;
 }
 
@@ -1149,7 +1146,7 @@
         return false;
     }
 
-    const LinkedUniform *uniform = nullptr;
+    LinkedUniform *uniform = NULL;
     if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
     {
         return false;
@@ -1184,7 +1181,7 @@
         return false;
     }
 
-    const LinkedUniform *uniform = nullptr;
+    LinkedUniform *uniform = NULL;
     if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
     {
         return false;
@@ -1480,7 +1477,7 @@
     // Uniform buffer validation
     for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
     {
-        const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
+        const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
         GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
         const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
 
@@ -1499,7 +1496,7 @@
             uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
         }
 
-        if (uniformBufferSize < uniformBlock.dataSize)
+        if (uniformBufferSize < uniformBlock->dataSize)
         {
             // undefined behaviour
             context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
@@ -1899,8 +1896,8 @@
     ASSERT(programObject);
 
     // sized queries -- ensure the provided buffer is large enough
-    const LinkedUniform &uniform = programObject->getUniformByLocation(location);
-    size_t requiredBytes = VariableExternalSize(uniform.type);
+    LinkedUniform *uniform = programObject->getUniformByLocation(location);
+    size_t requiredBytes = VariableExternalSize(uniform->type);
     if (static_cast<size_t>(bufSize) < requiredBytes)
     {
         context->recordError(Error(GL_INVALID_OPERATION));
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index 5bca02a..a5a6b21 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -140,6 +140,7 @@
             'libANGLE/renderer/FramebufferImpl.h',
             'libANGLE/renderer/ImageImpl.h',
             'libANGLE/renderer/ImplFactory.h',
+            'libANGLE/renderer/ProgramImpl.cpp',
             'libANGLE/renderer/ProgramImpl.h',
             'libANGLE/renderer/QueryImpl.h',
             'libANGLE/renderer/RenderbufferImpl.h',
diff --git a/src/tests/deqp_support/deqp_gles2_test_expectations.txt b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
index 746182e..da40c82 100644
--- a/src/tests/deqp_support/deqp_gles2_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
@@ -144,12 +144,9 @@
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.41 = FAIL
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.51 = FAIL
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.54 = FAIL
-1031 WIN : dEQP-GLES2.functional.uniform_api.random.61 = FAIL
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.72 = FAIL
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.79 = FAIL
 1031 WIN : dEQP-GLES2.functional.uniform_api.random.82 = FAIL
-1031 WIN : dEQP-GLES2.functional.uniform_api.random.87 = FAIL
-1031 WIN : dEQP-GLES2.functional.uniform_api.random.93 = FAIL
 504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_* = FAIL
 504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_* = FAIL
 504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_* = FAIL
diff --git a/src/tests/deqp_support/deqp_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
index 2948843..87405ad 100644
--- a/src/tests/deqp_support/deqp_gles3_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
@@ -982,14 +982,11 @@
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.3 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.6 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.8 = FAIL
-1098 WIN : dEQP-GLES3.functional.uniform_api.random.17 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.20 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.21 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.29 = FAIL
-1098 WIN : dEQP-GLES3.functional.uniform_api.random.54 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL
 1098 WIN : dEQP-GLES3.functional.uniform_api.random.83 = FAIL
-1098 WIN : dEQP-GLES3.functional.uniform_api.random.87 = FAIL
 1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.cond_float = FAIL
 1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.max_cond_float = FAIL
 1099 WIN : dEQP-GLES3.functional.attribute_location.bind_aliasing.cond_vec2 = FAIL
diff --git a/src/tests/gl_tests/UniformTest.cpp b/src/tests/gl_tests/UniformTest.cpp
index f8f4267..581f5ff 100644
--- a/src/tests/gl_tests/UniformTest.cpp
+++ b/src/tests/gl_tests/UniformTest.cpp
@@ -16,7 +16,11 @@
 class UniformTest : public ANGLETest
 {
   protected:
-    UniformTest() : mProgram(0), mUniformFLocation(-1), mUniformILocation(-1), mUniformBLocation(-1)
+    UniformTest()
+        : mProgram(0),
+          mUniformFLocation(-1),
+          mUniformILocation(-1),
+          mUniformBLocation(-1)
     {
         setWindowWidth(128);
         setWindowHeight(128);
@@ -165,6 +169,13 @@
 // Test that float to integer GetUniform rounds values correctly.
 TEST_P(UniformTest, FloatUniformStateQuery)
 {
+    // TODO(jmadill): remove this suppression once we support ANGLE-only state queries.
+    if (isAMD() && (GetParam() == ES2_OPENGL() || GetParam() == ES3_OPENGL()))
+    {
+        std::cout << "Skipping test due to a driver bug on AMD." << std::endl;
+        return;
+    }
+
     std::vector<GLfloat> inValues;
     std::vector<GLfloat> expectedFValues;
     std::vector<GLint> expectedIValues;
@@ -203,7 +214,7 @@
 
     for (size_t index = 0; index < inValues.size(); ++index)
     {
-        GLfloat inValue       = inValues[index];
+        GLfloat inValue = inValues[index];
         GLfloat expectedValue = expectedFValues[index];
 
         glUniform1f(mUniformFLocation, inValue);
@@ -215,7 +226,7 @@
 
     for (size_t index = 0; index < inValues.size(); ++index)
     {
-        GLfloat inValue     = inValues[index];
+        GLfloat inValue = inValues[index];
         GLint expectedValue = expectedIValues[index];
 
         glUniform1f(mUniformFLocation, inValue);
@@ -229,6 +240,13 @@
 // Test that integer to float GetUniform rounds values correctly.
 TEST_P(UniformTest, IntUniformStateQuery)
 {
+    // TODO(jmadill): remove this suppression once we support ANGLE-only state queries.
+    if ((isAMD() || isIntel()) && (GetParam() == ES2_OPENGL() || GetParam() == ES3_OPENGL()))
+    {
+        std::cout << "Skipping test due to a driver bug." << std::endl;
+        return;
+    }
+
     std::vector<GLint> inValues;
     std::vector<GLint> expectedIValues;
     std::vector<GLfloat> expectedFValues;
@@ -256,7 +274,7 @@
 
     for (size_t index = 0; index < inValues.size(); ++index)
     {
-        GLint inValue       = inValues[index];
+        GLint inValue = inValues[index];
         GLint expectedValue = expectedIValues[index];
 
         glUniform1i(mUniformILocation, inValue);
@@ -268,7 +286,7 @@
 
     for (size_t index = 0; index < inValues.size(); ++index)
     {
-        GLint inValue         = inValues[index];
+        GLint inValue = inValues[index];
         GLfloat expectedValue = expectedFValues[index];
 
         glUniform1i(mUniformILocation, inValue);
@@ -283,10 +301,9 @@
 TEST_P(UniformTest, BooleanUniformStateQuery)
 {
     glUseProgram(mProgram);
-    GLint intValue     = 0;
+    GLint intValue = 0;
     GLfloat floatValue = 0.0f;
 
-    // Calling Uniform1i
     glUniform1i(mUniformBLocation, GL_FALSE);
 
     glGetUniformiv(mProgram, mUniformBLocation, &intValue);
@@ -303,23 +320,6 @@
     glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
     EXPECT_EQ(1.0f, floatValue);
 
-    // Calling Uniform1f
-    glUniform1f(mUniformBLocation, 0.0f);
-
-    glGetUniformiv(mProgram, mUniformBLocation, &intValue);
-    EXPECT_EQ(0, intValue);
-
-    glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
-    EXPECT_EQ(0.0f, floatValue);
-
-    glUniform1f(mUniformBLocation, 1.0f);
-
-    glGetUniformiv(mProgram, mUniformBLocation, &intValue);
-    EXPECT_EQ(1, intValue);
-
-    glGetUniformfv(mProgram, mUniformBLocation, &floatValue);
-    EXPECT_EQ(1.0f, floatValue);
-
     ASSERT_GL_NO_ERROR();
 }