Add compute program compilation and linking support

Compute shaders can be now compiled and linked to create programs.
Some tests are added to verify successful and unsuccessful compute
shader linking.

The patch also replaces std::array<int, 3> with a custom struct
WorkGroupSize.

BUG=angleproject:1442

TEST=angle_end2end_tests
TEST=angle_unittests

Change-Id: I4ab0ac05755d0167a6d2a798f8d7f1516cf54d84
Reviewed-on: https://chromium-review.googlesource.com/366740
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/util/shader_utils.cpp b/util/shader_utils.cpp
index 62223b5..f92d715 100644
--- a/util/shader_utils.cpp
+++ b/util/shader_utils.cpp
@@ -77,6 +77,40 @@
     return CompileShader(type, source);
 }
 
+GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
+{
+    GLint linkStatus;
+    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+    if (linkStatus == 0)
+    {
+        if (outputErrorMessages)
+        {
+            GLint infoLogLength;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+            // Info log length includes the null terminator, so 1 means that the info log is an
+            // empty string.
+            if (infoLogLength > 1)
+            {
+                std::vector<GLchar> infoLog(infoLogLength);
+                glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
+                                    &infoLog[0]);
+
+                std::cerr << "program link failed: " << &infoLog[0];
+            }
+            else
+            {
+                std::cerr << "program link failed. <Empty log message>";
+            }
+        }
+
+        glDeleteProgram(program);
+        return 0;
+    }
+
+    return program;
+}
+
 GLuint CompileProgramWithTransformFeedback(
     const std::string &vsSource,
     const std::string &fsSource,
@@ -117,33 +151,7 @@
 
     glLinkProgram(program);
 
-    GLint linkStatus;
-    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
-
-    if (linkStatus == 0)
-    {
-        GLint infoLogLength;
-        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
-
-        // Info log length includes the null terminator, so 1 means that the info log is an empty
-        // string.
-        if (infoLogLength > 1)
-        {
-            std::vector<GLchar> infoLog(infoLogLength);
-            glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
-
-            std::cerr << "program link failed: " << &infoLog[0];
-        }
-        else
-        {
-            std::cerr << "program link failed. <Empty log message>";
-        }
-
-        glDeleteProgram(program);
-        return 0;
-    }
-
-    return program;
+    return CheckLinkStatusAndReturnProgram(program, true);
 }
 
 GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
@@ -163,3 +171,21 @@
 
     return CompileProgram(vsSource, fsSource);
 }
+
+GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
+{
+    GLuint program = glCreateProgram();
+
+    GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
+    if (cs == 0)
+    {
+        glDeleteProgram(program);
+        return 0;
+    }
+
+    glAttachShader(program, cs);
+
+    glLinkProgram(program);
+
+    return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
+}