diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp new file mode 100755 index 000000000..6d9df5d76 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp @@ -0,0 +1,222 @@ +// +// Copyright 2015 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. +// + +// QueryGL.cpp: Implements the class methods for QueryGL. + +#include "libANGLE/renderer/gl/QueryGL.h" + +#include "common/debug.h" +#include "libANGLE/renderer/gl/FunctionsGL.h" +#include "libANGLE/renderer/gl/StateManagerGL.h" + +namespace +{ + +GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult) +{ + switch (type) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE; + + 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; + } +} + +} // anonymous namespace + +namespace rx +{ + +QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager) + : QueryImpl(type), + mType(type), + mFunctions(functions), + mStateManager(stateManager), + mActiveQuery(0), + mPendingQueries(), + mResultSum(0) +{ +} + +QueryGL::~QueryGL() +{ + mStateManager->deleteQuery(mActiveQuery); + mStateManager->onDeleteQueryObject(this); + while (!mPendingQueries.empty()) + { + mStateManager->deleteQuery(mPendingQueries.front()); + mPendingQueries.pop_front(); + } +} + +gl::Error QueryGL::begin() +{ + mResultSum = 0; + mStateManager->onBeginQuery(this); + return resume(); +} + +gl::Error QueryGL::end() +{ + return pause(); +} + +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); + + gl::Error error = flush(true); + if (error.isError()) + { + return error; + } + + ASSERT(mPendingQueries.empty()); + *params = static_cast<T>(mResultSum); + + return gl::Error(GL_NO_ERROR); +} + +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); + + gl::Error error = flush(false); + if (error.isError()) + { + return error; + } + + *available = mPendingQueries.empty(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error QueryGL::pause() +{ + if (mActiveQuery != 0) + { + mStateManager->endQuery(mType, mActiveQuery); + + mPendingQueries.push_back(mActiveQuery); + mActiveQuery = 0; + } + + // Flush to make sure the pending queries don't add up too much. + gl::Error error = flush(false); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error QueryGL::resume() +{ + if (mActiveQuery == 0) + { + // Flush to make sure the pending queries don't add up too much. + gl::Error error = flush(false); + if (error.isError()) + { + return error; + } + + mFunctions->genQueries(1, &mActiveQuery); + mStateManager->beginQuery(mType, mActiveQuery); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error QueryGL::flush(bool force) +{ + while (!mPendingQueries.empty()) + { + GLuint id = mPendingQueries.front(); + if (!force) + { + GLuint resultAvailable = 0; + mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT_AVAILABLE, &resultAvailable); + if (resultAvailable == GL_FALSE) + { + return gl::Error(GL_NO_ERROR); + } + } + + // 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); + + mPendingQueries.pop_front(); + } + + return gl::Error(GL_NO_ERROR); +} + +} |