Commit 3ffd78bc by Ian Ewell

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/323450Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tryjob-Request: Ian Ewell <ewell@google.com> Tested-by: 's avatarIan Ewell <ewell@google.com>
parent 89853e84
......@@ -124,6 +124,9 @@ Extensions::Extensions()
occlusionQueryBoolean(false),
fence(false),
timerQuery(false),
disjointTimerQuery(false),
queryCounterBitsTimeElapsed(0),
queryCounterBitsTimestamp(0),
robustness(false),
blendMinMax(false),
framebufferBlit(false),
......@@ -194,6 +197,7 @@ std::vector<std::string> Extensions::getStrings() const
InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings);
InsertExtensionString("GL_NV_fence", fence, &extensionStrings);
InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings);
InsertExtensionString("GL_EXT_disjoint_timer_query", disjointTimerQuery, &extensionStrings);
InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings);
InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings);
InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings);
......
......@@ -191,6 +191,11 @@ struct Extensions
// GL_ANGLE_timer_query
bool timerQuery;
// GL_EXT_disjoint_timer_query
bool disjointTimerQuery;
GLuint queryCounterBitsTimeElapsed;
GLuint queryCounterBitsTimestamp;
// GL_EXT_robustness
bool robustness;
......
......@@ -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 @@ Error Context::endQuery(GLenum target)
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);
......
......@@ -129,6 +129,12 @@ class Context final : public ValidationContext
Error beginQuery(GLenum target, GLuint query);
Error endQuery(GLenum target);
Error queryCounter(GLuint id, GLenum target);
void getQueryiv(GLenum target, GLenum pname, GLint *params);
Error getQueryObjectiv(GLuint id, GLenum pname, GLint *params);
Error getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params);
Error getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params);
Error getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params);
void setVertexAttribDivisor(GLuint index, GLuint divisor);
......
......@@ -40,12 +40,32 @@ Error Query::end()
return mQuery->end();
}
Error Query::queryCounter()
{
return mQuery->queryCounter();
}
Error Query::getResult(GLint *params)
{
return mQuery->getResult(params);
}
Error Query::getResult(GLuint *params)
{
return mQuery->getResult(params);
}
Error Query::isResultAvailable(GLuint *available)
Error Query::getResult(GLint64 *params)
{
return mQuery->getResult(params);
}
Error Query::getResult(GLuint64 *params)
{
return mQuery->getResult(params);
}
Error Query::isResultAvailable(bool *available)
{
return mQuery->isResultAvailable(available);
}
......
......@@ -36,9 +36,12 @@ class Query final : public RefCountObject, public LabeledObject
Error begin();
Error end();
Error queryCounter();
Error getResult(GLint *params);
Error getResult(GLuint *params);
Error isResultAvailable(GLuint *available);
Error getResult(GLint64 *params);
Error getResult(GLuint64 *params);
Error isResultAvailable(bool *available);
GLenum getType() const;
......
......@@ -180,14 +180,15 @@ void State::initialize(const Caps &caps,
mSamplers.resize(caps.maxCombinedTextureImageUnits);
mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL);
mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL);
mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL);
mActiveQueries[GL_ANY_SAMPLES_PASSED].set(nullptr);
mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(nullptr);
mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(nullptr);
mActiveQueries[GL_TIME_ELAPSED_EXT].set(nullptr);
mProgram = NULL;
mProgram = nullptr;
mReadFramebuffer = NULL;
mDrawFramebuffer = NULL;
mReadFramebuffer = nullptr;
mDrawFramebuffer = nullptr;
mPrimitiveRestart = false;
......@@ -1005,10 +1006,22 @@ void State::detachTransformFeedback(GLuint transformFeedback)
bool State::isQueryActive() const
{
for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin();
i != mActiveQueries.end(); i++)
for (auto &iter : mActiveQueries)
{
if (iter.second.get() != NULL)
{
return true;
}
}
return false;
}
bool State::isQueryActive(Query *query) const
{
for (auto &iter : mActiveQueries)
{
if (i->second.get() != NULL)
if (iter.second.get() == query)
{
return true;
}
......
......@@ -196,6 +196,7 @@ class State : angle::NonCopyable
// Query binding manipulation
bool isQueryActive() const;
bool isQueryActive(Query *query) const;
void setActiveQuery(GLenum target, Query *query);
GLuint getActiveQueryId(GLenum target) const;
Query *getActiveQuery(GLenum target) const;
......
......@@ -26,8 +26,12 @@ class QueryImpl : angle::NonCopyable
virtual gl::Error begin() = 0;
virtual gl::Error end() = 0;
virtual gl::Error queryCounter() = 0;
virtual gl::Error getResult(GLint *params) = 0;
virtual gl::Error getResult(GLuint *params) = 0;
virtual gl::Error isResultAvailable(GLuint *available) = 0;
virtual gl::Error getResult(GLint64 *params) = 0;
virtual gl::Error getResult(GLuint64 *params) = 0;
virtual gl::Error isResultAvailable(bool *available) = 0;
GLenum getType() const { return mType; }
......
......@@ -60,7 +60,14 @@ gl::Error Query11::end()
return gl::Error(GL_NO_ERROR);
}
gl::Error Query11::getResult(GLuint *params)
gl::Error Query11::queryCounter()
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION, "Unimplemented");
}
template <typename T>
gl::Error Query11::getResultBase(T *params)
{
while (!mQueryFinished)
{
......@@ -77,12 +84,32 @@ gl::Error Query11::getResult(GLuint *params)
}
ASSERT(mQueryFinished);
*params = mResult;
*params = static_cast<T>(mResult);
return gl::Error(GL_NO_ERROR);
}
gl::Error Query11::isResultAvailable(GLuint *available)
gl::Error Query11::getResult(GLint *params)
{
return getResultBase(params);
}
gl::Error Query11::getResult(GLuint *params)
{
return getResultBase(params);
}
gl::Error Query11::getResult(GLint64 *params)
{
return getResultBase(params);
}
gl::Error Query11::getResult(GLuint64 *params)
{
return getResultBase(params);
}
gl::Error Query11::isResultAvailable(bool *available)
{
gl::Error error = testQuery();
if (error.isError())
......@@ -90,7 +117,7 @@ gl::Error Query11::isResultAvailable(GLuint *available)
return error;
}
*available = (mQueryFinished ? GL_TRUE : GL_FALSE);
*available = mQueryFinished;
return gl::Error(GL_NO_ERROR);
}
......@@ -134,7 +161,7 @@ gl::Error Query11::testQuery()
if (result == S_OK)
{
mQueryFinished = true;
mResult = static_cast<GLuint>(soStats.NumPrimitivesWritten);
mResult = static_cast<GLuint64>(soStats.NumPrimitivesWritten);
}
}
break;
......
......@@ -23,13 +23,20 @@ class Query11 : public QueryImpl
virtual gl::Error begin();
virtual gl::Error end();
virtual gl::Error queryCounter();
virtual gl::Error getResult(GLint *params);
virtual gl::Error getResult(GLuint *params);
virtual gl::Error isResultAvailable(GLuint *available);
virtual gl::Error getResult(GLint64 *params);
virtual gl::Error getResult(GLuint64 *params);
virtual gl::Error isResultAvailable(bool *available);
private:
gl::Error testQuery();
GLuint mResult;
template <typename T>
gl::Error getResultBase(T *params);
GLuint64 mResult;
bool mQueryFinished;
......
......@@ -1198,6 +1198,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel);
extensions->fence = GetEventQuerySupport(featureLevel);
extensions->timerQuery = false; // Unimplemented
extensions->disjointTimerQuery = false;
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel);
......
......@@ -66,7 +66,14 @@ gl::Error Query9::end()
return gl::Error(GL_NO_ERROR);
}
gl::Error Query9::getResult(GLuint *params)
gl::Error Query9::queryCounter()
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION, "Unimplemented");
}
template <typename T>
gl::Error Query9::getResultBase(T *params)
{
while (!mQueryFinished)
{
......@@ -83,12 +90,31 @@ gl::Error Query9::getResult(GLuint *params)
}
ASSERT(mQueryFinished);
*params = mResult;
*params = static_cast<T>(mResult);
return gl::Error(GL_NO_ERROR);
}
gl::Error Query9::isResultAvailable(GLuint *available)
gl::Error Query9::getResult(GLint *params)
{
return getResultBase(params);
}
gl::Error Query9::getResult(GLuint *params)
{
return getResultBase(params);
}
gl::Error Query9::getResult(GLint64 *params)
{
return getResultBase(params);
}
gl::Error Query9::getResult(GLuint64 *params)
{
return getResultBase(params);
}
gl::Error Query9::isResultAvailable(bool *available)
{
gl::Error error = testQuery();
if (error.isError())
......@@ -96,7 +122,7 @@ gl::Error Query9::isResultAvailable(GLuint *available)
return error;
}
*available = (mQueryFinished ? GL_TRUE : GL_FALSE);
*available = mQueryFinished;
return gl::Error(GL_NO_ERROR);
}
......
......@@ -23,13 +23,20 @@ class Query9 : public QueryImpl
virtual gl::Error begin();
virtual gl::Error end();
virtual gl::Error queryCounter();
virtual gl::Error getResult(GLint *params);
virtual gl::Error getResult(GLuint *params);
virtual gl::Error isResultAvailable(GLuint *available);
virtual gl::Error getResult(GLint64 *params);
virtual gl::Error getResult(GLuint64 *params);
virtual gl::Error isResultAvailable(bool *available);
private:
gl::Error testQuery();
GLuint mResult;
template <typename T>
gl::Error getResultBase(T *params);
GLuint64 mResult;
bool mQueryFinished;
Renderer9 *mRenderer;
......
......@@ -558,6 +558,7 @@ void GenerateCaps(IDirect3D9 *d3d9,
SafeRelease(eventQuery);
extensions->timerQuery = false; // Unimplemented
extensions->disjointTimerQuery = false;
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = true;
......
......@@ -1774,6 +1774,19 @@ void FunctionsGL::initializeProcsGLES()
AssignGLExtensionEntryPoint(extensions, "GL_EXT_occlusion_query_boolean", loadProcAddress("glGetQueryivEXT"), &getQueryiv);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_occlusion_query_boolean", loadProcAddress("glGetQueryObjectuivEXT"), &getQueryObjectuiv);
// GL_EXT_disjoint_timer_query
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGenQueriesEXT"), &genQueries);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glDeleteQueriesEXT"), &deleteQueries);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glIsQueryEXT"), &isQuery);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glBeginQueryEXT"), &beginQuery);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glEndQueryEXT"), &endQuery);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glQueryCounterEXT"), &queryCounter);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGetQueryivEXT"), &getQueryiv);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGetQueryObjectivEXT"), &getQueryObjectiv);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGetQueryObjectuivEXT"), &getQueryObjectuiv);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGetQueryObjecti64vEXT"), &getQueryObjecti64v);
AssignGLExtensionEntryPoint(extensions, "GL_EXT_disjoint_timer_query", loadProcAddress("glGetQueryObjectui64vEXT"), &getQueryObjectui64v);
// GL_OES_EGL_image
AssignGLExtensionEntryPoint(extensions, "GL_OES_EGL_image", loadProcAddress("glEGLImageTargetRenderbufferStorageOES"), &eglImageTargetRenderbufferStorageOES);
AssignGLExtensionEntryPoint(extensions, "GL_OES_EGL_image", loadProcAddress("glEGLImageTargetTexture2DOES"), &eglImageTargetTexture2DOES);
......
......@@ -15,7 +15,7 @@
namespace
{
GLuint MergeQueryResults(GLenum type, GLuint currentResult, GLuint newResult)
GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult)
{
switch (type)
{
......@@ -26,6 +26,12 @@ GLuint MergeQueryResults(GLenum type, GLuint currentResult, GLuint newResult)
case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
return currentResult + newResult;
case GL_TIME_ELAPSED:
return currentResult + newResult;
case GL_TIMESTAMP:
return newResult;
default:
UNREACHABLE();
return 0;
......@@ -70,7 +76,22 @@ gl::Error QueryGL::end()
return pause();
}
gl::Error QueryGL::getResult(GLuint *params)
gl::Error QueryGL::queryCounter()
{
ASSERT(mType == GL_TIMESTAMP);
// Directly create a query for the timestamp and add it to the pending query queue, as timestamp
// queries do not have the traditional begin/end block and never need to be paused/resumed
GLuint query;
mFunctions->genQueries(1, &query);
mFunctions->queryCounter(query, GL_TIMESTAMP);
mPendingQueries.push_back(query);
return gl::Error(GL_NO_ERROR);
}
template <typename T>
gl::Error QueryGL::getResultBase(T *params)
{
ASSERT(mActiveQuery == 0);
......@@ -81,12 +102,32 @@ gl::Error QueryGL::getResult(GLuint *params)
}
ASSERT(mPendingQueries.empty());
*params = mResultSum;
*params = static_cast<T>(mResultSum);
return gl::Error(GL_NO_ERROR);
}
gl::Error QueryGL::isResultAvailable(GLuint *available)
gl::Error QueryGL::getResult(GLint *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLuint *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLint64 *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLuint64 *params)
{
return getResultBase(params);
}
gl::Error QueryGL::isResultAvailable(bool *available)
{
ASSERT(mActiveQuery == 0);
......@@ -96,7 +137,7 @@ gl::Error QueryGL::isResultAvailable(GLuint *available)
return error;
}
*available = mPendingQueries.empty() ? GL_TRUE : GL_FALSE;
*available = mPendingQueries.empty();
return gl::Error(GL_NO_ERROR);
}
......@@ -153,9 +194,21 @@ gl::Error QueryGL::flush(bool force)
}
}
GLuint result = 0;
mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
mResultSum = MergeQueryResults(mType, mResultSum, result);
// Even though getQueryObjectui64v was introduced for timer queries, there is nothing in the
// standard that says that it doesn't work for any other queries. It also passes on all the
// trybots, so we use it if it is available
if (mFunctions->getQueryObjectui64v != nullptr)
{
GLuint64 result = 0;
mFunctions->getQueryObjectui64v(id, GL_QUERY_RESULT, &result);
mResultSum = MergeQueryResults(mType, mResultSum, result);
}
else
{
GLuint result = 0;
mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
mResultSum = MergeQueryResults(mType, mResultSum, static_cast<GLuint64>(result));
}
mStateManager->deleteQuery(id);
......
......@@ -27,8 +27,12 @@ class QueryGL : public QueryImpl
gl::Error begin() override;
gl::Error end() override;
gl::Error queryCounter() override;
gl::Error getResult(GLint *params) override;
gl::Error getResult(GLuint *params) override;
gl::Error isResultAvailable(GLuint *available) override;
gl::Error getResult(GLint64 *params) override;
gl::Error getResult(GLuint64 *params) override;
gl::Error isResultAvailable(bool *available) override;
// OpenGL is only allowed to have one query of each type active at any given time. Since ANGLE
// virtualizes contexts, queries need to be able to be paused and resumed.
......@@ -42,6 +46,9 @@ class QueryGL : public QueryImpl
private:
gl::Error flush(bool force);
template <typename T>
gl::Error getResultBase(T *params);
GLenum mType;
const FunctionsGL *mFunctions;
......@@ -49,7 +56,7 @@ class QueryGL : public QueryImpl
GLuint mActiveQuery;
std::deque<GLuint> mPendingQueries;
GLuint mResultSum;
GLuint64 mResultSum;
};
}
......
......@@ -28,7 +28,7 @@ namespace rx
{
static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN};
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED};
StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0)
{
......
......@@ -151,6 +151,13 @@ static gl::TypePrecision QueryTypePrecision(const FunctionsGL *functions, GLenum
return precision;
}
static GLint QueryQueryValue(const FunctionsGL *functions, GLenum target, GLenum name)
{
GLint result;
functions->getQueryiv(target, name, &result);
return result;
}
static void LimitVersion(gl::Version *curVersion, const gl::Version &maxVersion)
{
if (*curVersion >= maxVersion)
......@@ -612,6 +619,17 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
extensions->debugMarker =
functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_KHR_debug") ||
functions->isAtLeastGLES(gl::Version(3, 2)) || functions->hasGLESExtension("GL_KHR_debug");
if (functions->isAtLeastGL(gl::Version(3, 3)) ||
functions->hasGLExtension("GL_ARB_timer_query") ||
functions->hasGLESExtension("GL_EXT_disjoint_timer_query"))
{
// TODO(ewell): Extension is disabled by default until all functionality is implemented
extensions->disjointTimerQuery = false;
extensions->queryCounterBitsTimeElapsed =
QueryQueryValue(functions, GL_TIME_ELAPSED, GL_QUERY_COUNTER_BITS);
extensions->queryCounterBitsTimestamp =
QueryQueryValue(functions, GL_TIMESTAMP, GL_QUERY_COUNTER_BITS);
}
// ANGLE emulates vertex array objects in its GL layer
extensions->vertexArrayObject = true;
......
......@@ -383,6 +383,8 @@ bool ValidQueryType(const Context *context, GLenum queryType)
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 @@ bool ValidateReadnPixelsEXT(Context *context,
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 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// 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 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// 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,
......
......@@ -105,8 +105,22 @@ bool ValidateReadnPixelsEXT(Context *context,
GLsizei bufSize,
GLvoid *pixels);
bool ValidateBeginQuery(Context *context, GLenum target, GLuint id);
bool ValidateEndQuery(Context *context, GLenum target);
bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids);
bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids);
bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids);
bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids);
bool ValidateBeginQueryBase(Context *context, GLenum target, GLuint id);
bool ValidateBeginQueryEXT(Context *context, GLenum target, GLuint id);
bool ValidateEndQueryBase(Context *context, GLenum target);
bool ValidateEndQueryEXT(Context *context, GLenum target);
bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target);
bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname);
bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params);
bool ValidateGetQueryObjectValueBase(Context *context, GLenum target, GLenum pname);
bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params);
bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params);
bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params);
bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params);
bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count);
bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count,
......
......@@ -1116,6 +1116,72 @@ bool ValidateES3TexStorage3DParameters(Context *context,
height, depth);
}
bool ValidateGenQueries(gl::Context *context, GLsizei n, const GLuint *ids)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateGenQueriesBase(context, n, ids);
}
bool ValidateDeleteQueries(gl::Context *context, GLsizei n, const GLuint *ids)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateDeleteQueriesBase(context, n, ids);
}
bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateBeginQueryBase(context, target, id);
}
bool ValidateEndQuery(gl::Context *context, GLenum target)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateEndQueryBase(context, target);
}
bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateGetQueryivBase(context, target, pname);
}
bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
return false;
}
return ValidateGetQueryObjectValueBase(context, id, pname);
}
bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level, GLint layer)
{
......
......@@ -141,6 +141,18 @@ bool ValidateES3TexStorage3DParameters(Context *context,
GLsizei height,
GLsizei depth);
bool ValidateGenQueries(Context *context, GLsizei n, const GLuint *ids);
bool ValidateDeleteQueries(Context *context, GLsizei n, const GLuint *ids);
bool ValidateBeginQuery(Context *context, GLenum target, GLuint id);
bool ValidateEndQuery(Context *context, GLenum target);
bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params);
bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params);
bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level, GLint layer);
......
......@@ -55,6 +55,12 @@ ANGLE_EXPORT void GL_APIENTRY EndQueryEXT(GLenum target);
ANGLE_EXPORT void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params);
ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params);
// GL_EXT_disjoint_timer_query
ANGLE_EXPORT void GL_APIENTRY QueryCounterEXT(GLuint id, GLenum target);
ANGLE_EXPORT void GL_APIENTRY GetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params);
ANGLE_EXPORT void GL_APIENTRY GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params);
ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *params);
// GL_EXT_draw_buffers
ANGLE_EXPORT void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs);
......
......@@ -273,15 +273,8 @@ void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (n < 0)
if (!ValidateGenQueries(context, n, ids))
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
......@@ -299,19 +292,12 @@ void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (n < 0)
if (!ValidateDeleteQueries(context, n, ids))
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
for (GLsizei i = 0; i < n; i++)
for (int i = 0; i < n; i++)
{
context->deleteQuery(ids[i]);
}
......@@ -344,12 +330,6 @@ void GL_APIENTRY BeginQuery(GLenum target, GLuint id)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (!ValidateBeginQuery(context, target, id))
{
return;
......@@ -371,12 +351,6 @@ void GL_APIENTRY EndQuery(GLenum target)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (!ValidateEndQuery(context, target))
{
return;
......@@ -398,28 +372,12 @@ void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint* params)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
if (!ValidateGetQueryiv(context, target, pname, params))
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (!ValidQueryType(context, target))
{
context->recordError(Error(GL_INVALID_ENUM));
return;
}
switch (pname)
{
case GL_CURRENT_QUERY:
params[0] = static_cast<GLint>(context->getState().getActiveQueryId(target));
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
context->getQueryiv(target, pname, params);
}
}
......@@ -430,52 +388,15 @@ void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
Query *queryObject = context->getQuery(id, false, GL_NONE);
if (!queryObject)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (context->getState().getActiveQueryId(queryObject->getType()) == id)
if (!ValidateGetQueryObjectuiv(context, id, pname, params))
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
switch(pname)
Error error = context->getQueryObjectuiv(id, pname, params);
if (error.isError())
{
case GL_QUERY_RESULT_EXT:
{
Error error = queryObject->getResult(params);
if (error.isError())
{
context->recordError(error);
return;
}
}
break;
case GL_QUERY_RESULT_AVAILABLE_EXT:
{
Error error = queryObject->isResultAvailable(params);
if (error.isError())
{
context->recordError(error);
return;
}
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
context->recordError(error);
return;
}
}
......
......@@ -1350,16 +1350,36 @@ void GL_APIENTRY glEndQueryEXT(GLenum target)
return gl::EndQueryEXT(target);
}
void GL_APIENTRY glQueryCounterEXT(GLuint id, GLenum target)
{
return gl::QueryCounterEXT(id, target);
}
void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
{
return gl::GetQueryivEXT(target, pname, params);
}
void GL_APIENTRY glGetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params)
{
return gl::GetQueryObjectivEXT(id, pname, params);
}
void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
{
return gl::GetQueryObjectuivEXT(id, pname, params);
}
void GL_APIENTRY glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params)
{
return gl::GetQueryObjecti64vEXT(id, pname, params);
}
void GL_APIENTRY glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *params)
{
return gl::GetQueryObjectui64vEXT(id, pname, params);
}
void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
{
return gl::DrawBuffersEXT(n, bufs);
......
......@@ -198,6 +198,10 @@ EXPORTS
glObjectPtrLabelKHR @311
glGetObjectPtrLabelKHR @312
glGetPointervKHR @313
glQueryCounterEXT @314
glGetQueryObjectivEXT @315
glGetQueryObjecti64vEXT @316
glGetQueryObjectui64vEXT @317
; GLES 3.0 Functions
glReadBuffer @180
......
......@@ -56,6 +56,7 @@
'<(angle_path)/src/tests/gl_tests/StateChangeTest.cpp',
'<(angle_path)/src/tests/gl_tests/SwizzleTest.cpp',
'<(angle_path)/src/tests/gl_tests/TextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/TimerQueriesTest.cpp',
'<(angle_path)/src/tests/gl_tests/TransformFeedbackTest.cpp',
'<(angle_path)/src/tests/gl_tests/UniformBufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/UniformTest.cpp',
......
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TimerQueriesTest.cpp
// Various tests for EXT_disjoint_timer_query functionality and validation
//
#include "system_utils.h"
#include "test_utils/ANGLETest.h"
#include "random_utils.h"
using namespace angle;
class TimerQueriesTest : public ANGLETest
{
protected:
TimerQueriesTest() : mProgram(0), mProgramCostly(0)
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
}
virtual void SetUp()
{
ANGLETest::SetUp();
const std::string passthroughVS =
"attribute highp vec4 position; void main(void)\n"
"{\n"
" gl_Position = position;\n"
"}\n";
const std::string passthroughPS =
"precision highp float; void main(void)\n"
"{\n"
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
"}\n";
const std::string costlyVS =
"attribute highp vec4 position; varying highp vec4 testPos; void main(void)\n"
"{\n"
" testPos = position;\n"
" gl_Position = position;\n"
"}\n";
const std::string costlyPS =
"precision highp float; varying highp vec4 testPos; void main(void)\n"
"{\n"
" vec4 test = testPos;\n"
" for (int i = 0; i < 500; i++)\n"
" {\n"
" test = sqrt(test);\n"
" }\n"
" gl_FragColor = test;\n"
"}\n";
mProgram = CompileProgram(passthroughVS, passthroughPS);
ASSERT_NE(0u, mProgram) << "shader compilation failed.";
mProgramCostly = CompileProgram(costlyVS, costlyPS);
ASSERT_NE(0u, mProgramCostly) << "shader compilation failed.";
}
virtual void TearDown()
{
glDeleteProgram(mProgram);
glDeleteProgram(mProgramCostly);
ANGLETest::TearDown();
}
GLuint mProgram;
GLuint mProgramCostly;
};
// Tests the time elapsed query
TEST_P(TimerQueriesTest, TimeElapsed)
{
if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
{
std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
<< std::endl;
return;
}
GLint queryTimeElapsedBits = 0;
glGetQueryivEXT(GL_TIME_ELAPSED_EXT, GL_QUERY_COUNTER_BITS_EXT, &queryTimeElapsedBits);
ASSERT_GL_NO_ERROR();
std::cout << "Time elapsed counter bits: " << queryTimeElapsedBits << std::endl;
// Skip test if the number of bits is 0
if (queryTimeElapsedBits == 0)
{
std::cout << "Test skipped because of 0 counter bits" << std::endl;
return;
}
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLuint query1 = 0;
GLuint query2 = 0;
glGenQueriesEXT(1, &query1);
glGenQueriesEXT(1, &query2);
// Test time elapsed for a single quad
glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query1);
drawQuad(mProgram, "position", 0.8f);
glEndQueryEXT(GL_TIME_ELAPSED_EXT);
ASSERT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Test time elapsed for costly quad
glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query2);
drawQuad(mProgramCostly, "position", 0.8f);
glEndQueryEXT(GL_TIME_ELAPSED_EXT);
ASSERT_GL_NO_ERROR();
swapBuffers();
int timeout = 10000;
GLuint ready = GL_FALSE;
while (ready == GL_FALSE && timeout > 0)
{
angle::Sleep(0);
glGetQueryObjectuivEXT(query1, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
timeout--;
}
ready = GL_FALSE;
while (ready == GL_FALSE && timeout > 0)
{
angle::Sleep(0);
glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
timeout--;
}
ASSERT_LT(0, timeout) << "Query result available timed out" << std::endl;
GLuint64 result1 = 0;
GLuint64 result2 = 0;
glGetQueryObjectui64vEXT(query1, GL_QUERY_RESULT_EXT, &result1);
glGetQueryObjectui64vEXT(query2, GL_QUERY_RESULT_EXT, &result2);
ASSERT_GL_NO_ERROR();
glDeleteQueriesEXT(1, &query1);
glDeleteQueriesEXT(1, &query2);
ASSERT_GL_NO_ERROR();
std::cout << "Elapsed time: " << result1 << " cheap quad" << std::endl;
std::cout << "Elapsed time: " << result2 << " costly quad" << std::endl;
// The time elapsed should be nonzero
EXPECT_LT(0ul, result1);
EXPECT_LT(0ul, result2);
// The costly quad should take longer than the cheap quad
EXPECT_LT(result1, result2);
}
// Tests validation of query functions with respect to elapsed time query
TEST_P(TimerQueriesTest, TimeElapsedValidationTest)
{
if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
{
std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
<< std::endl;
return;
}
GLint queryTimeElapsedBits = 0;
glGetQueryivEXT(GL_TIME_ELAPSED_EXT, GL_QUERY_COUNTER_BITS_EXT, &queryTimeElapsedBits);
ASSERT_GL_NO_ERROR();
std::cout << "Time elapsed counter bits: " << queryTimeElapsedBits << std::endl;
// Skip test if the number of bits is 0
if (queryTimeElapsedBits == 0)
{
std::cout << "Test skipped because of 0 counter bits" << std::endl;
return;
}
GLuint query = 0;
glGenQueriesEXT(-1, &query);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
glGenQueriesEXT(1, &query);
EXPECT_GL_NO_ERROR();
glBeginQueryEXT(GL_TIMESTAMP_EXT, query);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glBeginQueryEXT(GL_TIME_ELAPSED_EXT, 0);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glEndQueryEXT(GL_TIME_ELAPSED_EXT);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
EXPECT_GL_NO_ERROR();
glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glEndQueryEXT(GL_TIME_ELAPSED_EXT);
EXPECT_GL_NO_ERROR();
glEndQueryEXT(GL_TIME_ELAPSED_EXT);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Tests GPU timestamp functionality
TEST_P(TimerQueriesTest, Timestamp)
{
if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
{
std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
<< std::endl;
return;
}
GLint queryTimestampBits = 0;
glGetQueryivEXT(GL_TIMESTAMP_EXT, GL_QUERY_COUNTER_BITS_EXT, &queryTimestampBits);
ASSERT_GL_NO_ERROR();
std::cout << "Timestamp counter bits: " << queryTimestampBits << std::endl;
// Macs for some reason return 0 bits so skip the test for now if either are 0
if (queryTimestampBits == 0)
{
std::cout << "Test skipped because of 0 counter bits" << std::endl;
return;
}
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLuint query1 = 0;
GLuint query2 = 0;
glGenQueriesEXT(1, &query1);
glGenQueriesEXT(1, &query2);
glQueryCounterEXT(query1, GL_TIMESTAMP_EXT);
drawQuad(mProgram, "position", 0.8f);
glQueryCounterEXT(query2, GL_TIMESTAMP_EXT);
ASSERT_GL_NO_ERROR();
swapBuffers();
int timeout = 10000;
GLuint ready = GL_FALSE;
while (ready == GL_FALSE && timeout > 0)
{
angle::Sleep(0);
glGetQueryObjectuivEXT(query1, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
timeout--;
}
ready = GL_FALSE;
while (ready == GL_FALSE && timeout > 0)
{
angle::Sleep(0);
glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
timeout--;
}
ASSERT_LT(0, timeout) << "Query result available timed out" << std::endl;
GLuint64 result1 = 0;
GLuint64 result2 = 0;
glGetQueryObjectui64vEXT(query1, GL_QUERY_RESULT_EXT, &result1);
glGetQueryObjectui64vEXT(query2, GL_QUERY_RESULT_EXT, &result2);
ASSERT_GL_NO_ERROR();
glDeleteQueriesEXT(1, &query1);
glDeleteQueriesEXT(1, &query2);
std::cout << "Timestamps: " << result1 << " " << result2 << std::endl;
EXPECT_LT(0ul, result1);
EXPECT_LT(0ul, result2);
EXPECT_LT(result1, result2);
}
ANGLE_INSTANTIATE_TEST(TimerQueriesTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment