Add initial support for EXT_disjoint_timer_query.

Basic timer queries are supported and tested in the OpenGL backend
but are not enabled by default. A good portion of the existing query
code was also refactored for improved validation - specifically for
validating that the appropriate extensions are available.

BUG=angleproject:1265

Change-Id: Iebae994cd7a8d3ed3e9fc3776fe2f3d99caa9237
Reviewed-on: https://chromium-review.googlesource.com/323450
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tryjob-Request: Ian Ewell <ewell@google.com>
Tested-by: Ian Ewell <ewell@google.com>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 745f342..0a14d12 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -383,6 +383,8 @@
         return true;
       case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
         return (context->getClientVersion() >= 3);
+      case GL_TIME_ELAPSED_EXT:
+          return context->getExtensions().disjointTimerQuery;
       default:
         return false;
     }
@@ -1095,17 +1097,63 @@
     return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
 }
 
-bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
+bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+    if (n < 0)
+    {
+        context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+    if (!context->getExtensions().occlusionQueryBoolean &&
+        !context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+
+    return ValidateGenQueriesBase(context, n, ids);
+}
+
+bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+    if (n < 0)
+    {
+        context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+    if (!context->getExtensions().occlusionQueryBoolean &&
+        !context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+
+    return ValidateDeleteQueriesBase(context, n, ids);
+}
+
+bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
 {
     if (!ValidQueryType(context, target))
     {
-        context->recordError(Error(GL_INVALID_ENUM));
+        context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
         return false;
     }
 
     if (id == 0)
     {
-        context->recordError(Error(GL_INVALID_OPERATION));
+        context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
         return false;
     }
 
@@ -1124,9 +1172,12 @@
     //    b) There are no active queries for the requested target (and in the case
     //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
     //       no query may be active for either if glBeginQuery targets either.
+
+    // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
+    // same time
     if (context->getState().isQueryActive())
     {
-        context->recordError(Error(GL_INVALID_OPERATION));
+        context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
         return false;
     }
 
@@ -1135,39 +1186,210 @@
     // check that name was obtained with glGenQueries
     if (!queryObject)
     {
-        context->recordError(Error(GL_INVALID_OPERATION));
+        context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
         return false;
     }
 
     // check for type mismatch
     if (queryObject->getType() != target)
     {
-        context->recordError(Error(GL_INVALID_OPERATION));
+        context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
         return false;
     }
 
     return true;
 }
 
-bool ValidateEndQuery(gl::Context *context, GLenum target)
+bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
+{
+    if (!context->getExtensions().occlusionQueryBoolean &&
+        !context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+
+    return ValidateBeginQueryBase(context, target, id);
+}
+
+bool ValidateEndQueryBase(gl::Context *context, GLenum target)
 {
     if (!ValidQueryType(context, target))
     {
-        context->recordError(Error(GL_INVALID_ENUM));
+        context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
         return false;
     }
 
     const Query *queryObject = context->getState().getActiveQuery(target);
 
-    if (queryObject == NULL)
+    if (queryObject == nullptr)
     {
-        context->recordError(Error(GL_INVALID_OPERATION));
+        context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
         return false;
     }
 
     return true;
 }
 
+bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
+{
+    if (!context->getExtensions().occlusionQueryBoolean &&
+        !context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+
+    return ValidateEndQueryBase(context, target);
+}
+
+bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
+{
+    if (!context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
+        return false;
+    }
+
+    if (target != GL_TIMESTAMP_EXT)
+    {
+        context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
+        return false;
+    }
+
+    Query *queryObject = context->getQuery(id, true, target);
+    if (queryObject == nullptr)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
+        return false;
+    }
+
+    if (context->getState().isQueryActive(queryObject))
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
+{
+    if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
+    {
+        context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
+        return false;
+    }
+
+    switch (pname)
+    {
+        case GL_CURRENT_QUERY_EXT:
+            if (target == GL_TIMESTAMP_EXT)
+            {
+                context->recordError(
+                    Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
+                return false;
+            }
+            break;
+        case GL_QUERY_COUNTER_BITS_EXT:
+            if (!context->getExtensions().disjointTimerQuery ||
+                (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
+            {
+                context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
+                return false;
+            }
+            break;
+        default:
+            context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
+            return false;
+    }
+
+    return true;
+}
+
+bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
+{
+    if (!context->getExtensions().occlusionQueryBoolean &&
+        !context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+
+    return ValidateGetQueryivBase(context, target, pname);
+}
+
+bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
+{
+    Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+    if (!queryObject)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
+        return false;
+    }
+
+    if (context->getState().isQueryActive(queryObject))
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
+        return false;
+    }
+
+    switch (pname)
+    {
+        case GL_QUERY_RESULT_EXT:
+        case GL_QUERY_RESULT_AVAILABLE_EXT:
+            break;
+
+        default:
+            context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
+            return false;
+    }
+
+    return true;
+}
+
+bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
+{
+    if (!context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+        return false;
+    }
+    return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
+{
+    if (!context->getExtensions().disjointTimerQuery &&
+        !context->getExtensions().occlusionQueryBoolean)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+        return false;
+    }
+    return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
+{
+    if (!context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+        return false;
+    }
+    return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
+{
+    if (!context->getExtensions().disjointTimerQuery)
+    {
+        context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+        return false;
+    }
+    return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
 static bool ValidateUniformCommonBase(gl::Context *context,
                                       GLenum targetUniformType,
                                       GLint location,