summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
new file mode 100755
index 000000000..58b18ded5
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
@@ -0,0 +1,400 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl.
+
+#include "libANGLE/renderer/d3d/d3d11/Query11.h"
+
+#include <GLES2/gl2ext.h>
+
+#include "common/utilities.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.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_EXT:
+ return currentResult + newResult;
+
+ case GL_TIMESTAMP_EXT:
+ return newResult;
+
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return newResult;
+
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+} // anonymous namespace
+
+namespace rx
+{
+
+Query11::QueryState::QueryState()
+ : query(nullptr), beginTimestamp(nullptr), endTimestamp(nullptr), finished(false)
+{
+}
+
+Query11::QueryState::~QueryState()
+{
+ SafeRelease(beginTimestamp);
+ SafeRelease(endTimestamp);
+ SafeRelease(query);
+}
+
+Query11::Query11(Renderer11 *renderer, GLenum type)
+ : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer)
+{
+ mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
+}
+
+Query11::~Query11()
+{
+ mRenderer->getStateManager()->onDeleteQueryObject(this);
+}
+
+gl::Error Query11::begin()
+{
+ mResultSum = 0;
+ mRenderer->getStateManager()->onBeginQuery(this);
+ return resume();
+}
+
+gl::Error Query11::end()
+{
+ return pause();
+}
+
+gl::Error Query11::queryCounter()
+{
+ // This doesn't do anything for D3D11 as we don't support timestamps
+ ASSERT(getType() == GL_TIMESTAMP_EXT);
+ mResultSum = 0;
+ mPendingQueries.push_back(std::unique_ptr<QueryState>(new QueryState()));
+ return gl::Error(GL_NO_ERROR);
+}
+
+template <typename T>
+gl::Error Query11::getResultBase(T *params)
+{
+ ASSERT(mActiveQuery->query == nullptr);
+ ANGLE_TRY(flush(true));
+ ASSERT(mPendingQueries.empty());
+ *params = static_cast<T>(mResultSum);
+
+ return gl::NoError();
+}
+
+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)
+{
+ ANGLE_TRY(flush(false));
+
+ *available = mPendingQueries.empty();
+ return gl::NoError();
+}
+
+gl::Error Query11::pause()
+{
+ if (mActiveQuery->query != nullptr)
+ {
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+ GLenum queryType = getType();
+
+ // If we are doing time elapsed query the end timestamp
+ if (queryType == GL_TIME_ELAPSED_EXT)
+ {
+ context->End(mActiveQuery->endTimestamp);
+ }
+
+ context->End(mActiveQuery->query);
+
+ mPendingQueries.push_back(std::move(mActiveQuery));
+ mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
+ }
+
+ return flush(false);
+}
+
+gl::Error Query11::resume()
+{
+ if (mActiveQuery->query == nullptr)
+ {
+ ANGLE_TRY(flush(false));
+
+ GLenum queryType = getType();
+ D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(queryType);
+
+ D3D11_QUERY_DESC queryDesc;
+ queryDesc.Query = d3dQueryType;
+ queryDesc.MiscFlags = 0;
+
+ ID3D11Device *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateQuery(&queryDesc, &mActiveQuery->query);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
+ result);
+ }
+
+ // If we are doing time elapsed we also need a query to actually query the timestamp
+ if (queryType == GL_TIME_ELAPSED_EXT)
+ {
+ D3D11_QUERY_DESC desc;
+ desc.Query = D3D11_QUERY_TIMESTAMP;
+ desc.MiscFlags = 0;
+ result = device->CreateQuery(&desc, &mActiveQuery->beginTimestamp);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
+ result);
+ }
+ result = device->CreateQuery(&desc, &mActiveQuery->endTimestamp);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
+ result);
+ }
+ }
+
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ if (d3dQueryType != D3D11_QUERY_EVENT)
+ {
+ context->Begin(mActiveQuery->query);
+ }
+
+ // If we are doing time elapsed, query the begin timestamp
+ if (queryType == GL_TIME_ELAPSED_EXT)
+ {
+ context->End(mActiveQuery->beginTimestamp);
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Query11::flush(bool force)
+{
+ while (!mPendingQueries.empty())
+ {
+ QueryState *query = mPendingQueries.front().get();
+
+ do
+ {
+ ANGLE_TRY(testQuery(query));
+ if (!query->finished && !force)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+ } while (!query->finished);
+
+ mResultSum = MergeQueryResults(getType(), mResultSum, mResult);
+ mPendingQueries.pop_front();
+ }
+
+ return gl::NoError();
+}
+
+gl::Error Query11::testQuery(QueryState *queryState)
+{
+ if (!queryState->finished)
+ {
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+ switch (getType())
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ {
+ ASSERT(queryState->query);
+ UINT64 numPixels = 0;
+ HRESULT result =
+ context->GetData(queryState->query, &numPixels, sizeof(numPixels), 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.",
+ result);
+ }
+
+ if (result == S_OK)
+ {
+ queryState->finished = true;
+ mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ break;
+
+ case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+ {
+ ASSERT(queryState->query);
+ D3D11_QUERY_DATA_SO_STATISTICS soStats = {0};
+ HRESULT result = context->GetData(queryState->query, &soStats, sizeof(soStats), 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.",
+ result);
+ }
+
+ if (result == S_OK)
+ {
+ queryState->finished = true;
+ mResult = static_cast<GLuint64>(soStats.NumPrimitivesWritten);
+ }
+ }
+ break;
+
+ case GL_TIME_ELAPSED_EXT:
+ {
+ ASSERT(queryState->query);
+ ASSERT(queryState->beginTimestamp);
+ ASSERT(queryState->endTimestamp);
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {0};
+ HRESULT result =
+ context->GetData(queryState->query, &timeStats, sizeof(timeStats), 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.",
+ result);
+ }
+
+ if (result == S_OK)
+ {
+ UINT64 beginTime = 0;
+ HRESULT beginRes =
+ context->GetData(queryState->beginTimestamp, &beginTime, sizeof(UINT64), 0);
+ if (FAILED(beginRes))
+ {
+ return gl::Error(
+ GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.", beginRes);
+ }
+ UINT64 endTime = 0;
+ HRESULT endRes =
+ context->GetData(queryState->endTimestamp, &endTime, sizeof(UINT64), 0);
+ if (FAILED(endRes))
+ {
+ return gl::Error(
+ GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.", endRes);
+ }
+
+ if (beginRes == S_OK && endRes == S_OK)
+ {
+ queryState->finished = true;
+ if (timeStats.Disjoint)
+ {
+ mRenderer->setGPUDisjoint();
+ }
+ static_assert(sizeof(UINT64) == sizeof(unsigned long long),
+ "D3D UINT64 isn't 64 bits");
+
+ angle::CheckedNumeric<UINT64> checkedTime(endTime);
+ checkedTime -= beginTime;
+ checkedTime *= 1000000000ull;
+ checkedTime /= timeStats.Frequency;
+ if (checkedTime.IsValid())
+ {
+ mResult = checkedTime.ValueOrDie();
+ }
+ else
+ {
+ mResult = std::numeric_limits<GLuint64>::max() / timeStats.Frequency;
+ // If an overflow does somehow occur, there is no way the elapsed time
+ // is accurate, so we generate a disjoint event
+ mRenderer->setGPUDisjoint();
+ }
+ }
+ }
+ }
+ break;
+
+ case GL_TIMESTAMP_EXT:
+ {
+ // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed
+ // to have any sort of continuity outside of a disjoint timestamp query block, which
+ // GL depends on
+ ASSERT(queryState->query == nullptr);
+ mResult = 0;
+ queryState->finished = true;
+ }
+ break;
+
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ {
+ ASSERT(queryState->query);
+ BOOL completed = 0;
+ HRESULT result =
+ context->GetData(queryState->query, &completed, sizeof(completed), 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.",
+ result);
+ }
+
+ if (result == S_OK)
+ {
+ queryState->finished = true;
+ ASSERT(completed == TRUE);
+ mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (!queryState->finished && mRenderer->testDeviceLost())
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost.");
+ }
+ }
+
+ return gl::NoError();
+}
+
+} // namespace rx