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/Context.cpp b/src/libANGLE/Context.cpp
index b978ab2..58f39a6 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -36,6 +36,32 @@
 namespace
 {
 
+template <typename T>
+gl::Error GetQueryObjectParameter(gl::Context *context, GLuint id, GLenum pname, T *params)
+{
+    gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+    ASSERT(queryObject != nullptr);
+
+    switch (pname)
+    {
+        case GL_QUERY_RESULT_EXT:
+            return queryObject->getResult(params);
+        case GL_QUERY_RESULT_AVAILABLE_EXT:
+        {
+            bool available;
+            gl::Error error = queryObject->isResultAvailable(&available);
+            if (!error.isError())
+            {
+                *params = static_cast<T>(available ? GL_TRUE : GL_FALSE);
+            }
+            return error;
+        }
+        default:
+            UNREACHABLE();
+            return gl::Error(GL_INVALID_OPERATION, "Unreachable Error");
+    }
+}
+
 void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback)
 {
     if (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
@@ -801,6 +827,64 @@
     return error;
 }
 
+Error Context::queryCounter(GLuint id, GLenum target)
+{
+    ASSERT(target == GL_TIMESTAMP_EXT);
+
+    Query *queryObject = getQuery(id, true, target);
+    ASSERT(queryObject);
+
+    return queryObject->queryCounter();
+}
+
+void Context::getQueryiv(GLenum target, GLenum pname, GLint *params)
+{
+    switch (pname)
+    {
+        case GL_CURRENT_QUERY_EXT:
+            params[0] = getState().getActiveQueryId(target);
+            break;
+        case GL_QUERY_COUNTER_BITS_EXT:
+            switch (target)
+            {
+                case GL_TIME_ELAPSED_EXT:
+                    params[0] = getExtensions().queryCounterBitsTimeElapsed;
+                    break;
+                case GL_TIMESTAMP_EXT:
+                    params[0] = getExtensions().queryCounterBitsTimestamp;
+                    break;
+                default:
+                    UNREACHABLE();
+                    params[0] = 0;
+                    break;
+            }
+            break;
+        default:
+            UNREACHABLE();
+            return;
+    }
+}
+
+Error Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params)
+{
+    return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Error Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
+{
+    return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Error Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params)
+{
+    return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Error Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params)
+{
+    return GetQueryObjectParameter(this, id, pname, params);
+}
+
 Framebuffer *Context::getFramebuffer(unsigned int handle) const
 {
     FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle);