| // |
| // 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/Context.h" |
| #include "libANGLE/renderer/gl/ContextGL.h" |
| #include "libANGLE/renderer/gl/FunctionsGL.h" |
| #include "libANGLE/renderer/gl/StateManagerGL.h" |
| #include "libANGLE/renderer/gl/renderergl_utils.h" |
| |
| namespace |
| { |
| |
| GLuint64 MergeQueryResults(gl::QueryType type, GLuint64 currentResult, GLuint64 newResult) |
| { |
| switch (type) |
| { |
| case gl::QueryType::AnySamples: |
| case gl::QueryType::AnySamplesConservative: |
| return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE; |
| |
| case gl::QueryType::TransformFeedbackPrimitivesWritten: |
| return currentResult + newResult; |
| |
| case gl::QueryType::TimeElapsed: |
| return currentResult + newResult; |
| |
| case gl::QueryType::Timestamp: |
| return newResult; |
| |
| case gl::QueryType::PrimitivesGenerated: |
| return currentResult + newResult; |
| |
| default: |
| UNREACHABLE(); |
| return 0; |
| } |
| } |
| |
| // Some drivers tend to hang when flushing pending queries. Wait until this number of queries have |
| // added up before checking if results are ready. |
| constexpr uint32_t kPauseResumeFlushThreshold = 5; |
| } // anonymous namespace |
| |
| namespace rx |
| { |
| |
| QueryGL::QueryGL(gl::QueryType type) : QueryImpl(type) {} |
| |
| QueryGL::~QueryGL() {} |
| |
| StandardQueryGL::StandardQueryGL(gl::QueryType type, |
| const FunctionsGL *functions, |
| StateManagerGL *stateManager) |
| : QueryGL(type), |
| mFunctions(functions), |
| mStateManager(stateManager), |
| mActiveQuery(0), |
| mPendingQueries(), |
| mResultSum(0) |
| {} |
| |
| StandardQueryGL::~StandardQueryGL() |
| { |
| clearInternalQueries(); |
| } |
| |
| void StandardQueryGL::clearInternalQueries() |
| { |
| if (mActiveQuery != 0) |
| { |
| mStateManager->endQuery(mType, this, mActiveQuery); |
| mFunctions->deleteQueries(1, &mActiveQuery); |
| mActiveQuery = 0; |
| } |
| |
| while (!mPendingQueries.empty()) |
| { |
| GLuint id = mPendingQueries.front(); |
| mFunctions->deleteQueries(1, &id); |
| mPendingQueries.pop_front(); |
| } |
| } |
| |
| angle::Result StandardQueryGL::begin(const gl::Context *context) |
| { |
| clearInternalQueries(); |
| mResultSum = 0; |
| return resume(context); |
| } |
| |
| angle::Result StandardQueryGL::end(const gl::Context *context) |
| { |
| return pause(context); |
| } |
| |
| angle::Result StandardQueryGL::queryCounter(const gl::Context *context) |
| { |
| ASSERT(mType == gl::QueryType::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 angle::Result::Continue; |
| } |
| |
| template <typename T> |
| angle::Result StandardQueryGL::getResultBase(const gl::Context *context, T *params) |
| { |
| ASSERT(mActiveQuery == 0); |
| |
| ANGLE_TRY(flush(context, true)); |
| ASSERT(mPendingQueries.empty()); |
| *params = static_cast<T>(mResultSum); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StandardQueryGL::getResult(const gl::Context *context, GLint *params) |
| { |
| return getResultBase(context, params); |
| } |
| |
| angle::Result StandardQueryGL::getResult(const gl::Context *context, GLuint *params) |
| { |
| return getResultBase(context, params); |
| } |
| |
| angle::Result StandardQueryGL::getResult(const gl::Context *context, GLint64 *params) |
| { |
| return getResultBase(context, params); |
| } |
| |
| angle::Result StandardQueryGL::getResult(const gl::Context *context, GLuint64 *params) |
| { |
| return getResultBase(context, params); |
| } |
| |
| angle::Result StandardQueryGL::isResultAvailable(const gl::Context *context, bool *available) |
| { |
| ASSERT(mActiveQuery == 0); |
| |
| ANGLE_TRY(flush(context, false)); |
| *available = mPendingQueries.empty(); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StandardQueryGL::pause(const gl::Context *context) |
| { |
| if (mActiveQuery != 0) |
| { |
| mStateManager->endQuery(mType, this, mActiveQuery); |
| |
| mPendingQueries.push_back(mActiveQuery); |
| mActiveQuery = 0; |
| } |
| |
| // Flush to make sure the pending queries don't add up too much. |
| if (mPendingQueries.size() >= kPauseResumeFlushThreshold) |
| { |
| ANGLE_TRY(flush(context, false)); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StandardQueryGL::resume(const gl::Context *context) |
| { |
| if (mActiveQuery == 0) |
| { |
| // Flush to make sure the pending queries don't add up too much. |
| if (mPendingQueries.size() >= kPauseResumeFlushThreshold) |
| { |
| ANGLE_TRY(flush(context, false)); |
| } |
| |
| mFunctions->genQueries(1, &mActiveQuery); |
| mStateManager->beginQuery(mType, this, mActiveQuery); |
| |
| ContextGL *contextGL = GetImplAs<ContextGL>(context); |
| contextGL->markWorkSubmitted(); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StandardQueryGL::flush(const gl::Context *context, 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 angle::Result::Continue; |
| } |
| } |
| |
| // 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)); |
| } |
| |
| mFunctions->deleteQueries(1, &id); |
| |
| mPendingQueries.pop_front(); |
| } |
| |
| return angle::Result::Continue; |
| } |
| } // namespace rx |