Move state query validation out of Context.

Generate all GL errors in the validation helper functions, instead of
within the state manipulation logic and internals of Context.

BUG=angle:571

Change-Id: I7a3f540e2ae0f5f8c7126e2593717cc3200dd7e5
Reviewed-on: https://chromium-review.googlesource.com/200551
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/validationES.cpp b/src/libGLESv2/validationES.cpp
index 0fe7d22..a6ae90a 100644
--- a/src/libGLESv2/validationES.cpp
+++ b/src/libGLESv2/validationES.cpp
@@ -829,6 +829,7 @@
                                   GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
 {
     gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+    ASSERT(framebuffer);
 
     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
@@ -840,16 +841,15 @@
         return gl::error(GL_INVALID_OPERATION, false);
     }
 
+    if (!framebuffer->getReadColorbuffer())
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
     GLenum currentInternalFormat, currentFormat, currentType;
     int clientVersion = context->getClientVersion();
 
-    // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
-    // and attempting to read back if that's the case is an error. The error will be registered
-    // by getCurrentReadFormat.
-    // Note: we need to explicitly check for framebuffer completeness here, before we call
-    // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
-    if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
-        return false;
+    context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
 
     bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
                                                  ValidES3ReadFormatType(context, currentInternalFormat, format, type);
@@ -1038,4 +1038,64 @@
     return true;
 }
 
+bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
+{
+    if (!context->getQueryParameterInfo(pname, nativeType, numParams))
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
+    {
+        unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
+
+        if (colorAttachment >= context->getMaximumRenderTargets())
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+    }
+
+    switch (pname)
+    {
+      case GL_TEXTURE_BINDING_2D:
+      case GL_TEXTURE_BINDING_CUBE_MAP:
+      case GL_TEXTURE_BINDING_3D:
+      case GL_TEXTURE_BINDING_2D_ARRAY:
+        if (context->getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+        break;
+
+      case GL_IMPLEMENTATION_COLOR_READ_TYPE:
+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+        {
+            Framebuffer *framebuffer = context->getReadFramebuffer();
+            ASSERT(framebuffer);
+            if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+            {
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+
+            Renderbuffer *renderbuffer = framebuffer->getReadColorbuffer();
+            if (!renderbuffer)
+            {
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+        }
+        break;
+
+      default:
+        break;
+    }
+
+    // pname is valid, but there are no parameters to return
+    if (numParams == 0)
+    {
+        return false;
+    }
+
+    return true;
+}
+
 }