Implement the WebGL VertexAttribPointer restrictions

BUG=angleproject:1523
BUG=chromium:668223

Change-Id: Ic89c476a6c95824069772e22ede596ba85ac8859
Reviewed-on: https://chromium-review.googlesource.com/422347
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index f60959a..4deb90a 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -23,6 +23,7 @@
 #include "libANGLE/formatutils.h"
 #include "libANGLE/validationES.h"
 #include "libANGLE/validationES3.h"
+#include "libANGLE/VertexArray.h"
 
 namespace gl
 {
@@ -3881,4 +3882,126 @@
     return true;
 }
 
+bool ValidateVertexAttribPointer(ValidationContext *context,
+                                 GLuint index,
+                                 GLint size,
+                                 GLenum type,
+                                 GLboolean normalized,
+                                 GLsizei stride,
+                                 const GLvoid *ptr)
+{
+    if (index >= MAX_VERTEX_ATTRIBS)
+    {
+        context->handleError(Error(GL_INVALID_VALUE, "Invalid index value."));
+        return false;
+    }
+
+    if (size < 1 || size > 4)
+    {
+        context->handleError(Error(GL_INVALID_VALUE, "Invalide size value."));
+        return false;
+    }
+
+    switch (type)
+    {
+        case GL_BYTE:
+        case GL_UNSIGNED_BYTE:
+        case GL_SHORT:
+        case GL_UNSIGNED_SHORT:
+        case GL_FIXED:
+        case GL_FLOAT:
+            break;
+
+        case GL_HALF_FLOAT:
+        case GL_INT:
+        case GL_UNSIGNED_INT:
+        case GL_INT_2_10_10_10_REV:
+        case GL_UNSIGNED_INT_2_10_10_10_REV:
+            if (context->getClientMajorVersion() < 3)
+            {
+                context->handleError(
+                    Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
+                return false;
+            }
+            break;
+
+        default:
+            context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
+            return false;
+    }
+
+    if (stride < 0)
+    {
+        context->handleError(Error(GL_INVALID_VALUE, "Invalid stride."));
+        return false;
+    }
+
+    if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION, "Invalid size for a sized vertex type."));
+        return false;
+    }
+
+    // [OpenGL ES 3.0.2] Section 2.8 page 24:
+    // An INVALID_OPERATION error is generated when a non-zero vertex array object
+    // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point,
+    // and the pointer argument is not NULL.
+    if (context->getGLState().getVertexArray()->id() != 0 &&
+        context->getGLState().getArrayBufferId() == 0 && ptr != NULL)
+    {
+        context->handleError(
+            Error(GL_INVALID_OPERATION,
+                  "Pointer is null with a non-zero VAO bound and zero bound to GL_ARRAY_BUFFER."));
+        return false;
+    }
+
+    if (context->getExtensions().webglCompatibility)
+    {
+        // WebGL 1.0 [Section 6.14] Fixed point support
+        // The WebGL API does not support the GL_FIXED data type.
+        if (type == GL_FIXED)
+        {
+            context->handleError(Error(GL_INVALID_ENUM, "GL_FIXED is not supported in WebGL."));
+            return false;
+        }
+
+        // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
+        // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
+        // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
+        // parameter exceeds 255.
+        constexpr GLsizei kMaxWebGLStride = 255;
+        if (stride > kMaxWebGLStride)
+        {
+            context->handleError(
+                Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
+            return false;
+        }
+
+        // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
+        // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
+        // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
+        // or an INVALID_OPERATION error is generated.
+        VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, false);
+        size_t typeSize = GetVertexFormatTypeSize(internalType);
+
+        ASSERT(isPow2(typeSize) && typeSize > 0);
+        size_t sizeMask = (typeSize - 1);
+        if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
+        {
+            context->handleError(
+                Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
+            return false;
+        }
+
+        if ((stride & sizeMask) != 0)
+        {
+            context->handleError(
+                Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
+            return false;
+        }
+    }
+
+    return true;
+}
+
 }  // namespace gl