Commit bccaaffd by Jamie Madill Committed by Commit Bot

Vulkan: Use XFB queries with the XFB extension.

This will enable accurate XFB primitive counts when using tessellation and geometry shaders. Adds new vk::QueryResult and gl::QueryTypeMap helper classes. Based on contributions by Mohan Maiya (m.maiya@samsung.com). Bug: angleproject:3572 Change-Id: Ie3f496deda887c13bb4ad7ab430e31d615849bfd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2564002 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarMohan Maiya <m.maiya@samsung.com>
parent 01e8b675
...@@ -848,6 +848,9 @@ template <typename T> ...@@ -848,6 +848,9 @@ template <typename T>
using TransformFeedbackBuffersArray = using TransformFeedbackBuffersArray =
std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>; std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
template <typename T>
using QueryTypeMap = angle::PackedEnumMap<QueryType, T>;
constexpr size_t kBarrierVectorDefaultSize = 16; constexpr size_t kBarrierVectorDefaultSize = 16;
template <typename T> template <typename T>
......
...@@ -39,17 +39,20 @@ class QueryImpl : angle::NonCopyable ...@@ -39,17 +39,20 @@ class QueryImpl : angle::NonCopyable
gl::QueryType getType() const { return mType; } gl::QueryType getType() const { return mType; }
// Convenient functions // Convenience functions
bool isOcclusionQuery() const { return isAnySamplesQuery() || isAnySamplesConservativeQuery(); } bool isOcclusionQuery() const { return isAnySamplesQuery() || isAnySamplesConservativeQuery(); }
bool isAnySamplesQuery() const { return getType() == gl::QueryType::AnySamples; } bool isAnySamplesQuery() const { return mType == gl::QueryType::AnySamples; }
bool isAnySamplesConservativeQuery() const bool isAnySamplesConservativeQuery() const
{ {
return getType() == gl::QueryType::AnySamplesConservative; return mType == gl::QueryType::AnySamplesConservative;
}
bool isTransformFeedbackQuery() const
{
return mType == gl::QueryType::TransformFeedbackPrimitivesWritten;
} }
private: protected:
gl::QueryType mType; const gl::QueryType mType;
}; };
} // namespace rx } // namespace rx
......
...@@ -60,7 +60,6 @@ StandardQueryGL::StandardQueryGL(gl::QueryType type, ...@@ -60,7 +60,6 @@ StandardQueryGL::StandardQueryGL(gl::QueryType type,
const FunctionsGL *functions, const FunctionsGL *functions,
StateManagerGL *stateManager) StateManagerGL *stateManager)
: QueryGL(type), : QueryGL(type),
mType(type),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mActiveQuery(0), mActiveQuery(0),
......
...@@ -59,8 +59,6 @@ class StandardQueryGL : public QueryGL ...@@ -59,8 +59,6 @@ class StandardQueryGL : public QueryGL
template <typename T> template <typename T>
angle::Result getResultBase(const gl::Context *context, T *params); angle::Result getResultBase(const gl::Context *context, T *params);
gl::QueryType mType;
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
......
...@@ -364,12 +364,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -364,12 +364,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mCurrentWindowSurface(nullptr), mCurrentWindowSurface(nullptr),
mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity), mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity),
mCurrentRotationReadFramebuffer(SurfaceRotation::Identity), mCurrentRotationReadFramebuffer(SurfaceRotation::Identity),
mRenderPassQueries{},
mVertexArray(nullptr), mVertexArray(nullptr),
mDrawFramebuffer(nullptr), mDrawFramebuffer(nullptr),
mProgram(nullptr), mProgram(nullptr),
mExecutable(nullptr), mExecutable(nullptr),
mActiveQueryAnySamples(nullptr),
mActiveQueryAnySamplesConservative(nullptr),
mLastIndexBufferOffset(0), mLastIndexBufferOffset(0),
mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum), mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
mXfbBaseVertex(0), mXfbBaseVertex(0),
...@@ -558,6 +557,13 @@ angle::Result ContextVk::initialize() ...@@ -558,6 +557,13 @@ angle::Result ContextVk::initialize()
vk::kDefaultTimestampQueryPoolSize)); vk::kDefaultTimestampQueryPoolSize));
} }
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
ANGLE_TRY(mQueryPools[gl::QueryType::TransformFeedbackPrimitivesWritten].init(
this, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT,
vk::kDefaultTransformFeedbackQueryPoolSize));
}
// Init gles to vulkan index type map // Init gles to vulkan index type map
initIndexTypeMap(); initIndexTypeMap();
...@@ -1725,13 +1731,13 @@ angle::Result ContextVk::synchronizeCpuGpuTime() ...@@ -1725,13 +1731,13 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
// another thread had submitted work. // another thread had submitted work.
ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial())); ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
uint64_t gpuTimestampCycles = 0; vk::QueryResult gpuTimestampCycles(1);
ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles)); ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
// Use the first timestamp queried as origin. // Use the first timestamp queried as origin.
if (mGpuEventTimestampOrigin == 0) if (mGpuEventTimestampOrigin == 0)
{ {
mGpuEventTimestampOrigin = gpuTimestampCycles; mGpuEventTimestampOrigin = gpuTimestampCycles.getResult();
} }
// Take these CPU and GPU timestamps if there is better confidence. // Take these CPU and GPU timestamps if there is better confidence.
...@@ -1740,7 +1746,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime() ...@@ -1740,7 +1746,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
{ {
tightestRangeS = confidenceRangeS; tightestRangeS = confidenceRangeS;
TcpuS = cpuTimestampS; TcpuS = cpuTimestampS;
TgpuCycles = gpuTimestampCycles; TgpuCycles = gpuTimestampCycles.getResult();
} }
} }
...@@ -1797,8 +1803,8 @@ angle::Result ContextVk::checkCompletedGpuEvents() ...@@ -1797,8 +1803,8 @@ angle::Result ContextVk::checkCompletedGpuEvents()
} }
// See if the results are available. // See if the results are available.
uint64_t gpuTimestampCycles = 0; vk::QueryResult gpuTimestampCycles(1);
bool available = false; bool available = false;
ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles, ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
&available)); &available));
if (!available) if (!available)
...@@ -1809,7 +1815,7 @@ angle::Result ContextVk::checkCompletedGpuEvents() ...@@ -1809,7 +1815,7 @@ angle::Result ContextVk::checkCompletedGpuEvents()
mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper); mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
GpuEvent gpuEvent; GpuEvent gpuEvent;
gpuEvent.gpuTimestampCycles = gpuTimestampCycles; gpuEvent.gpuTimestampCycles = gpuTimestampCycles.getResult();
gpuEvent.name = eventQuery.name; gpuEvent.name = eventQuery.name;
gpuEvent.phase = eventQuery.phase; gpuEvent.phase = eventQuery.phase;
...@@ -3589,6 +3595,7 @@ vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType) ...@@ -3589,6 +3595,7 @@ vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
{ {
ASSERT(queryType == gl::QueryType::AnySamples || ASSERT(queryType == gl::QueryType::AnySamples ||
queryType == gl::QueryType::AnySamplesConservative || queryType == gl::QueryType::AnySamplesConservative ||
queryType == gl::QueryType::TransformFeedbackPrimitivesWritten ||
queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed); queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
// Assert that timestamp extension is available if needed. // Assert that timestamp extension is available if needed.
...@@ -4363,7 +4370,9 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut) ...@@ -4363,7 +4370,9 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial); scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial);
// Get the query results // Get the query results
ANGLE_TRY(timestampQuery.getUint64Result(this, timestampOut)); vk::QueryResult result(1);
ANGLE_TRY(timestampQuery.getUint64Result(this, &result));
*timestampOut = result.getResult();
timestampQueryPool.get().freeQuery(this, &timestampQuery); timestampQueryPool.get().freeQuery(this, &timestampQuery);
// Convert results to nanoseconds. // Convert results to nanoseconds.
...@@ -4490,7 +4499,7 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea, ...@@ -4490,7 +4499,7 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer)); ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer));
ANGLE_TRY(resumeOcclusionQueryIfActive()); resumeRenderPassQueryIfActive();
const gl::DepthStencilState &dsState = mState.getDepthStencilState(); const gl::DepthStencilState &dsState = mState.getDepthStencilState();
vk::ResourceAccess depthAccess = GetDepthAccess(dsState); vk::ResourceAccess depthAccess = GetDepthAccess(dsState);
...@@ -4557,7 +4566,7 @@ angle::Result ContextVk::flushCommandsAndEndRenderPass() ...@@ -4557,7 +4566,7 @@ angle::Result ContextVk::flushCommandsAndEndRenderPass()
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_TRY(pauseOcclusionQueryIfActive()); ANGLE_TRY(pauseRenderPassQueryIfActive());
mCurrentTransformFeedbackBuffers.clear(); mCurrentTransformFeedbackBuffers.clear();
mCurrentIndirectBuffer = nullptr; mCurrentIndirectBuffer = nullptr;
...@@ -4714,88 +4723,56 @@ angle::Result ContextVk::flushOutsideRenderPassCommands() ...@@ -4714,88 +4723,56 @@ angle::Result ContextVk::flushOutsideRenderPassCommands()
return angle::Result::Continue; return angle::Result::Continue;
} }
void ContextVk::beginOcclusionQuery(QueryVk *queryVk) void ContextVk::beginRenderPassQuery(QueryVk *queryVk)
{ {
// To avoid complexity, we always start and end occlusion query inside renderpass. if renderpass // To avoid complexity, we always start and end occlusion query inside renderpass. if renderpass
// not yet started, we just remember it and defer the start call. // not yet started, we just remember it and defer the start call.
if (mRenderPassCommands->started()) if (mRenderPassCommands->started())
{ {
queryVk->getQueryHelper()->beginOcclusionQuery(this, mRenderPassCommandBuffer); queryVk->getQueryHelper()->beginRenderPassQuery(this, mRenderPassCommandBuffer);
}
if (queryVk->isAnySamplesQuery())
{
ASSERT(mActiveQueryAnySamples == nullptr);
mActiveQueryAnySamples = queryVk;
}
else if (queryVk->isAnySamplesConservativeQuery())
{
ASSERT(mActiveQueryAnySamplesConservative == nullptr);
mActiveQueryAnySamplesConservative = queryVk;
}
else
{
UNREACHABLE();
} }
mRenderPassQueries[queryVk->getType()] = queryVk;
} }
void ContextVk::endOcclusionQuery(QueryVk *queryVk) void ContextVk::endRenderPassQuery(QueryVk *queryVk)
{ {
if (mRenderPassCommands->started() && mRenderPassCommandBuffer) if (mRenderPassCommands->started() && mRenderPassCommandBuffer)
{ {
queryVk->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer); queryVk->getQueryHelper()->endRenderPassQuery(this, mRenderPassCommandBuffer);
}
if (queryVk->isAnySamplesQuery())
{
ASSERT(mActiveQueryAnySamples == queryVk);
mActiveQueryAnySamples = nullptr;
}
else if (queryVk->isAnySamplesConservativeQuery())
{
ASSERT(mActiveQueryAnySamplesConservative == queryVk);
mActiveQueryAnySamplesConservative = nullptr;
}
else
{
UNREACHABLE();
} }
mRenderPassQueries[queryVk->getType()] = nullptr;
} }
angle::Result ContextVk::pauseOcclusionQueryIfActive() angle::Result ContextVk::pauseRenderPassQueryIfActive()
{ {
if (mRenderPassCommandBuffer == nullptr) if (mRenderPassCommandBuffer == nullptr)
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
if (mActiveQueryAnySamples) for (QueryVk *activeQuery : mRenderPassQueries)
{
mActiveQueryAnySamples->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer);
ANGLE_TRY(mActiveQueryAnySamples->stashQueryHelper(this));
}
if (mActiveQueryAnySamplesConservative)
{ {
mActiveQueryAnySamplesConservative->getQueryHelper()->endOcclusionQuery( if (activeQuery)
this, mRenderPassCommandBuffer); {
ANGLE_TRY(mActiveQueryAnySamplesConservative->stashQueryHelper(this)); activeQuery->getQueryHelper()->endRenderPassQuery(this, mRenderPassCommandBuffer);
ANGLE_TRY(activeQuery->stashQueryHelper(this));
}
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::resumeOcclusionQueryIfActive() void ContextVk::resumeRenderPassQueryIfActive()
{ {
if (mActiveQueryAnySamples) for (QueryVk *activeQuery : mRenderPassQueries)
{
mActiveQueryAnySamples->getQueryHelper()->beginOcclusionQuery(this,
mRenderPassCommandBuffer);
}
if (mActiveQueryAnySamplesConservative)
{ {
mActiveQueryAnySamplesConservative->getQueryHelper()->beginOcclusionQuery( if (activeQuery)
this, mRenderPassCommandBuffer); {
activeQuery->getQueryHelper()->beginRenderPassQuery(this, mRenderPassCommandBuffer);
}
} }
return angle::Result::Continue;
} }
bool ContextVk::isRobustResourceInitEnabled() const bool ContextVk::isRobustResourceInitEnabled() const
......
...@@ -536,11 +536,11 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -536,11 +536,11 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
bool isRobustResourceInitEnabled() const; bool isRobustResourceInitEnabled() const;
// occlusion query // occlusion query
void beginOcclusionQuery(QueryVk *queryVk); void beginRenderPassQuery(QueryVk *queryVk);
void endOcclusionQuery(QueryVk *queryVk); void endRenderPassQuery(QueryVk *queryVk);
angle::Result pauseOcclusionQueryIfActive(); angle::Result pauseRenderPassQueryIfActive();
angle::Result resumeOcclusionQueryIfActive(); void resumeRenderPassQueryIfActive();
void updateOverlayOnPresent(); void updateOverlayOnPresent();
void addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer); void addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer);
...@@ -893,7 +893,10 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -893,7 +893,10 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
// Note that this implementation would need to change in shared resource scenarios. Likely // Note that this implementation would need to change in shared resource scenarios. Likely
// we'd instead share a single set of pools between the share groups. // we'd instead share a single set of pools between the share groups.
angle::PackedEnumMap<PipelineType, vk::DynamicDescriptorPool> mDriverUniformsDescriptorPools; angle::PackedEnumMap<PipelineType, vk::DynamicDescriptorPool> mDriverUniformsDescriptorPools;
angle::PackedEnumMap<gl::QueryType, vk::DynamicQueryPool> mQueryPools; gl::QueryTypeMap<vk::DynamicQueryPool> mQueryPools;
// Saved queries run in the RenderPass.
gl::QueryTypeMap<QueryVk *> mRenderPassQueries;
// Dirty bits. // Dirty bits.
DirtyBits mGraphicsDirtyBits; DirtyBits mGraphicsDirtyBits;
...@@ -910,10 +913,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -910,10 +913,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
ProgramPipelineVk *mProgramPipeline; ProgramPipelineVk *mProgramPipeline;
ProgramExecutableVk *mExecutable; ProgramExecutableVk *mExecutable;
// occlusion query
QueryVk *mActiveQueryAnySamples;
QueryVk *mActiveQueryAnySamplesConservative;
// The offset we had the last time we bound the index buffer. // The offset we had the last time we bound the index buffer.
const GLvoid *mLastIndexBufferOffset; const GLvoid *mLastIndexBufferOffset;
gl::DrawElementsType mCurrentDrawElementsType; gl::DrawElementsType mCurrentDrawElementsType;
......
...@@ -41,24 +41,22 @@ void QueryVk::onDestroy(const gl::Context *context) ...@@ -41,24 +41,22 @@ void QueryVk::onDestroy(const gl::Context *context)
angle::Result QueryVk::stashQueryHelper(ContextVk *contextVk) angle::Result QueryVk::stashQueryHelper(ContextVk *contextVk)
{ {
ASSERT(isOcclusionQuery()); ASSERT(isRenderPassQuery(contextVk));
mStashedQueryHelpers.emplace_back(std::move(mQueryHelper)); mStashedQueryHelpers.emplace_back(std::move(mQueryHelper));
mQueryHelper.deinit(); mQueryHelper.deinit();
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper)); ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result QueryVk::retrieveStashedQueryResult(ContextVk *contextVk, uint64_t *result) angle::Result QueryVk::accumulateStashedQueryResult(ContextVk *contextVk, vk::QueryResult *result)
{ {
uint64_t total = 0;
for (vk::QueryHelper &query : mStashedQueryHelpers) for (vk::QueryHelper &query : mStashedQueryHelpers)
{ {
uint64_t v; vk::QueryResult v(getQueryResultCount());
ANGLE_TRY(query.getUint64Result(contextVk, &v)); ANGLE_TRY(query.getUint64Result(contextVk, &v));
total += v; *result += v;
} }
mStashedQueryHelpers.clear(); mStashedQueryHelpers.clear();
*result = total;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -68,12 +66,16 @@ angle::Result QueryVk::begin(const gl::Context *context) ...@@ -68,12 +66,16 @@ angle::Result QueryVk::begin(const gl::Context *context)
mCachedResultValid = false; mCachedResultValid = false;
// Transform feedback query is a handled by a CPU-calculated value when emulated. if (isTransformFeedbackQuery())
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
{ {
mTransformFeedbackPrimitivesDrawn = 0; mTransformFeedbackPrimitivesDrawn = 0;
// We could consider using VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT.
return angle::Result::Continue; // Transform feedback query is a handled by a CPU-calculated value when emulated.
if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
ASSERT(!contextVk->getFeatures().supportsTransformFeedbackExtension.enabled);
return angle::Result::Continue;
}
} }
if (!mQueryHelper.valid()) if (!mQueryHelper.valid())
...@@ -81,7 +83,7 @@ angle::Result QueryVk::begin(const gl::Context *context) ...@@ -81,7 +83,7 @@ angle::Result QueryVk::begin(const gl::Context *context)
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper)); ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
} }
if (isOcclusionQuery()) if (isRenderPassQuery(contextVk))
{ {
// For pathological usage case where begin/end is called back to back without flush and get // For pathological usage case where begin/end is called back to back without flush and get
// result, we have to force flush so that the same mQueryHelper will not encoded in the same // result, we have to force flush so that the same mQueryHelper will not encoded in the same
...@@ -95,7 +97,7 @@ angle::Result QueryVk::begin(const gl::Context *context) ...@@ -95,7 +97,7 @@ angle::Result QueryVk::begin(const gl::Context *context)
mQueryHelper.deinit(); mQueryHelper.deinit();
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper)); ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
} }
contextVk->beginOcclusionQuery(this); contextVk->beginRenderPassQuery(this);
} }
else if (getType() == gl::QueryType::TimeElapsed) else if (getType() == gl::QueryType::TimeElapsed)
{ {
...@@ -120,12 +122,18 @@ angle::Result QueryVk::end(const gl::Context *context) ...@@ -120,12 +122,18 @@ angle::Result QueryVk::end(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten) if (isRenderPassQuery(contextVk))
{ {
contextVk->endRenderPassQuery(this);
}
else if (isTransformFeedbackQuery())
{
// Transform feedback query is a handled by a CPU-calculated value when emulated.
ASSERT(contextVk->getFeatures().emulateTransformFeedback.enabled);
mCachedResult = mTransformFeedbackPrimitivesDrawn; mCachedResult = mTransformFeedbackPrimitivesDrawn;
// There could be transform feedback in progress, so add the primitives drawn so far from // There could be transform feedback in progress, so add the primitives drawn so far
// the current transform feedback object. // from the current transform feedback object.
gl::TransformFeedback *transformFeedback = gl::TransformFeedback *transformFeedback =
context->getState().getCurrentTransformFeedback(); context->getState().getCurrentTransformFeedback();
if (transformFeedback) if (transformFeedback)
...@@ -133,11 +141,6 @@ angle::Result QueryVk::end(const gl::Context *context) ...@@ -133,11 +141,6 @@ angle::Result QueryVk::end(const gl::Context *context)
mCachedResult += transformFeedback->getPrimitivesDrawn(); mCachedResult += transformFeedback->getPrimitivesDrawn();
} }
mCachedResultValid = true; mCachedResultValid = true;
// We could consider using VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT.
}
else if (isOcclusionQuery())
{
contextVk->endOcclusionQuery(this);
} }
else if (getType() == gl::QueryType::TimeElapsed) else if (getType() == gl::QueryType::TimeElapsed)
{ {
...@@ -268,25 +271,23 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait) ...@@ -268,25 +271,23 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
ANGLE_TRY(finishRunningCommands(contextVk)); ANGLE_TRY(finishRunningCommands(contextVk));
} }
vk::QueryResult result(getQueryResultCount());
if (wait) if (wait)
{ {
ANGLE_TRY(mQueryHelper.getUint64Result(contextVk, &mCachedResult)); ANGLE_TRY(mQueryHelper.getUint64Result(contextVk, &result));
uint64_t v; ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
ANGLE_TRY(retrieveStashedQueryResult(contextVk, &v));
mCachedResult += v;
} }
else else
{ {
bool available = false; bool available = false;
ANGLE_TRY(mQueryHelper.getUint64ResultNonBlocking(contextVk, &mCachedResult, &available)); ANGLE_TRY(mQueryHelper.getUint64ResultNonBlocking(contextVk, &result, &available));
if (!available) if (!available)
{ {
// If the results are not ready, do nothing. mCachedResultValid remains false. // If the results are not ready, do nothing. mCachedResultValid remains false.
return angle::Result::Continue; return angle::Result::Continue;
} }
uint64_t v; ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
ANGLE_TRY(retrieveStashedQueryResult(contextVk, &v));
mCachedResult += v;
} }
double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod; double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod;
...@@ -297,24 +298,26 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait) ...@@ -297,24 +298,26 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
case gl::QueryType::AnySamples: case gl::QueryType::AnySamples:
case gl::QueryType::AnySamplesConservative: case gl::QueryType::AnySamplesConservative:
// OpenGL query result in these cases is binary // OpenGL query result in these cases is binary
mCachedResult = !!mCachedResult; mCachedResult = !!result.getResult();
break; break;
case gl::QueryType::Timestamp: case gl::QueryType::Timestamp:
mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod); mCachedResult = static_cast<uint64_t>(result.getResult() * timestampPeriod);
break; break;
case gl::QueryType::TimeElapsed: case gl::QueryType::TimeElapsed:
{ {
uint64_t timeElapsedEnd = mCachedResult; vk::QueryResult timeElapsedBegin(1);
// Since the result of the end query of time-elapsed is already available, the // Since the result of the end query of time-elapsed is already available, the
// result of begin query must be available too. // result of begin query must be available too.
ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &mCachedResult)); ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &timeElapsedBegin));
mCachedResult = timeElapsedEnd - mCachedResult;
mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod);
uint64_t delta = result.getResult() - timeElapsedBegin.getResult();
mCachedResult = static_cast<uint64_t>(delta * timestampPeriod);
break; break;
} }
case gl::QueryType::TransformFeedbackPrimitivesWritten:
mCachedResult = result.getResult();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
...@@ -363,4 +366,16 @@ void QueryVk::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn) ...@@ -363,4 +366,16 @@ void QueryVk::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
{ {
mTransformFeedbackPrimitivesDrawn += primitivesDrawn; mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
} }
bool QueryVk::isRenderPassQuery(ContextVk *contextVk) const
{
return isOcclusionQuery() ||
(isTransformFeedbackQuery() &&
contextVk->getFeatures().supportsTransformFeedbackExtension.enabled);
}
uint32_t QueryVk::getQueryResultCount() const
{
return isTransformFeedbackQuery() ? 2 : 1;
}
} // namespace rx } // namespace rx
...@@ -37,7 +37,8 @@ class QueryVk : public QueryImpl ...@@ -37,7 +37,8 @@ class QueryVk : public QueryImpl
void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn); void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn);
vk::QueryHelper *getQueryHelper() { return &mQueryHelper; } vk::QueryHelper *getQueryHelper() { return &mQueryHelper; }
angle::Result stashQueryHelper(ContextVk *contextVk); angle::Result stashQueryHelper(ContextVk *contextVk);
angle::Result retrieveStashedQueryResult(ContextVk *contextVk, uint64_t *result);
bool isRenderPassQuery(ContextVk *contextVk) const;
private: private:
angle::Result getResult(const gl::Context *context, bool wait); angle::Result getResult(const gl::Context *context, bool wait);
...@@ -45,6 +46,8 @@ class QueryVk : public QueryImpl ...@@ -45,6 +46,8 @@ class QueryVk : public QueryImpl
bool isUsedInRecordedCommands() const; bool isUsedInRecordedCommands() const;
bool isCurrentlyInUse(Serial lastCompletedSerial) const; bool isCurrentlyInUse(Serial lastCompletedSerial) const;
angle::Result finishRunningCommands(ContextVk *contextVk); angle::Result finishRunningCommands(ContextVk *contextVk);
uint32_t getQueryResultCount() const;
angle::Result accumulateStashedQueryResult(ContextVk *contextVk, vk::QueryResult *result);
// Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end). // Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end).
vk::QueryHelper mQueryHelper; vk::QueryHelper mQueryHelper;
......
...@@ -1598,10 +1598,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1598,10 +1598,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
sizeof(shaderParams), commandBuffer)); sizeof(shaderParams), commandBuffer));
// Make sure this draw call doesn't count towards occlusion query results. // Make sure this draw call doesn't count towards occlusion query results.
ANGLE_TRY(contextVk->pauseOcclusionQueryIfActive()); ANGLE_TRY(contextVk->pauseRenderPassQueryIfActive());
commandBuffer->setScissor(0, 1, &scissor); commandBuffer->setScissor(0, 1, &scissor);
commandBuffer->draw(3, 0); commandBuffer->draw(3, 0);
ANGLE_TRY(contextVk->resumeOcclusionQueryIfActive()); contextVk->resumeRenderPassQueryIfActive();
// Make sure what's bound here is correctly reverted on the next draw. // Make sure what's bound here is correctly reverted on the next draw.
contextVk->invalidateGraphicsPipelineAndDescriptorSets(); contextVk->invalidateGraphicsPipelineAndDescriptorSets();
......
...@@ -2487,14 +2487,14 @@ angle::Result QueryHelper::endQuery(ContextVk *contextVk) ...@@ -2487,14 +2487,14 @@ angle::Result QueryHelper::endQuery(ContextVk *contextVk)
return angle::Result::Continue; return angle::Result::Continue;
} }
void QueryHelper::beginOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer) void QueryHelper::beginRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
{ {
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
renderPassCommandBuffer->queueResetQueryPool(queryPool.getHandle(), mQuery, 1); renderPassCommandBuffer->queueResetQueryPool(queryPool.getHandle(), mQuery, 1);
renderPassCommandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0); renderPassCommandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0);
} }
void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer) void QueryHelper::endRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
{ {
renderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery); renderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
...@@ -2537,7 +2537,7 @@ void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuf ...@@ -2537,7 +2537,7 @@ void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuf
} }
angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk, angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
uint64_t *resultOut, QueryResult *resultOut,
bool *availableOut) bool *availableOut)
{ {
ASSERT(valid()); ASSERT(valid());
...@@ -2549,8 +2549,9 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk, ...@@ -2549,8 +2549,9 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
{ {
VkDevice device = contextVk->getDevice(); VkDevice device = contextVk->getDevice();
constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT; constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
result = getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t), resultOut, result =
sizeof(uint64_t), kFlags); getQueryPool().getResults(device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags);
} }
else else
{ {
...@@ -2571,15 +2572,16 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk, ...@@ -2571,15 +2572,16 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, uint64_t *resultOut) angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
{ {
ASSERT(valid()); ASSERT(valid());
if (mUse.getSerial().valid()) if (mUse.getSerial().valid())
{ {
VkDevice device = contextVk->getDevice(); VkDevice device = contextVk->getDevice();
constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT; constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
ANGLE_VK_TRY(contextVk, getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t), ANGLE_VK_TRY(contextVk, getQueryPool().getResults(
resultOut, sizeof(uint64_t), kFlags)); device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags));
} }
else else
{ {
......
...@@ -380,8 +380,9 @@ class DynamicallyGrowingPool : angle::NonCopyable ...@@ -380,8 +380,9 @@ class DynamicallyGrowingPool : angle::NonCopyable
// another is created. The query pools live permanently, but are recycled as indices get freed. // another is created. The query pools live permanently, but are recycled as indices get freed.
// These are arbitrary default sizes for query pools. // These are arbitrary default sizes for query pools.
constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64; constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64;
constexpr uint32_t kDefaultTimestampQueryPoolSize = 64; constexpr uint32_t kDefaultTimestampQueryPoolSize = 64;
constexpr uint32_t kDefaultTransformFeedbackQueryPoolSize = 128;
class QueryHelper; class QueryHelper;
...@@ -406,6 +407,27 @@ class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool> ...@@ -406,6 +407,27 @@ class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool>
VkQueryType mQueryType; VkQueryType mQueryType;
}; };
// Stores the result of a Vulkan query call. XFB queries in particular store two result values.
class QueryResult final
{
public:
QueryResult(uint32_t intsPerResult) : mIntsPerResult(intsPerResult), mResults{} {}
void operator+=(const QueryResult &rhs)
{
mResults[0] += rhs.mResults[0];
mResults[1] += rhs.mResults[1];
}
size_t getDataSize() const { return mIntsPerResult * sizeof(uint64_t); }
uint64_t getResult() const { return mResults[0]; }
uint64_t *getPointerToResults() { return mResults.data(); }
private:
uint32_t mIntsPerResult;
std::array<uint64_t, 2> mResults;
};
// Queries in vulkan are identified by the query pool and an index for a query within that pool. // Queries in vulkan are identified by the query pool and an index for a query within that pool.
// Unlike other pools, such as descriptor pools where an allocation returns an independent object // Unlike other pools, such as descriptor pools where an allocation returns an independent object
// from the pool, the query allocations are not done through a Vulkan function and are only an // from the pool, the query allocations are not done through a Vulkan function and are only an
...@@ -435,8 +457,8 @@ class QueryHelper final : public Resource ...@@ -435,8 +457,8 @@ class QueryHelper final : public Resource
// for occlusion query // for occlusion query
// Must resetQueryPool outside of RenderPass before beginning occlusion query. // Must resetQueryPool outside of RenderPass before beginning occlusion query.
void resetQueryPool(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer); void resetQueryPool(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
void beginOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer); void beginRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
void endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer); void endRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
angle::Result flushAndWriteTimestamp(ContextVk *contextVk); angle::Result flushAndWriteTimestamp(ContextVk *contextVk);
// When syncing gpu/cpu time, main thread accesses primary directly // When syncing gpu/cpu time, main thread accesses primary directly
...@@ -445,9 +467,9 @@ class QueryHelper final : public Resource ...@@ -445,9 +467,9 @@ class QueryHelper final : public Resource
void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer); void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
angle::Result getUint64ResultNonBlocking(ContextVk *contextVk, angle::Result getUint64ResultNonBlocking(ContextVk *contextVk,
uint64_t *resultOut, QueryResult *resultOut,
bool *availableOut); bool *availableOut);
angle::Result getUint64Result(ContextVk *contextVk, uint64_t *resultOut); angle::Result getUint64Result(ContextVk *contextVk, QueryResult *resultOut);
private: private:
friend class DynamicQueryPool; friend class DynamicQueryPool;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment