diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Query11.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Query11.cpp new file mode 100644 index 0000000000..f2368e9f8f --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -0,0 +1,357 @@ +// +// Copyright 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/Context.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_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::CommandsCompleted: + return newResult; + + default: + UNREACHABLE(); + return 0; + } +} + +} // anonymous namespace + +namespace rx +{ + +Query11::QueryState::QueryState() + : getDataAttemptCount(0), query(), beginTimestamp(), endTimestamp(), finished(false) +{} + +Query11::QueryState::~QueryState() {} + +Query11::Query11(Renderer11 *renderer, gl::QueryType type) + : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer) +{ + mActiveQuery = std::unique_ptr<QueryState>(new QueryState()); +} + +Query11::~Query11() +{ + mRenderer->getStateManager()->onDeleteQueryObject(this); +} + +angle::Result Query11::begin(const gl::Context *context) +{ + mResultSum = 0; + mRenderer->getStateManager()->onBeginQuery(this); + return resume(GetImplAs<Context11>(context)); +} + +angle::Result Query11::end(const gl::Context *context) +{ + return pause(GetImplAs<Context11>(context)); +} + +angle::Result Query11::queryCounter(const gl::Context *context) +{ + // This doesn't do anything for D3D11 as we don't support timestamps + ASSERT(getType() == gl::QueryType::Timestamp); + mResultSum = 0; + mPendingQueries.push_back(std::unique_ptr<QueryState>(new QueryState())); + return angle::Result::Continue; +} + +template <typename T> +angle::Result Query11::getResultBase(Context11 *context11, T *params) +{ + ASSERT(!mActiveQuery->query.valid()); + ANGLE_TRY(flush(context11, true)); + ASSERT(mPendingQueries.empty()); + *params = static_cast<T>(mResultSum); + + return angle::Result::Continue; +} + +angle::Result Query11::getResult(const gl::Context *context, GLint *params) +{ + return getResultBase(GetImplAs<Context11>(context), params); +} + +angle::Result Query11::getResult(const gl::Context *context, GLuint *params) +{ + return getResultBase(GetImplAs<Context11>(context), params); +} + +angle::Result Query11::getResult(const gl::Context *context, GLint64 *params) +{ + return getResultBase(GetImplAs<Context11>(context), params); +} + +angle::Result Query11::getResult(const gl::Context *context, GLuint64 *params) +{ + return getResultBase(GetImplAs<Context11>(context), params); +} + +angle::Result Query11::isResultAvailable(const gl::Context *context, bool *available) +{ + ANGLE_TRY(flush(GetImplAs<Context11>(context), false)); + + *available = mPendingQueries.empty(); + return angle::Result::Continue; +} + +angle::Result Query11::pause(Context11 *context11) +{ + if (mActiveQuery->query.valid()) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + gl::QueryType type = getType(); + + // If we are doing time elapsed query the end timestamp + if (type == gl::QueryType::TimeElapsed) + { + context->End(mActiveQuery->endTimestamp.get()); + } + + context->End(mActiveQuery->query.get()); + + mPendingQueries.push_back(std::move(mActiveQuery)); + mActiveQuery = std::unique_ptr<QueryState>(new QueryState()); + } + + return flush(context11, false); +} + +angle::Result Query11::resume(Context11 *context11) +{ + if (!mActiveQuery->query.valid()) + { + ANGLE_TRY(flush(context11, false)); + + gl::QueryType type = getType(); + D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(type); + + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = d3dQueryType; + queryDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->query)); + + // If we are doing time elapsed we also need a query to actually query the timestamp + if (type == gl::QueryType::TimeElapsed) + { + D3D11_QUERY_DESC desc; + desc.Query = D3D11_QUERY_TIMESTAMP; + desc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->beginTimestamp)); + ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->endTimestamp)); + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + if (d3dQueryType != D3D11_QUERY_EVENT) + { + context->Begin(mActiveQuery->query.get()); + } + + // If we are doing time elapsed, query the begin timestamp + if (type == gl::QueryType::TimeElapsed) + { + context->End(mActiveQuery->beginTimestamp.get()); + } + } + + return angle::Result::Continue; +} + +angle::Result Query11::flush(Context11 *context11, bool force) +{ + while (!mPendingQueries.empty()) + { + QueryState *query = mPendingQueries.front().get(); + + do + { + ANGLE_TRY(testQuery(context11, query)); + if (!query->finished && !force) + { + return angle::Result::Continue; + } + } while (!query->finished); + + mResultSum = MergeQueryResults(getType(), mResultSum, mResult); + mPendingQueries.pop_front(); + } + + return angle::Result::Continue; +} + +angle::Result Query11::testQuery(Context11 *context11, QueryState *queryState) +{ + if (!queryState->finished) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + switch (getType()) + { + case gl::QueryType::AnySamples: + case gl::QueryType::AnySamplesConservative: + { + ASSERT(queryState->query.valid()); + UINT64 numPixels = 0; + HRESULT result = + context->GetData(queryState->query.get(), &numPixels, sizeof(numPixels), 0); + ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); + + if (result == S_OK) + { + queryState->finished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + } + break; + + case gl::QueryType::TransformFeedbackPrimitivesWritten: + { + ASSERT(queryState->query.valid()); + D3D11_QUERY_DATA_SO_STATISTICS soStats = {}; + HRESULT result = + context->GetData(queryState->query.get(), &soStats, sizeof(soStats), 0); + ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); + + if (result == S_OK) + { + queryState->finished = true; + mResult = static_cast<GLuint64>(soStats.NumPrimitivesWritten); + } + } + break; + + case gl::QueryType::TimeElapsed: + { + ASSERT(queryState->query.valid()); + ASSERT(queryState->beginTimestamp.valid()); + ASSERT(queryState->endTimestamp.valid()); + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {}; + HRESULT result = + context->GetData(queryState->query.get(), &timeStats, sizeof(timeStats), 0); + ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); + + if (result == S_OK) + { + UINT64 beginTime = 0; + HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(), + &beginTime, sizeof(UINT64), 0); + ANGLE_TRY_HR(context11, beginRes, + "Failed to get the data of an internal query"); + + UINT64 endTime = 0; + HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &endTime, + sizeof(UINT64), 0); + ANGLE_TRY_HR(context11, endRes, "Failed to get the data of an internal query"); + + 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::QueryType::Timestamp: + { + // 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.valid()); + mResult = 0; + queryState->finished = true; + } + break; + + case gl::QueryType::CommandsCompleted: + { + ASSERT(queryState->query.valid()); + BOOL completed = 0; + HRESULT result = + context->GetData(queryState->query.get(), &completed, sizeof(completed), 0); + ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); + + if (result == S_OK) + { + queryState->finished = true; + ASSERT(completed == TRUE); + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } + } + break; + + default: + UNREACHABLE(); + break; + } + + queryState->getDataAttemptCount++; + bool checkDeviceLost = + (queryState->getDataAttemptCount % kPollingD3DDeviceLostCheckFrequency) == 0; + if (!queryState->finished && checkDeviceLost && mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + ANGLE_TRY_HR(context11, E_OUTOFMEMORY, + "Failed to test get query result, device is lost."); + } + } + + return angle::Result::Continue; +} + +} // namespace rx |