GLES1: Renderer (minimal)

This is the renderer code for GLES1 that delivers basic vertex
attributes, matrices, and allows texturing for unit 0 only (more units
mean implementing the multitexturing pipeline).

+ Sample
+ Update test expectations for GLES1 conformance tests

BUG=angleproject:2554
BUG=angleproject:2306

Change-Id: I398edc764f982fbfc4c5e0f9d6bfef1e91aec47c
Reviewed-on: https://chromium-review.googlesource.com/1057356
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Lingfeng Yang <lfy@google.com>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index cbf4ef2..f8d213b 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -117,7 +117,10 @@
     const auto &vertexAttribs  = vao->getVertexAttributes();
     const auto &vertexBindings = vao->getVertexBindings();
 
-    const AttributesMask &activeAttribs = (program->getActiveAttribLocationsMask() &
+    bool isGLES1 = context->getClientVersion() < Version(2, 0);
+
+    const AttributesMask &activeAttribs = ((isGLES1 ? context->getVertexArraysAttributeMask()
+                                                    : program->getActiveAttribLocationsMask()) &
                                            vao->getEnabledAttributesMask() & ~clientAttribs);
 
     for (size_t attributeIndex : activeAttribs)
@@ -126,7 +129,7 @@
         ASSERT(attrib.enabled);
 
         const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
-        ASSERT(program->isAttribLocationActive(attributeIndex));
+        ASSERT(isGLES1 || program->isAttribLocationActive(attributeIndex));
 
         GLint maxVertexElement = maxVertex;
         GLuint divisor         = binding.getDivisor();
@@ -2675,140 +2678,150 @@
         return false;
     }
 
-    gl::Program *program = state.getProgram();
-    if (!program)
+    // If we are running GLES1, there is no current program.
+    if (context->getClientVersion() >= Version(2, 0))
     {
-        ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound);
-        return false;
-    }
 
-    // In OpenGL ES spec for UseProgram at section 7.3, trying to render without
-    // vertex shader stage or fragment shader stage is a undefined behaviour.
-    // But ANGLE should clearly generate an INVALID_OPERATION error instead of
-    // produce undefined result.
-    if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
-        !program->hasLinkedShaderStage(ShaderType::Fragment))
-    {
-        context->handleError(InvalidOperation() << "It is a undefined behaviour to render without "
-                                                   "vertex shader stage or fragment shader stage.");
-        return false;
-    }
-
-    if (!program->validateSamplers(nullptr, context->getCaps()))
-    {
-        context->handleError(InvalidOperation());
-        return false;
-    }
-
-    if (extensions.multiview)
-    {
-        const int programNumViews     = program->usesMultiview() ? program->getNumViews() : 1;
-        const int framebufferNumViews = framebuffer->getNumViews();
-        if (framebufferNumViews != programNumViews)
+        gl::Program *program = state.getProgram();
+        if (!program)
         {
-            context->handleError(InvalidOperation() << "The number of views in the active program "
-                                                       "and draw framebuffer does not match.");
+            ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound);
             return false;
         }
 
-        const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
-        if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
-            framebufferNumViews > 1)
+        // In OpenGL ES spec for UseProgram at section 7.3, trying to render without
+        // vertex shader stage or fragment shader stage is a undefined behaviour.
+        // But ANGLE should clearly generate an INVALID_OPERATION error instead of
+        // produce undefined result.
+        if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
+            !program->hasLinkedShaderStage(ShaderType::Fragment))
         {
             context->handleError(InvalidOperation()
-                                 << "There is an active transform feedback object "
-                                    "when the number of views in the active draw "
-                                    "framebuffer is greater than 1.");
+                                 << "It is a undefined behaviour to render without "
+                                    "vertex shader stage or fragment shader stage.");
             return false;
         }
 
-        if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
-            state.isQueryActive(QueryType::TimeElapsed))
+        if (!program->validateSamplers(nullptr, context->getCaps()))
         {
-            context->handleError(InvalidOperation() << "There is an active query for target "
-                                                       "GL_TIME_ELAPSED_EXT when the number of "
-                                                       "views in the active draw framebuffer is "
-                                                       "greater than 1.");
-            return false;
-        }
-    }
-
-    // Do geometry shader specific validations
-    if (program->hasLinkedShaderStage(ShaderType::Geometry))
-    {
-        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++)
-    {
-        const gl::InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
-        GLuint blockBinding                    = program->getUniformBlockBinding(uniformBlockIndex);
-        const OffsetBindingPointer<Buffer> &uniformBuffer =
-            state.getIndexedUniformBuffer(blockBinding);
-
-        if (uniformBuffer.get() == nullptr)
-        {
-            // undefined behaviour
-            context->handleError(
-                InvalidOperation()
-                << "It is undefined behaviour to have a used but unbound uniform buffer.");
+            context->handleError(InvalidOperation());
             return false;
         }
 
-        size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
-        if (uniformBufferSize < uniformBlock.dataSize)
+        if (extensions.multiview)
         {
-            // undefined behaviour
-            context->handleError(
-                InvalidOperation()
-                << "It is undefined behaviour to use a uniform buffer that is too small.");
-            return false;
+            const int programNumViews     = program->usesMultiview() ? program->getNumViews() : 1;
+            const int framebufferNumViews = framebuffer->getNumViews();
+            if (framebufferNumViews != programNumViews)
+            {
+                context->handleError(InvalidOperation()
+                                     << "The number of views in the active program "
+                                        "and draw framebuffer does not match.");
+                return false;
+            }
+
+            const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
+            if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
+                framebufferNumViews > 1)
+            {
+                context->handleError(InvalidOperation()
+                                     << "There is an active transform feedback object "
+                                        "when the number of views in the active draw "
+                                        "framebuffer is greater than 1.");
+                return false;
+            }
+
+            if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
+                state.isQueryActive(QueryType::TimeElapsed))
+            {
+                context->handleError(InvalidOperation()
+                                     << "There is an active query for target "
+                                        "GL_TIME_ELAPSED_EXT when the number of "
+                                        "views in the active draw framebuffer is "
+                                        "greater than 1.");
+                return false;
+            }
         }
 
-        if (extensions.webglCompatibility &&
-            uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
+        // Do geometry shader specific validations
+        if (program->hasLinkedShaderStage(ShaderType::Geometry))
         {
-            ANGLE_VALIDATION_ERR(context, InvalidOperation(),
-                                 UniformBufferBoundForTransformFeedback);
-            return false;
-        }
-    }
-
-    // Do some additonal WebGL-specific validation
-    if (extensions.webglCompatibility)
-    {
-        const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
-        if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
-            transformFeedbackObject->buffersBoundForOtherUse())
-        {
-            ANGLE_VALIDATION_ERR(context, InvalidOperation(), TransformFeedbackBufferDoubleBound);
-            return false;
-        }
-        // Detect rendering feedback loops for WebGL.
-        if (framebuffer->formsRenderingFeedbackLoopWith(state))
-        {
-            ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop);
-            return false;
+            if (!IsCompatibleDrawModeWithGeometryShader(
+                    mode, program->getGeometryShaderInputPrimitiveType()))
+            {
+                ANGLE_VALIDATION_ERR(context, InvalidOperation(),
+                                     IncompatibleDrawModeAgainstGeometryShader);
+                return false;
+            }
         }
 
-        // Detect that the vertex shader input types match the attribute types
-        if (!ValidateVertexShaderAttributeTypeMatch(context))
+        // Uniform buffer validation
+        for (unsigned int uniformBlockIndex = 0;
+             uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
         {
-            return false;
+            const gl::InterfaceBlock &uniformBlock =
+                program->getUniformBlockByIndex(uniformBlockIndex);
+            GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
+            const OffsetBindingPointer<Buffer> &uniformBuffer =
+                state.getIndexedUniformBuffer(blockBinding);
+
+            if (uniformBuffer.get() == nullptr)
+            {
+                // undefined behaviour
+                context->handleError(
+                    InvalidOperation()
+                    << "It is undefined behaviour to have a used but unbound uniform buffer.");
+                return false;
+            }
+
+            size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
+            if (uniformBufferSize < uniformBlock.dataSize)
+            {
+                // undefined behaviour
+                context->handleError(
+                    InvalidOperation()
+                    << "It is undefined behaviour to use a uniform buffer that is too small.");
+                return false;
+            }
+
+            if (extensions.webglCompatibility &&
+                uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
+            {
+                ANGLE_VALIDATION_ERR(context, InvalidOperation(),
+                                     UniformBufferBoundForTransformFeedback);
+                return false;
+            }
         }
 
-        // Detect that the color buffer types match the fragment shader output types
-        if (!ValidateFragmentShaderColorBufferTypeMatch(context))
+        // Do some additonal WebGL-specific validation
+        if (extensions.webglCompatibility)
         {
-            return false;
+            const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
+            if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
+                transformFeedbackObject->buffersBoundForOtherUse())
+            {
+                ANGLE_VALIDATION_ERR(context, InvalidOperation(),
+                                     TransformFeedbackBufferDoubleBound);
+                return false;
+            }
+            // Detect rendering feedback loops for WebGL.
+            if (framebuffer->formsRenderingFeedbackLoopWith(state))
+            {
+                ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop);
+                return false;
+            }
+
+            // Detect that the vertex shader input types match the attribute types
+            if (!ValidateVertexShaderAttributeTypeMatch(context))
+            {
+                return false;
+            }
+
+            // Detect that the color buffer types match the fragment shader output types
+            if (!ValidateFragmentShaderColorBufferTypeMatch(context))
+            {
+                return false;
+            }
         }
     }