Re-re-land "Add GL_OES_vertex_array_object to D3D11 and GL renderers"

+ Include fixed validation logic for GL_UNPACK_SKIP_IMAGES and GL_UNPACK_ROW_LENGTH
+ Include fix for Clang build break

BUG=angleproject:1186

Change-Id: I403a066e29614f532db6931755265d2ee088d442
Reviewed-on: https://chromium-review.googlesource.com/308746
Tested-by: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index b57d30c..40511f0 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -141,6 +141,7 @@
       eglImageExternalEssl3(false),
       unpackSubimage(false),
       packSubimage(false),
+      vertexArrayObject(false),
       colorBufferFloat(false)
 {
 }
@@ -201,6 +202,7 @@
     InsertExtensionString("GL_EXT_unpack_subimage",              unpackSubimage,            &extensionStrings);
     InsertExtensionString("GL_NV_pack_subimage",                 packSubimage,              &extensionStrings);
     InsertExtensionString("GL_EXT_color_buffer_float",           colorBufferFloat,          &extensionStrings);
+    InsertExtensionString("GL_OES_vertex_array_object",          vertexArrayObject,         &extensionStrings);
     // clang-format on
 
     return extensionStrings;
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 1ed6783..8162dd0 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -239,6 +239,9 @@
     // NV_pack_subimage
     bool packSubimage;
 
+    // GL_OES_vertex_array_object
+    bool vertexArrayObject;
+
     // ES3 Extension support
 
     // GL_EXT_color_buffer_float
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index cef4037..5d7b22c 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1107,26 +1107,6 @@
             }
         }
         return true;
-        case GL_PACK_ROW_LENGTH:
-        case GL_PACK_SKIP_ROWS:
-        case GL_PACK_SKIP_PIXELS:
-            if ((mClientVersion < 3) && !mExtensions.packSubimage)
-            {
-                return false;
-            }
-            *type      = GL_INT;
-            *numParams = 1;
-            return true;
-        case GL_UNPACK_ROW_LENGTH:
-        case GL_UNPACK_SKIP_ROWS:
-        case GL_UNPACK_SKIP_PIXELS:
-            if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
-            {
-                return false;
-            }
-            *type      = GL_INT;
-            *numParams = 1;
-            return true;
       case GL_MAX_VIEWPORT_DIMS:
         {
             *type = GL_INT;
@@ -1199,6 +1179,39 @@
         return true;
     }
 
+    // Check for ES3.0+ parameter names which are also exposed as ES2 extensions
+    switch (pname)
+    {
+        case GL_PACK_ROW_LENGTH:
+        case GL_PACK_SKIP_ROWS:
+        case GL_PACK_SKIP_PIXELS:
+            if ((mClientVersion < 3) && !mExtensions.packSubimage)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+        case GL_UNPACK_ROW_LENGTH:
+        case GL_UNPACK_SKIP_ROWS:
+        case GL_UNPACK_SKIP_PIXELS:
+            if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+        case GL_VERTEX_ARRAY_BINDING:
+            if ((mClientVersion < 3) && !mExtensions.vertexArrayObject)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+    }
+
     if (mClientVersion < 3)
     {
         return false;
@@ -1224,7 +1237,6 @@
       case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
       case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
       case GL_MAX_VARYING_COMPONENTS:
-      case GL_VERTEX_ARRAY_BINDING:
       case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
       case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
       case GL_MIN_PROGRAM_TEXEL_OFFSET:
@@ -1237,14 +1249,8 @@
       case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
-      case GL_PACK_ROW_LENGTH:
-      case GL_PACK_SKIP_ROWS:
-      case GL_PACK_SKIP_PIXELS:
-      case GL_UNPACK_ROW_LENGTH:
       case GL_UNPACK_IMAGE_HEIGHT:
       case GL_UNPACK_SKIP_IMAGES:
-      case GL_UNPACK_SKIP_ROWS:
-      case GL_UNPACK_SKIP_PIXELS:
         {
             *type = GL_INT;
             *numParams = 1;
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index 72462e9..76e541c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -1215,6 +1215,7 @@
     extensions->eglImage                 = true;
     extensions->unpackSubimage           = true;
     extensions->packSubimage             = true;
+    extensions->vertexArrayObject        = true;
 
     // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
     // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.
diff --git a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
index ed9c146..b931035 100644
--- a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -576,6 +576,7 @@
     extensions->eglImage               = true;
     extensions->unpackSubimage         = true;
     extensions->packSubimage           = true;
+    extensions->vertexArrayObject      = true;
 
     // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
     // state.
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index a47a7cd..3988a0c 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -578,6 +578,9 @@
     extensions->debugMarker =
         functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_KHR_debug") ||
         functions->isAtLeastGLES(gl::Version(3, 2)) || functions->hasGLESExtension("GL_KHR_debug");
+
+    // ANGLE emulates vertex array objects in its GL layer
+    extensions->vertexArrayObject = true;
 }
 
 void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds)
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 8a59c06..fc90330 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2173,4 +2173,41 @@
 
     return true;
 }
+
+bool ValidateBindVertexArrayBase(Context *context, GLuint array)
+{
+    VertexArray *vao = context->getVertexArray(array);
+
+    if (!vao)
+    {
+        // The default VAO should always exist
+        ASSERT(array != 0);
+        context->recordError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
+{
+    if (n < 0)
+    {
+        context->recordError(Error(GL_INVALID_VALUE));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
+{
+    if (n < 0)
+    {
+        context->recordError(Error(GL_INVALID_VALUE));
+        return false;
+    }
+
+    return true;
+}
 }
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index afd1c0c..9439a7a 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -141,6 +141,10 @@
                                                   egl::Display *display,
                                                   GLenum target,
                                                   egl::Image *image);
+
+bool ValidateBindVertexArrayBase(Context *context, GLuint array);
+bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n);
+bool ValidateGenVertexArraysBase(Context *context, GLsizei n);
 }
 
 #endif // LIBANGLE_VALIDATION_ES_H_
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index d9a69d1..dc05584 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -993,4 +993,48 @@
 
     return true;
 }
+
+bool ValidateBindVertexArrayOES(Context *context, GLuint array)
+{
+    if (!context->getExtensions().vertexArrayObject)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+        return false;
+    }
+
+    return ValidateBindVertexArrayBase(context, array);
+}
+
+bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n)
+{
+    if (!context->getExtensions().vertexArrayObject)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+        return false;
+    }
+
+    return ValidateDeleteVertexArraysBase(context, n);
+}
+
+bool ValidateGenVertexArraysOES(Context *context, GLsizei n)
+{
+    if (!context->getExtensions().vertexArrayObject)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+        return false;
+    }
+
+    return ValidateGenVertexArraysBase(context, n);
+}
+
+bool ValidateIsVertexArrayOES(Context *context)
+{
+    if (!context->getExtensions().vertexArrayObject)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+        return false;
+    }
+
+    return true;
+}
 }
diff --git a/src/libANGLE/validationES2.h b/src/libANGLE/validationES2.h
index 4a858d9..44166af 100644
--- a/src/libANGLE/validationES2.h
+++ b/src/libANGLE/validationES2.h
@@ -33,6 +33,11 @@
                                    const GLenum *attachments);
 
 bool ValidateDrawBuffers(Context *context, GLsizei n, const GLenum *bufs);
+
+bool ValidateBindVertexArrayOES(Context *context, GLuint array);
+bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n);
+bool ValidateGenVertexArraysOES(Context *context, GLsizei n);
+bool ValidateIsVertexArrayOES(Context *context);
 }
 
 #endif // LIBANGLE_VALIDATION_ES2_H_
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index b13ee9c..245a4af 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -1299,4 +1299,48 @@
 
     return true;
 }
+
+bool ValidateBindVertexArray(Context *context, GLuint array)
+{
+    if (context->getClientVersion() < 3)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return ValidateBindVertexArrayBase(context, array);
+}
+
+bool ValidateDeleteVertexArrays(Context *context, GLsizei n)
+{
+    if (context->getClientVersion() < 3)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return ValidateDeleteVertexArraysBase(context, n);
+}
+
+bool ValidateGenVertexArrays(Context *context, GLsizei n)
+{
+    if (context->getClientVersion() < 3)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return ValidateGenVertexArraysBase(context, n);
+}
+
+bool ValidateIsVertexArray(Context *context)
+{
+    if (context->getClientVersion() < 3)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return true;
+}
 }
diff --git a/src/libANGLE/validationES3.h b/src/libANGLE/validationES3.h
index 60f321e..c1d7b74 100644
--- a/src/libANGLE/validationES3.h
+++ b/src/libANGLE/validationES3.h
@@ -54,6 +54,11 @@
                                   GLint border,
                                   GLsizei imageSize,
                                   const GLvoid *data);
+
+bool ValidateBindVertexArray(Context *context, GLuint array);
+bool ValidateDeleteVertexArrays(Context *context, GLsizei n);
+bool ValidateGenVertexArrays(Context *context, GLsizei n);
+bool ValidateIsVertexArray(Context *context);
 }
 
 #endif // LIBANGLE_VALIDATION_ES3_H_
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
index 1b2397c..0b72ff1 100644
--- a/src/libGLESv2/entry_points_egl.cpp
+++ b/src/libGLESv2/entry_points_egl.cpp
@@ -1341,6 +1341,12 @@
         INSERT_PROC_ADDRESS(gl, EGLImageTargetTexture2DOES);
         INSERT_PROC_ADDRESS(gl, EGLImageTargetRenderbufferStorageOES);
 
+        // GL_OES_vertex_array_object
+        INSERT_PROC_ADDRESS(gl, BindVertexArrayOES);
+        INSERT_PROC_ADDRESS(gl, DeleteVertexArraysOES);
+        INSERT_PROC_ADDRESS(gl, GenVertexArraysOES);
+        INSERT_PROC_ADDRESS(gl, IsVertexArrayOES);
+
         // GLES3 core
         INSERT_PROC_ADDRESS(gl, ReadBuffer);
         INSERT_PROC_ADDRESS(gl, DrawRangeElements);
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index bdd8b67..296f90d 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -1202,4 +1202,86 @@
         }
     }
 }
+
+void GL_APIENTRY BindVertexArrayOES(GLuint array)
+{
+    EVENT("(GLuint array = %u)", array);
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        if (!ValidateBindVertexArrayOES(context, array))
+        {
+            return;
+        }
+
+        context->bindVertexArray(array);
+    }
+}
+
+void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
+{
+    EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays);
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        if (!ValidateDeleteVertexArraysOES(context, n))
+        {
+            return;
+        }
+
+        for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+        {
+            if (arrays[arrayIndex] != 0)
+            {
+                context->deleteVertexArray(arrays[arrayIndex]);
+            }
+        }
+    }
+}
+
+void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays)
+{
+    EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays);
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        if (!ValidateGenVertexArraysOES(context, n))
+        {
+            return;
+        }
+
+        for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+        {
+            arrays[arrayIndex] = context->createVertexArray();
+        }
+    }
+}
+
+GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array)
+{
+    EVENT("(GLuint array = %u)", array);
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        if (!ValidateIsVertexArrayOES(context))
+        {
+            return GL_FALSE;
+        }
+
+        if (array == 0)
+        {
+            return GL_FALSE;
+        }
+
+        VertexArray *vao = context->getVertexArray(array);
+
+        return (vao != nullptr ? GL_TRUE : GL_FALSE);
+    }
+
+    return GL_FALSE;
+}
 }
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.h b/src/libGLESv2/entry_points_gles_2_0_ext.h
index 08d576b..486df6a 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.h
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.h
@@ -85,6 +85,12 @@
 ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
 ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target,
                                                                    GLeglImageOES image);
+
+// GL_OES_vertex_array_object
+ANGLE_EXPORT void GL_APIENTRY BindVertexArrayOES(GLuint array);
+ANGLE_EXPORT void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arrays);
+ANGLE_EXPORT void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays);
+ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array);
 }
 
 #endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_
diff --git a/src/libGLESv2/entry_points_gles_3_0.cpp b/src/libGLESv2/entry_points_gles_3_0.cpp
index b850109..2c19eb6 100644
--- a/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -806,19 +806,8 @@
     Context *context = GetValidGlobalContext();
     if (context)
     {
-        if (context->getClientVersion() < 3)
+        if (!ValidateBindVertexArray(context, array))
         {
-            context->recordError(Error(GL_INVALID_OPERATION));
-            return;
-        }
-
-        VertexArray *vao = context->getVertexArray(array);
-
-        if (!vao)
-        {
-            // The default VAO should always exist
-            ASSERT(array != 0);
-            context->recordError(Error(GL_INVALID_OPERATION));
             return;
         }
 
@@ -833,15 +822,8 @@
     Context *context = GetValidGlobalContext();
     if (context)
     {
-        if (context->getClientVersion() < 3)
+        if (!ValidateDeleteVertexArrays(context, n))
         {
-            context->recordError(Error(GL_INVALID_OPERATION));
-            return;
-        }
-
-        if (n < 0)
-        {
-            context->recordError(Error(GL_INVALID_VALUE));
             return;
         }
 
@@ -862,15 +844,8 @@
     Context *context = GetValidGlobalContext();
     if (context)
     {
-        if (context->getClientVersion() < 3)
+        if (!ValidateGenVertexArrays(context, n))
         {
-            context->recordError(Error(GL_INVALID_OPERATION));
-            return;
-        }
-
-        if (n < 0)
-        {
-            context->recordError(Error(GL_INVALID_VALUE));
             return;
         }
 
@@ -888,9 +863,8 @@
     Context *context = GetValidGlobalContext();
     if (context)
     {
-        if (context->getClientVersion() < 3)
+        if (!ValidateIsVertexArray(context))
         {
-            context->recordError(Error(GL_INVALID_OPERATION));
             return GL_FALSE;
         }
 
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 0d5dfd5..71eb25d 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -1439,4 +1439,24 @@
 {
     return gl::EGLImageTargetRenderbufferStorageOES(target, image);
 }
+
+void GL_APIENTRY glBindVertexArrayOES(GLuint array)
+{
+    return gl::BindVertexArrayOES(array);
+}
+
+void GL_APIENTRY glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
+{
+    return gl::DeleteVertexArraysOES(n, arrays);
+}
+
+void GL_APIENTRY glGenVertexArraysOES(GLsizei n, GLuint *arrays)
+{
+    return gl::GenVertexArraysOES(n, arrays);
+}
+
+GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array)
+{
+    return gl::IsVertexArrayOES(array);
+}
 }
diff --git a/src/libGLESv2/libGLESv2.def b/src/libGLESv2/libGLESv2.def
index e58826b..af41a67 100644
--- a/src/libGLESv2/libGLESv2.def
+++ b/src/libGLESv2/libGLESv2.def
@@ -183,6 +183,10 @@
     glPopGroupMarkerEXT             @296
     glEGLImageTargetTexture2DOES    @297
     glEGLImageTargetRenderbufferStorageOES @298
+    glBindVertexArrayOES            @299
+    glDeleteVertexArraysOES         @300
+    glGenVertexArraysOES            @301
+    glIsVertexArrayOES              @302
 
     ; GLES 3.0 Functions
     glReadBuffer                    @180