ES31: Support adjacency draw modes for geometry shader

This patch implements adjacency primitive types as new draw modes
on OpenGL back-ends.

This patch also implements validations on the compatibilities among
draw modes and geometry shader input primitive types.

BUG=angleproject:1941
TEST=dEQP-GLES31.functional.geometry_shading.input.*
     dEQP-GLES31.functional.geometry_shading.negative.*

Change-Id: I373ebfe88d7f50da3cc81adaf2d1b7f586b0932a
Reviewed-on: https://chromium-review.googlesource.com/954715
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 6ce0f21..43ca249 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -497,6 +497,30 @@
     return true;
 }
 
+bool IsCompatibleDrawModeWithGeometryShader(GLenum drawMode,
+                                            GLenum geometryShaderInputPrimitiveType)
+{
+    // [EXT_geometry_shader] Section 11.1gs.1, Geometry Shader Input Primitives
+    switch (geometryShaderInputPrimitiveType)
+    {
+        case GL_POINTS:
+            return drawMode == GL_POINTS;
+        case GL_LINES:
+            return drawMode == GL_LINES || drawMode == GL_LINE_STRIP || drawMode == GL_LINE_LOOP;
+        case GL_LINES_ADJACENCY_EXT:
+            return drawMode == GL_LINES_ADJACENCY_EXT || drawMode == GL_LINE_STRIP_ADJACENCY_EXT;
+        case GL_TRIANGLES:
+            return drawMode == GL_TRIANGLES || drawMode == GL_TRIANGLE_FAN ||
+                   drawMode == GL_TRIANGLE_STRIP;
+        case GL_TRIANGLES_ADJACENCY_EXT:
+            return drawMode == GL_TRIANGLES_ADJACENCY_EXT ||
+                   drawMode == GL_TRIANGLE_STRIP_ADJACENCY_EXT;
+        default:
+            UNREACHABLE();
+            return false;
+    }
+}
+
 }  // anonymous namespace
 
 bool IsETC2EACFormat(const GLenum format)
@@ -2434,6 +2458,8 @@
 
 bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count)
 {
+    const Extensions &extensions = context->getExtensions();
+
     switch (mode)
     {
         case GL_POINTS:
@@ -2444,6 +2470,17 @@
         case GL_TRIANGLE_STRIP:
         case GL_TRIANGLE_FAN:
             break;
+
+        case GL_LINES_ADJACENCY_EXT:
+        case GL_LINE_STRIP_ADJACENCY_EXT:
+        case GL_TRIANGLES_ADJACENCY_EXT:
+        case GL_TRIANGLE_STRIP_ADJACENCY_EXT:
+            if (!extensions.geometryShader)
+            {
+                ANGLE_VALIDATION_ERR(context, InvalidEnum(), GeometryShaderExtensionNotEnabled);
+                return false;
+            }
+            break;
         default:
             ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDrawMode);
             return false;
@@ -2457,8 +2494,6 @@
 
     const State &state = context->getGLState();
 
-    const Extensions &extensions = context->getExtensions();
-
     // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange,
     // and UnmapBuffer entry points are removed from the WebGL 2.0 API.
     // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
@@ -2565,6 +2600,18 @@
         }
     }
 
+    // Do geometry shader specific validations
+    if (program->hasLinkedGeometryShader())
+    {
+        if (!IsCompatibleDrawModeWithGeometryShader(mode,
+                                                    program->getGeometryShaderInputPrimitiveType()))
+        {
+            ANGLE_VALIDATION_ERR(context, InvalidOperation(),
+                                 IncompatibleDrawModeAgainstGeometryShader);
+            return false;
+        }
+    }
+
     // Uniform buffer validation
     for (unsigned int uniformBlockIndex = 0;
          uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)