Implement ES3.1 glProgramUniform* entry points

BUG=angleproject:1589
TEST=dEQP-GLES31.functional.program_uniform.*

Change-Id: I27fffa755fd277ed918746259cac88ab9e349c41
Reviewed-on: https://chromium-review.googlesource.com/412193
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index e9b143d..6d76d33 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2560,19 +2560,20 @@
 }
 
 static bool ValidateUniformCommonBase(gl::Context *context,
+                                      gl::Program *program,
                                       GLenum targetUniformType,
                                       GLint location,
                                       GLsizei count,
                                       const LinkedUniform **uniformOut)
 {
+    // TODO(Jiajia): Add image uniform check in future.
     if (count < 0)
     {
         context->handleError(Error(GL_INVALID_VALUE));
         return false;
     }
 
-    gl::Program *program = context->getGLState().getProgram();
-    if (!program)
+    if (!program || !program->isLinked())
     {
         context->handleError(Error(GL_INVALID_OPERATION));
         return false;
@@ -2603,6 +2604,67 @@
     return true;
 }
 
+bool ValidateProgramUniform(gl::Context *context,
+                            GLenum uniformType,
+                            GLuint program,
+                            GLint location,
+                            GLsizei count)
+{
+    // Check for ES31 program uniform entry points
+    if (context->getClientVersion() < Version(3, 1))
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    const LinkedUniform *uniform = nullptr;
+    gl::Program *programObject   = GetValidProgram(context, program);
+    if (!ValidateUniformCommonBase(context, programObject, uniformType, location, count, &uniform))
+    {
+        return false;
+    }
+
+    GLenum targetBoolType    = VariableBoolVectorType(uniformType);
+    bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
+    if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateProgramUniformMatrix(gl::Context *context,
+                                  GLenum matrixType,
+                                  GLuint program,
+                                  GLint location,
+                                  GLsizei count,
+                                  GLboolean transpose)
+{
+    // Check for ES31 program uniform entry points
+    if (context->getClientVersion() < Version(3, 1))
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    const LinkedUniform *uniform = nullptr;
+    gl::Program *programObject   = GetValidProgram(context, program);
+    if (!ValidateUniformCommonBase(context, programObject, matrixType, location, count, &uniform))
+    {
+        return false;
+    }
+
+    if (uniform->type != matrixType)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return true;
+}
+
 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
 {
     // Check for ES3 uniform entry points
@@ -2614,7 +2676,8 @@
     }
 
     const LinkedUniform *uniform = nullptr;
-    if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
+    gl::Program *program         = context->getGLState().getProgram();
+    if (!ValidateUniformCommonBase(context, program, uniformType, location, count, &uniform))
     {
         return false;
     }
@@ -2649,7 +2712,8 @@
     }
 
     const LinkedUniform *uniform = nullptr;
-    if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
+    gl::Program *program         = context->getGLState().getProgram();
+    if (!ValidateUniformCommonBase(context, program, matrixType, location, count, &uniform))
     {
         return false;
     }