Adding checks in DrawBuffers to return INVALID_ENUM

When a enum is given that is not a BACK, NONE, or COLOR_ATTACHMENTi where
i ranges from 0 to MAX_COLOR_ATTACHMENT, an INVALID_ENUM should be
returned rather than an INVALID_OPERATION.

BUG=angleproject:1148

Change-Id: I3663f897face14f6ba46a15fb982efda6f4f4b05
Reviewed-on: https://chromium-review.googlesource.com/299312
Tryjob-Request: Dian Xiang <dianx@google.com>
Tested-by: Dian Xiang <dianx@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index de36dbc..377c350 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -897,4 +897,68 @@
     return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
 }
 
+bool ValidateDrawBuffers(Context *context, GLsizei n, const GLenum *bufs)
+{
+    // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
+    if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
+    {
+        context->recordError(
+            Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
+        return false;
+    }
+
+    ASSERT(context->getState().getDrawFramebuffer());
+    GLuint frameBufferId      = context->getState().getDrawFramebuffer()->id();
+    GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
+
+    // This should come first before the check for the default frame buffer
+    // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
+    // rather than INVALID_OPERATION
+    for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
+    {
+        const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
+
+        if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
+            (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
+             bufs[colorAttachment] >= maxColorAttachment))
+        {
+            // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
+            // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
+            // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
+            context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
+            return false;
+        }
+        else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
+                 frameBufferId != 0)
+        {
+            // INVALID_OPERATION-GL is bound to buffer and ith argument
+            // is not COLOR_ATTACHMENTi or NONE
+            context->recordError(
+                Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
+            return false;
+        }
+    }
+
+    // INVALID_OPERATION is generated if GL is bound to the default framebuffer
+    // and n is not 1 or bufs is bound to value other than BACK and NONE
+    if (frameBufferId == 0)
+    {
+        if (n != 1)
+        {
+            context->recordError(Error(GL_INVALID_OPERATION,
+                                       "n must be 1 when GL is bound to the default framebuffer"));
+            return false;
+        }
+
+        if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
+        {
+            context->recordError(Error(
+                GL_INVALID_OPERATION,
+                "Only NONE or BACK are valid values when drawing to the default framebuffer"));
+            return false;
+        }
+    }
+
+    return true;
+}
 }