summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/QueryGL.cpp222
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);
+}
+
+}