ES31: Add GL_ATOMIC_COUNTER_BUFFER_BINDING binding point

BUG=angleproject:1729
TEST=dEQP-GLES31.functional.state_query.integer.atomic_counter*
     dEQP-GLES31.functional.state_query.indexed.atomic_counter*
     angle_end2end_tests:AtomicCounterBufferTest

Change-Id: I059c4e22e04cedec9134ec9f631de33f77b1fbe2
Reviewed-on: https://chromium-review.googlesource.com/430959
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 13a1d2f..80ff967 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -1230,6 +1230,142 @@
     return true;
 }
 
+static bool ValidateBindBufferCommon(Context *context,
+                                     GLenum target,
+                                     GLuint index,
+                                     GLuint buffer,
+                                     GLintptr offset,
+                                     GLsizeiptr size)
+{
+    if (context->getClientMajorVersion() < 3)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    if (buffer != 0 && offset < 0)
+    {
+        context->handleError(Error(GL_INVALID_VALUE, "buffer is non-zero and offset is negative."));
+        return false;
+    }
+
+    if (!context->getGLState().isBindGeneratesResourceEnabled() &&
+        !context->isBufferGenerated(buffer))
+    {
+        context->handleError(Error(GL_INVALID_OPERATION, "Buffer was not generated."));
+        return false;
+    }
+
+    const Caps &caps = context->getCaps();
+    switch (target)
+    {
+        case GL_TRANSFORM_FEEDBACK_BUFFER:
+        {
+            if (index >= caps.maxTransformFeedbackSeparateAttributes)
+            {
+                context->handleError(Error(GL_INVALID_VALUE,
+                                           "index is greater than or equal to the number of "
+                                           "TRANSFORM_FEEDBACK_BUFFER indexed binding points."));
+                return false;
+            }
+            if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0))
+            {
+                context->handleError(
+                    Error(GL_INVALID_VALUE, "offset and size must be multiple of 4."));
+                return false;
+            }
+
+            TransformFeedback *curTransformFeedback =
+                context->getGLState().getCurrentTransformFeedback();
+            if (curTransformFeedback && curTransformFeedback->isActive())
+            {
+                context->handleError(Error(GL_INVALID_OPERATION,
+                                           "target is TRANSFORM_FEEDBACK_BUFFER and transform "
+                                           "feedback is currently active."));
+                return false;
+            }
+            break;
+        }
+        case GL_UNIFORM_BUFFER:
+        {
+            if (index >= caps.maxUniformBufferBindings)
+            {
+                context->handleError(Error(GL_INVALID_VALUE,
+                                           "index is greater than or equal to the number of "
+                                           "UNIFORM_BUFFER indexed binding points."));
+                return false;
+            }
+
+            if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0)
+            {
+                context->handleError(
+                    Error(GL_INVALID_VALUE,
+                          "offset must be multiple of value of UNIFORM_BUFFER_OFFSET_ALIGNMENT."));
+                return false;
+            }
+            break;
+        }
+        case GL_ATOMIC_COUNTER_BUFFER:
+        {
+            if (context->getClientVersion() < ES_3_1)
+            {
+                context->handleError(
+                    Error(GL_INVALID_ENUM, "ATOMIC_COUNTER_BUFFER is not supported in GLES3."));
+                return false;
+            }
+            if (index >= caps.maxAtomicCounterBufferBindings)
+            {
+                context->handleError(Error(GL_INVALID_VALUE,
+                                           "index is greater than or equal to the number of "
+                                           "ATOMIC_COUNTER_BUFFER indexed binding points."));
+                return false;
+            }
+            if (buffer != 0 && (offset % 4) != 0)
+            {
+                context->handleError(Error(GL_INVALID_VALUE, "offset must be a multiple of 4."));
+                return false;
+            }
+            break;
+        }
+        case GL_SHADER_STORAGE_BUFFER:
+        {
+            if (context->getClientVersion() < ES_3_1)
+            {
+                context->handleError(
+                    Error(GL_INVALID_ENUM, "ATOMIC_COUNTER_BUFFER is not supported in GLES3."));
+                return false;
+            }
+            break;
+        }
+        default:
+            context->handleError(Error(GL_INVALID_ENUM, "the target is not supported."));
+            return false;
+    }
+
+    return true;
+}
+
+bool ValidateBindBufferBase(Context *context, GLenum target, GLuint index, GLuint buffer)
+{
+    return ValidateBindBufferCommon(context, target, index, buffer, 0, 0);
+}
+
+bool ValidateBindBufferRange(Context *context,
+                             GLenum target,
+                             GLuint index,
+                             GLuint buffer,
+                             GLintptr offset,
+                             GLsizeiptr size)
+{
+    if (buffer != 0 && size <= 0)
+    {
+        context->handleError(
+            Error(GL_INVALID_VALUE, "buffer is non-zero and size is less than or equal to zero."));
+        return false;
+    }
+    return ValidateBindBufferCommon(context, target, index, buffer, offset, size);
+}
+
 bool ValidateProgramBinary(Context *context,
                            GLuint program,
                            GLenum binaryFormat,
@@ -1842,6 +1978,24 @@
                 return false;
             }
             break;
+        case GL_ATOMIC_COUNTER_BUFFER_START:
+        case GL_ATOMIC_COUNTER_BUFFER_SIZE:
+        case GL_ATOMIC_COUNTER_BUFFER_BINDING:
+            if (context->getClientVersion() < ES_3_1)
+            {
+                context->handleError(
+                    Error(GL_INVALID_ENUM,
+                          "Atomic Counter buffers are not supported in this version of GL"));
+                return false;
+            }
+            if (index >= caps.maxAtomicCounterBufferBindings)
+            {
+                context->handleError(
+                    Error(GL_INVALID_VALUE,
+                          "index is outside the valid range for GL_ATOMIC_COUNTER_BUFFER_BINDING"));
+                return false;
+            }
+            break;
         default:
             context->handleError(Error(GL_INVALID_ENUM));
             return false;