ES31: Implement glDispatchCompute for OpenGL backend

This patch refers to https://chromium-review.googlesource.com/c/380639/

BUG=angleproject:1955
TESTCASE=angle_end2end_tests

Change-Id: Iafd7a6ba2d71c0b332d9267a1260d9dbd9800c02
Reviewed-on: https://chromium-review.googlesource.com/462089
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Yunchao He <yunchao.he@intel.com>
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES31.cpp b/src/libANGLE/validationES31.cpp
index 4176e82..b128f3a 100644
--- a/src/libANGLE/validationES31.cpp
+++ b/src/libANGLE/validationES31.cpp
@@ -769,4 +769,62 @@
     return true;
 }
 
+bool ValidateDispatchCompute(Context *context,
+                             GLuint numGroupsX,
+                             GLuint numGroupsY,
+                             GLuint numGroupsZ)
+{
+    if (context->getClientVersion() < ES_3_1)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
+        return false;
+    }
+
+    const State &state = context->getGLState();
+    Program *program   = state.getProgram();
+
+    if (program == nullptr)
+    {
+        context->handleError(
+            Error(GL_INVALID_OPERATION, "No active program object for the compute shader stage."));
+        return false;
+    }
+
+    if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
+    {
+        context->handleError(Error(
+            GL_INVALID_OPERATION,
+            "Program has not been successfully linked, or program contains no compute shaders."));
+        return false;
+    }
+
+    const Caps &caps = context->getCaps();
+    if (numGroupsX > caps.maxComputeWorkGroupCount[0])
+    {
+        context->handleError(
+            Error(GL_INVALID_VALUE,
+                  "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0](%u).",
+                  caps.maxComputeWorkGroupCount[0]));
+        return false;
+    }
+    if (numGroupsY > caps.maxComputeWorkGroupCount[1])
+    {
+        context->handleError(
+            Error(GL_INVALID_VALUE,
+                  "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1](%u).",
+                  caps.maxComputeWorkGroupCount[1]));
+        return false;
+    }
+    if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
+    {
+        context->handleError(
+            Error(GL_INVALID_VALUE,
+                  "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2](%u).",
+                  caps.maxComputeWorkGroupCount[2]));
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace gl