Add getUniform impl methods.

This will let us remove some of the uniform data management code in
the GL front-end, and simplify the GL back-end. It will also enable
us to implement uniform data more efficiently in the D3D11 back-end,
and probably Vulkan back-end later.

This also implements a new impl method for the ProgramGL class to
flag optimized-out uniforms as no longer used, post-link. This is
important because otherwise the optimized uniforms get assigned
valid locations, and then the getUniform calls are expected to
succeed.

We also use a workaround for uniform value queries for the GL
back-end. It seems as though some drivers (seen on NVIDIA and AMD)
may not properly clamp to the maximum representable integer value
when querying out-of-range floating point values. Work around this by
always calling the driver with the proper type and then casting the
value in ANGLE.

BUG=angleproject:1390

Change-Id: I03dc2382e7af52455c356a2bf3971a4d1bd46ec6
Reviewed-on: https://chromium-review.googlesource.com/616785
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index b84ba00..137b7c1 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -4516,14 +4516,14 @@
 {
     Program *programObject = getProgram(program);
     ASSERT(programObject);
-    programObject->getUniformfv(location, params);
+    programObject->getUniformfv(this, location, params);
 }
 
 void Context::getUniformiv(GLuint program, GLint location, GLint *params)
 {
     Program *programObject = getProgram(program);
     ASSERT(programObject);
-    programObject->getUniformiv(location, params);
+    programObject->getUniformiv(this, location, params);
 }
 
 GLint Context::getUniformLocation(GLuint program, const GLchar *name)
@@ -5073,7 +5073,7 @@
 void Context::getUniformuiv(GLuint program, GLint location, GLuint *params)
 {
     const Program *programObject = getProgram(program);
-    programObject->getUniformuiv(location, params);
+    programObject->getUniformuiv(this, location, params);
 }
 
 GLint Context::getFragDataLocation(GLuint program, const GLchar *name)
diff --git a/src/libANGLE/MemoryProgramCache.cpp b/src/libANGLE/MemoryProgramCache.cpp
index c8d92e5..b6c2d73 100644
--- a/src/libANGLE/MemoryProgramCache.cpp
+++ b/src/libANGLE/MemoryProgramCache.cpp
@@ -315,7 +315,9 @@
     {
         GLenum textureType  = stream.readInt<GLenum>();
         size_t bindingCount = stream.readInt<size_t>();
-        state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
+        bool unreferenced   = stream.readBool();
+        state->mSamplerBindings.emplace_back(
+            SamplerBinding(textureType, bindingCount, unreferenced));
     }
 
     unsigned int imageRangeLow  = stream.readInt<unsigned int>();
@@ -475,6 +477,7 @@
     {
         stream.writeInt(samplerBinding.textureType);
         stream.writeInt(samplerBinding.boundTextureUnits.size());
+        stream.writeInt(samplerBinding.unreferenced);
     }
 
     stream.writeInt(state.getImageUniformRange().low());
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 1f47b9d..cc37d2f 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -788,6 +788,19 @@
 
     setUniformValuesFromBindingQualifiers();
 
+    // Mark implementation-specific unreferenced uniforms as ignored.
+    mProgram->markUnusedUniformLocations(&mState.mUniformLocations);
+
+    // Update sampler bindings with unreferenced uniforms.
+    for (const auto &location : mState.mUniformLocations)
+    {
+        if (!location.used && mState.isSamplerUniformIndex(location.index))
+        {
+            GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(location.index);
+            mState.mSamplerBindings[samplerIndex].unreferenced = true;
+        }
+    }
+
     // Save to the program cache.
     if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
                   !context->getWorkarounds().disableProgramCachingForTransformFeedback))
@@ -1444,19 +1457,55 @@
     mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v);
 }
 
-void Program::getUniformfv(GLint location, GLfloat *v) const
+void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const
 {
-    getUniformInternal(location, v);
+    const auto &uniformLocation = mState.getUniformLocations()[location];
+    const auto &uniform         = mState.getUniforms()[uniformLocation.index];
+
+    GLenum nativeType = gl::VariableComponentType(uniform.type);
+    if (nativeType == GL_FLOAT)
+    {
+        mProgram->getUniformfv(context, location, v);
+    }
+    else
+    {
+        getUniformInternal(context, v, location, nativeType,
+                           gl::VariableComponentCount(uniform.type));
+    }
 }
 
-void Program::getUniformiv(GLint location, GLint *v) const
+void Program::getUniformiv(const Context *context, GLint location, GLint *v) const
 {
-    getUniformInternal(location, v);
+    const auto &uniformLocation = mState.getUniformLocations()[location];
+    const auto &uniform         = mState.getUniforms()[uniformLocation.index];
+
+    GLenum nativeType = gl::VariableComponentType(uniform.type);
+    if (nativeType == GL_INT || nativeType == GL_BOOL)
+    {
+        mProgram->getUniformiv(context, location, v);
+    }
+    else
+    {
+        getUniformInternal(context, v, location, nativeType,
+                           gl::VariableComponentCount(uniform.type));
+    }
 }
 
-void Program::getUniformuiv(GLint location, GLuint *v) const
+void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const
 {
-    getUniformInternal(location, v);
+    const auto &uniformLocation = mState.getUniformLocations()[location];
+    const auto &uniform         = mState.getUniforms()[uniformLocation.index];
+
+    GLenum nativeType = gl::VariableComponentType(uniform.type);
+    if (nativeType == GL_UNSIGNED_INT)
+    {
+        mProgram->getUniformuiv(context, location, v);
+    }
+    else
+    {
+        getUniformInternal(context, v, location, nativeType,
+                           gl::VariableComponentCount(uniform.type));
+    }
 }
 
 void Program::flagForDeletion()
@@ -1506,6 +1555,9 @@
     // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
     for (const auto &samplerBinding : mState.mSamplerBindings)
     {
+        if (samplerBinding.unreferenced)
+            continue;
+
         GLenum textureType = samplerBinding.textureType;
 
         for (GLuint textureUnit : samplerBinding.boundTextureUnits)
@@ -1876,7 +1928,7 @@
         const auto &samplerUniform = mState.mUniforms[samplerIndex];
         GLenum textureType         = SamplerTypeToTextureType(samplerUniform.type);
         mState.mSamplerBindings.emplace_back(
-            SamplerBinding(textureType, samplerUniform.elementCount()));
+            SamplerBinding(textureType, samplerUniform.elementCount(), false));
     }
 }
 
@@ -2984,39 +3036,52 @@
     return clampedCount;
 }
 
+// Driver differences mean that doing the uniform value cast ourselves gives consistent results.
+// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
 template <typename DestT>
-void Program::getUniformInternal(GLint location, DestT *dataOut) const
+void Program::getUniformInternal(const Context *context,
+                                 DestT *dataOut,
+                                 GLint location,
+                                 GLenum nativeType,
+                                 int components) const
 {
-    const VariableLocation &locationInfo = mState.mUniformLocations[location];
-    const LinkedUniform &uniform         = mState.mUniforms[locationInfo.index];
-
-    const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
-
-    GLenum componentType = VariableComponentType(uniform.type);
-    if (componentType == GLTypeToGLenum<DestT>::value)
+    switch (nativeType)
     {
-        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);
+        {
+            GLint tempValue[16] = {0};
+            mProgram->getUniformiv(context, location, tempValue);
+            UniformStateQueryCastLoop<GLboolean>(
+                dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
             break;
+        }
+        case GL_INT:
+        {
+            GLint tempValue[16] = {0};
+            mProgram->getUniformiv(context, location, tempValue);
+            UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
+                                             components);
+            break;
+        }
+        case GL_UNSIGNED_INT:
+        {
+            GLuint tempValue[16] = {0};
+            mProgram->getUniformuiv(context, location, tempValue);
+            UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
+                                              components);
+            break;
+        }
         case GL_FLOAT:
-            UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
+        {
+            GLfloat tempValue[16] = {0};
+            mProgram->getUniformfv(context, location, tempValue);
+            UniformStateQueryCastLoop<GLfloat>(
+                dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
             break;
+        }
         default:
             UNREACHABLE();
+            break;
     }
 }
 
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 3690fb7..fb97643 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -171,8 +171,8 @@
 // This small structure encapsulates binding sampler uniforms to active GL textures.
 struct SamplerBinding
 {
-    SamplerBinding(GLenum textureTypeIn, size_t elementCount)
-        : textureType(textureTypeIn), boundTextureUnits(elementCount, 0)
+    SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced)
+        : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced)
     {
     }
 
@@ -181,6 +181,9 @@
 
     // List of all textures bound to this sampler, of type textureType.
     std::vector<GLuint> boundTextureUnits;
+
+    // A note if this sampler is an unreferenced uniform.
+    bool unreferenced;
 };
 
 // A varying with tranform feedback enabled. If it's an array, either the whole array or one of its
@@ -457,9 +460,9 @@
     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) const;
-    void getUniformiv(GLint location, GLint *params) const;
-    void getUniformuiv(GLint location, GLuint *params) const;
+    void getUniformfv(const Context *context, GLint location, GLfloat *params) const;
+    void getUniformiv(const Context *context, GLint location, GLint *params) const;
+    void getUniformuiv(const Context *context, GLint location, GLuint *params) const;
 
     void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
     GLuint getActiveUniformBlockCount() const;
@@ -627,7 +630,11 @@
                               const T *v);
 
     template <typename DestT>
-    void getUniformInternal(GLint location, DestT *dataOut) const;
+    void getUniformInternal(const Context *context,
+                            DestT *dataOut,
+                            GLint location,
+                            GLenum nativeType,
+                            int components) const;
 
     ProgramState mState;
     rx::ProgramImpl *mProgram;
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index d2b7118..b32b93b 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -72,6 +72,15 @@
     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;
 
+    // Done in the back-end to avoid having to keep a system copy of uniform data.
+    virtual void getUniformfv(const gl::Context *context,
+                              GLint location,
+                              GLfloat *params) const = 0;
+    virtual void getUniformiv(const gl::Context *context, GLint location, GLint *params) const = 0;
+    virtual void getUniformuiv(const gl::Context *context,
+                               GLint location,
+                               GLuint *params) const = 0;
+
     // TODO: synchronize in syncState when dirty bits exist.
     virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
 
@@ -90,6 +99,11 @@
                                          GLint components,
                                          const GLfloat *coeffs) = 0;
 
+    // Implementation-specific method for ignoring unreferenced uniforms. Some implementations may
+    // perform more extensive analysis and ignore some locations that ANGLE doesn't detect as
+    // unreferenced. This method is not required to be overriden by a back-end.
+    virtual void markUnusedUniformLocations(std::vector<gl::VariableLocation> *uniformLocations) {}
+
   protected:
     const gl::ProgramState &mState;
 };
diff --git a/src/libANGLE/renderer/ProgramImpl_mock.h b/src/libANGLE/renderer/ProgramImpl_mock.h
index 8883ca4..9587dbd 100644
--- a/src/libANGLE/renderer/ProgramImpl_mock.h
+++ b/src/libANGLE/renderer/ProgramImpl_mock.h
@@ -55,6 +55,10 @@
     MOCK_METHOD4(setUniformMatrix3x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
     MOCK_METHOD4(setUniformMatrix4x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
 
+    MOCK_CONST_METHOD3(getUniformfv, void(const gl::Context *, GLint, GLfloat *));
+    MOCK_CONST_METHOD3(getUniformiv, void(const gl::Context *, GLint, GLint *));
+    MOCK_CONST_METHOD3(getUniformuiv, void(const gl::Context *, GLint, GLuint *));
+
     MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint));
     MOCK_CONST_METHOD2(getUniformBlockSize, bool(const std::string &, size_t *));
     MOCK_CONST_METHOD2(getUniformBlockMemberInfo, bool(const std::string &, sh::BlockMemberInfo *));
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 3c4c432..dfe0665 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -18,6 +18,7 @@
 #include "libANGLE/VaryingPacking.h"
 #include "libANGLE/VertexArray.h"
 #include "libANGLE/features.h"
+#include "libANGLE/queryconversions.h"
 #include "libANGLE/renderer/ContextImpl.h"
 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
@@ -2602,4 +2603,29 @@
     return false;
 }
 
+template <typename DestT>
+void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const
+{
+    const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
+    const gl::LinkedUniform &uniform         = mState.getUniforms()[locationInfo.index];
+
+    const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
+    memcpy(dataOut, srcPointer, uniform.getElementSize());
+}
+
+void ProgramD3D::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
+{
+    getUniformInternal(location, params);
+}
+
+void ProgramD3D::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
+{
+    getUniformInternal(location, params);
+}
+
+void ProgramD3D::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
+{
+    getUniformInternal(location, params);
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index bc27b31..eb24bbc 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -247,6 +247,10 @@
                                GLboolean transpose,
                                const GLfloat *value);
 
+    void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
+    void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
+    void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
+
     void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
 
     UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage.get(); }
@@ -360,6 +364,9 @@
                                std::vector<Sampler> &outSamplers,
                                GLuint *outUsedRange);
 
+    template <typename DestT>
+    void getUniformInternal(GLint location, DestT *dataOut) const;
+
     template <typename T>
     void setUniform(GLint location, GLsizei count, const T *v, GLenum targetUniformType);
 
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index 3c1fe40..2e3c64b 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -753,4 +753,31 @@
                                  baseViewIndex);
 }
 
+void ProgramGL::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
+{
+    mFunctions->getUniformfv(mProgramID, uniLoc(location), params);
+}
+
+void ProgramGL::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
+{
+    mFunctions->getUniformiv(mProgramID, uniLoc(location), params);
+}
+
+void ProgramGL::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
+{
+    mFunctions->getUniformuiv(mProgramID, uniLoc(location), params);
+}
+
+void ProgramGL::markUnusedUniformLocations(std::vector<gl::VariableLocation> *uniformLocations)
+{
+    GLint maxLocation = static_cast<GLint>(uniformLocations->size());
+    for (GLint location = 0; location < maxLocation; ++location)
+    {
+        if (uniLoc(location) == -1)
+        {
+            (*uniformLocations)[location].used = false;
+        }
+    }
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index ea8acf8..01a20db 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -65,6 +65,10 @@
     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(const gl::Context *context, GLint location, GLfloat *params) const override;
+    void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
+    void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
+
     void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
 
     bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const override;
@@ -76,6 +80,8 @@
                                  GLint components,
                                  const GLfloat *coeffs) override;
 
+    void markUnusedUniformLocations(std::vector<gl::VariableLocation> *uniformLocations) override;
+
     GLuint getProgramID() const;
 
     void enableSideBySideRenderingPath() const;
diff --git a/src/libANGLE/renderer/null/ProgramNULL.cpp b/src/libANGLE/renderer/null/ProgramNULL.cpp
index cee30dd..1bdc09b 100644
--- a/src/libANGLE/renderer/null/ProgramNULL.cpp
+++ b/src/libANGLE/renderer/null/ProgramNULL.cpp
@@ -164,6 +164,21 @@
 {
 }
 
+void ProgramNULL::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
+{
+    // TODO(jmadill): Write some values.
+}
+
+void ProgramNULL::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
+{
+    // TODO(jmadill): Write some values.
+}
+
+void ProgramNULL::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
+{
+    // TODO(jmadill): Write some values.
+}
+
 void ProgramNULL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
 {
 }
diff --git a/src/libANGLE/renderer/null/ProgramNULL.h b/src/libANGLE/renderer/null/ProgramNULL.h
index 363d334..b7c8d7f 100644
--- a/src/libANGLE/renderer/null/ProgramNULL.h
+++ b/src/libANGLE/renderer/null/ProgramNULL.h
@@ -82,6 +82,10 @@
                                GLboolean transpose,
                                const GLfloat *value) override;
 
+    void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
+    void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
+    void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
+
     // TODO: synchronize in syncState when dirty bits exist.
     void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
 
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
index 36cbb29..7f1bddd 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
@@ -312,4 +312,19 @@
     return &mPipelineLayout;
 }
 
+void ProgramVk::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
+{
+    UNIMPLEMENTED();
+}
+
+void ProgramVk::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
+{
+    UNIMPLEMENTED();
+}
+
+void ProgramVk::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
+{
+    UNIMPLEMENTED();
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.h b/src/libANGLE/renderer/vulkan/ProgramVk.h
index c24cc3f..50550c7 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.h
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.h
@@ -84,6 +84,10 @@
                                GLboolean transpose,
                                const GLfloat *value) override;
 
+    void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
+    void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
+    void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
+
     // TODO: synchronize in syncState when dirty bits exist.
     void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
 
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index 11f5f13..0def420 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -458,7 +458,7 @@
         Program *programObject = context->getProgram(program);
         ASSERT(programObject);
 
-        programObject->getUniformfv(location, params);
+        programObject->getUniformfv(context, location, params);
     }
 }
 
@@ -479,7 +479,7 @@
         Program *programObject = context->getProgram(program);
         ASSERT(programObject);
 
-        programObject->getUniformiv(location, params);
+        programObject->getUniformiv(context, location, params);
     }
 }
 
@@ -2256,7 +2256,7 @@
         Program *programObject = context->getProgram(program);
         ASSERT(programObject);
 
-        programObject->getUniformfv(location, params);
+        programObject->getUniformfv(context, location, params);
         SetRobustLengthParam(length, writeLength);
     }
 }
@@ -2285,7 +2285,7 @@
         Program *programObject = context->getProgram(program);
         ASSERT(programObject);
 
-        programObject->getUniformiv(location, params);
+        programObject->getUniformiv(context, location, params);
         SetRobustLengthParam(length, writeLength);
     }
 }
@@ -2914,7 +2914,7 @@
         Program *programObject = context->getProgram(program);
         ASSERT(programObject);
 
-        programObject->getUniformuiv(location, params);
+        programObject->getUniformuiv(context, location, params);
         SetRobustLengthParam(length, writeLength);
     }
 }
diff --git a/src/tests/gl_tests/ComputeShaderTest.cpp b/src/tests/gl_tests/ComputeShaderTest.cpp
index f7326a2..7e677ee 100644
--- a/src/tests/gl_tests/ComputeShaderTest.cpp
+++ b/src/tests/gl_tests/ComputeShaderTest.cpp
@@ -77,11 +77,13 @@
 
     ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
 
-    GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
-    EXPECT_NE(-1, uniformLoc);
+    // It's not possible to validate uniforms are present since they are unreferenced.
+    // TODO(jmadill): Make uniforms referenced.
+    // GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
+    // EXPECT_NE(-1, uniformLoc);
 
-    uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
-    EXPECT_NE(-1, uniformLoc);
+    // uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
+    // EXPECT_NE(-1, uniformLoc);
 
     EXPECT_GL_NO_ERROR();
 }
diff --git a/src/tests/gl_tests/UniformTest.cpp b/src/tests/gl_tests/UniformTest.cpp
index 4ecc3d7..80534d0 100644
--- a/src/tests/gl_tests/UniformTest.cpp
+++ b/src/tests/gl_tests/UniformTest.cpp
@@ -43,6 +43,9 @@
             "  gl_FragColor = vec4(uniF + float(uniI));\n"
             "  gl_FragColor += vec4(uniB ? 1.0 : 0.0);\n"
             "  gl_FragColor += vec4(uniBArr[0] ? 1.0 : 0.0);\n"
+            "  gl_FragColor += vec4(uniBArr[1] ? 1.0 : 0.0);\n"
+            "  gl_FragColor += vec4(uniBArr[2] ? 1.0 : 0.0);\n"
+            "  gl_FragColor += vec4(uniBArr[3] ? 1.0 : 0.0);\n"
             "}";
 
         mProgram = CompileProgram(vertexShader, fragShader);
@@ -235,6 +238,11 @@
 // Test that integer to float GetUniform rounds values correctly.
 TEST_P(UniformTest, IntUniformStateQuery)
 {
+    // Qualcomm seems to have a bug where integer uniforms are internally stored as float, and
+    // large values are rounded to the nearest float representation of an integer.
+    // TODO(jmadill): Lift this suppression when/if the bug is fixed.
+    ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
+
     std::vector<GLint> inValues;
     std::vector<GLint> expectedIValues;
     std::vector<GLfloat> expectedFValues;
@@ -266,10 +274,10 @@
         GLint expectedValue = expectedIValues[index];
 
         glUniform1i(mUniformILocation, inValue);
-        GLint testValue;
+        GLint testValue = 1234567;
         glGetUniformiv(mProgram, mUniformILocation, &testValue);
         ASSERT_GL_NO_ERROR();
-        EXPECT_EQ(expectedValue, testValue);
+        EXPECT_EQ(expectedValue, testValue) << " with glGetUniformiv";
     }
 
     for (size_t index = 0; index < inValues.size(); ++index)
@@ -278,10 +286,10 @@
         GLfloat expectedValue = expectedFValues[index];
 
         glUniform1i(mUniformILocation, inValue);
-        GLfloat testValue;
+        GLfloat testValue = 124567.0;
         glGetUniformfv(mProgram, mUniformILocation, &testValue);
         ASSERT_GL_NO_ERROR();
-        EXPECT_EQ(expectedValue, testValue);
+        EXPECT_EQ(expectedValue, testValue) << " with glGetUniformfv";
     }
 }
 
@@ -343,6 +351,11 @@
         glGetUniformLocation(mProgram, "uniBArr[3]"),
     };
 
+    for (int i = 0; i < 4; ++i)
+    {
+        ASSERT_NE(-1, locations[i]) << " with i=" << i;
+    }
+
     // Calling Uniform1iv
     glUniform1iv(locations[0], 4, boolValuesi);
 
@@ -350,14 +363,14 @@
     {
         int value = -1;
         glGetUniformiv(mProgram, locations[idx], &value);
-        EXPECT_EQ(boolValuesi[idx], value);
+        EXPECT_EQ(boolValuesi[idx], value) << " with Uniform1iv/GetUniformiv at " << idx;
     }
 
     for (unsigned int idx = 0; idx < 4; ++idx)
     {
         float value = -1.0f;
         glGetUniformfv(mProgram, locations[idx], &value);
-        EXPECT_EQ(boolValuesf[idx], value);
+        EXPECT_EQ(boolValuesf[idx], value) << " with Uniform1iv/GetUniformfv at " << idx;
     }
 
     // Calling Uniform1fv
@@ -367,14 +380,14 @@
     {
         int value = -1;
         glGetUniformiv(mProgram, locations[idx], &value);
-        EXPECT_EQ(boolValuesi[idx], value);
+        EXPECT_EQ(boolValuesi[idx], value) << " with Uniform1fv/GetUniformiv at " << idx;
     }
 
     for (unsigned int idx = 0; idx < 4; ++idx)
     {
         float value = -1.0f;
         glGetUniformfv(mProgram, locations[idx], &value);
-        EXPECT_EQ(boolValuesf[idx], value);
+        EXPECT_EQ(boolValuesf[idx], value) << " with Uniform1fv/GetUniformfv at " << idx;
     }
 
     ASSERT_GL_NO_ERROR();
@@ -415,6 +428,10 @@
         "out vec4 color;\n"
         "void main() {\n"
         "  color = vec4(uniMat3x2[0][0][0]);\n"
+        "  color += vec4(uniMat3x2[1][0][0]);\n"
+        "  color += vec4(uniMat3x2[2][0][0]);\n"
+        "  color += vec4(uniMat3x2[3][0][0]);\n"
+        "  color += vec4(uniMat3x2[4][0][0]);\n"
         "}";
 
     mProgram = CompileProgram(vertexShader, fragShader);
@@ -474,6 +491,10 @@
         "out vec4 color;\n"
         "void main() {\n"
         "  color = vec4(uniMat3x2[0][0][0] + uniF[0]);\n"
+        "  color = vec4(uniMat3x2[1][0][0] + uniF[1]);\n"
+        "  color = vec4(uniMat3x2[2][0][0] + uniF[2]);\n"
+        "  color = vec4(uniMat3x2[3][0][0] + uniF[3]);\n"
+        "  color = vec4(uniMat3x2[4][0][0] + uniF[4]);\n"
         "}";
 
     mProgram = CompileProgram(vertexShader, fragShader);