Commit 4375d6c7 by Shahbaz Youssefi Committed by Angle LUCI CQ

Vulkan: Support multiview queries

When using queries with multiview, Vulkan specifies that N queries are actually produced (N being the number of views) which must be summed by the application. Bug: angleproject:6048 Change-Id: I5ea615536f1a357806b7ea8093280b9122f1d66a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2971562 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com>
parent 977a28f3
...@@ -2270,7 +2270,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime() ...@@ -2270,7 +2270,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
// Create a query used to receive the GPU timestamp // Create a query used to receive the GPU timestamp
vk::QueryHelper timestampQuery; vk::QueryHelper timestampQuery;
ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &timestampQuery)); ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &timestampQuery, 1));
// Create the three events // Create the three events
VkEventCreateInfo eventCreateInfo = {}; VkEventCreateInfo eventCreateInfo = {};
...@@ -2402,7 +2402,7 @@ angle::Result ContextVk::traceGpuEventImpl(vk::CommandBuffer *commandBuffer, ...@@ -2402,7 +2402,7 @@ angle::Result ContextVk::traceGpuEventImpl(vk::CommandBuffer *commandBuffer,
GpuEventQuery gpuEvent; GpuEventQuery gpuEvent;
gpuEvent.name = name; gpuEvent.name = name;
gpuEvent.phase = phase; gpuEvent.phase = phase;
ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper)); ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper, 1));
gpuEvent.queryHelper.writeTimestamp(this, commandBuffer); gpuEvent.queryHelper.writeTimestamp(this, commandBuffer);
...@@ -5374,7 +5374,7 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut) ...@@ -5374,7 +5374,7 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device); vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device);
vk::QueryHelper timestampQuery; vk::QueryHelper timestampQuery;
ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1)); ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, &timestampQuery)); ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, &timestampQuery, 1));
vk::ResourceUseList scratchResourceUseList; vk::ResourceUseList scratchResourceUseList;
...@@ -5598,6 +5598,12 @@ uint32_t ContextVk::getCurrentSubpassIndex() const ...@@ -5598,6 +5598,12 @@ uint32_t ContextVk::getCurrentSubpassIndex() const
return mGraphicsPipelineDesc->getSubpass(); return mGraphicsPipelineDesc->getSubpass();
} }
uint32_t ContextVk::getCurrentViewCount() const
{
ASSERT(mDrawFramebuffer);
return mDrawFramebuffer->getRenderPassDesc().viewCount();
}
angle::Result ContextVk::flushCommandsAndEndRenderPassImpl() angle::Result ContextVk::flushCommandsAndEndRenderPassImpl()
{ {
// Ensure we flush the RenderPass *after* the prior commands. // Ensure we flush the RenderPass *after* the prior commands.
......
...@@ -558,6 +558,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText ...@@ -558,6 +558,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
void restoreFinishedRenderPass(vk::Framebuffer *framebuffer); void restoreFinishedRenderPass(vk::Framebuffer *framebuffer);
uint32_t getCurrentSubpassIndex() const; uint32_t getCurrentSubpassIndex() const;
uint32_t getCurrentViewCount() const;
egl::ContextPriority getContextPriority() const override { return mContextPriority; } egl::ContextPriority getContextPriority() const override { return mContextPriority; }
angle::Result startRenderPass(gl::Rectangle renderArea, angle::Result startRenderPass(gl::Rectangle renderArea,
......
...@@ -117,7 +117,18 @@ angle::Result QueryVk::allocateQuery(ContextVk *contextVk) ...@@ -117,7 +117,18 @@ angle::Result QueryVk::allocateQuery(ContextVk *contextVk)
ASSERT(!mQueryHelper.isReferenced()); ASSERT(!mQueryHelper.isReferenced());
mQueryHelper.setUnreferenced(new vk::RefCounted<vk::QueryHelper>); mQueryHelper.setUnreferenced(new vk::RefCounted<vk::QueryHelper>);
return contextVk->getQueryPool(mType)->allocateQuery(contextVk, &mQueryHelper.get()); // When used with multiview, render pass queries write as many queries as the number of views.
// Render pass queries are always allocated at the beginning of the render pass, so the number
// of views is known at this time.
uint32_t queryCount = 1;
if (IsRenderPassQuery(contextVk, mType))
{
ASSERT(contextVk->hasStartedRenderPass());
queryCount = std::max(contextVk->getCurrentViewCount(), 1u);
}
return contextVk->getQueryPool(mType)->allocateQuery(contextVk, &mQueryHelper.get(),
queryCount);
} }
void QueryVk::assignSharedQuery(QueryVk *shareQuery) void QueryVk::assignSharedQuery(QueryVk *shareQuery)
...@@ -318,8 +329,10 @@ angle::Result QueryVk::begin(const gl::Context *context) ...@@ -318,8 +329,10 @@ angle::Result QueryVk::begin(const gl::Context *context)
// Note: TimeElapsed is implemented by using two Timestamp queries and taking the diff. // Note: TimeElapsed is implemented by using two Timestamp queries and taking the diff.
if (!mQueryHelperTimeElapsedBegin.valid()) if (!mQueryHelperTimeElapsedBegin.valid())
{ {
// Note that timestamp queries are not allowed with multiview, so query count is
// always 1.
ANGLE_TRY(contextVk->getQueryPool(mType)->allocateQuery( ANGLE_TRY(contextVk->getQueryPool(mType)->allocateQuery(
contextVk, &mQueryHelperTimeElapsedBegin)); contextVk, &mQueryHelperTimeElapsedBegin, 1));
} }
ANGLE_TRY(mQueryHelperTimeElapsedBegin.flushAndWriteTimestamp(contextVk)); ANGLE_TRY(mQueryHelperTimeElapsedBegin.flushAndWriteTimestamp(contextVk));
......
...@@ -2680,18 +2680,22 @@ void DynamicQueryPool::destroy(VkDevice device) ...@@ -2680,18 +2680,22 @@ void DynamicQueryPool::destroy(VkDevice device)
destroyEntryPool(); destroyEntryPool();
} }
angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk, QueryHelper *queryOut) angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
QueryHelper *queryOut,
uint32_t queryCount)
{ {
ASSERT(!queryOut->valid()); ASSERT(!queryOut->valid());
if (mCurrentFreeEntry >= mPoolSize) if (mCurrentFreeEntry + queryCount > mPoolSize)
{ {
// No more queries left in this pool, create another one. // No more queries left in this pool, create another one.
ANGLE_TRY(allocateNewPool(contextVk)); ANGLE_TRY(allocateNewPool(contextVk));
} }
uint32_t queryIndex = mCurrentFreeEntry++; uint32_t queryIndex = mCurrentFreeEntry;
queryOut->init(this, mCurrentPool, queryIndex); mCurrentFreeEntry += queryCount;
queryOut->init(this, mCurrentPool, queryIndex, queryCount);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2735,8 +2739,27 @@ angle::Result DynamicQueryPool::allocateNewPool(ContextVk *contextVk) ...@@ -2735,8 +2739,27 @@ angle::Result DynamicQueryPool::allocateNewPool(ContextVk *contextVk)
return allocateNewEntryPool(contextVk, std::move(queryPool)); return allocateNewEntryPool(contextVk, std::move(queryPool));
} }
// QueryResult implementation
void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
{
ASSERT(mResults[0] == 0 && mResults[1] == 0);
// Accumulate the query results. For multiview, where multiple query indices are used to return
// the results, it's undefined how the results are distributed between indices, but the sum is
// guaranteed to be the desired result.
for (uint32_t query = 0; query < queryCount; ++query)
{
for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
{
mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
}
}
}
// QueryHelper implementation // QueryHelper implementation
QueryHelper::QueryHelper() : mDynamicQueryPool(nullptr), mQueryPoolIndex(0), mQuery(0) {} QueryHelper::QueryHelper()
: mDynamicQueryPool(nullptr), mQueryPoolIndex(0), mQuery(0), mQueryCount(0)
{}
QueryHelper::~QueryHelper() {} QueryHelper::~QueryHelper() {}
...@@ -2745,11 +2768,13 @@ QueryHelper::QueryHelper(QueryHelper &&rhs) ...@@ -2745,11 +2768,13 @@ QueryHelper::QueryHelper(QueryHelper &&rhs)
: Resource(std::move(rhs)), : Resource(std::move(rhs)),
mDynamicQueryPool(rhs.mDynamicQueryPool), mDynamicQueryPool(rhs.mDynamicQueryPool),
mQueryPoolIndex(rhs.mQueryPoolIndex), mQueryPoolIndex(rhs.mQueryPoolIndex),
mQuery(rhs.mQuery) mQuery(rhs.mQuery),
mQueryCount(rhs.mQueryCount)
{ {
rhs.mDynamicQueryPool = nullptr; rhs.mDynamicQueryPool = nullptr;
rhs.mQueryPoolIndex = 0; rhs.mQueryPoolIndex = 0;
rhs.mQuery = 0; rhs.mQuery = 0;
rhs.mQueryCount = 0;
} }
QueryHelper &QueryHelper::operator=(QueryHelper &&rhs) QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
...@@ -2757,16 +2782,21 @@ QueryHelper &QueryHelper::operator=(QueryHelper &&rhs) ...@@ -2757,16 +2782,21 @@ QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool); std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex); std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
std::swap(mQuery, rhs.mQuery); std::swap(mQuery, rhs.mQuery);
std::swap(mQueryCount, rhs.mQueryCount);
return *this; return *this;
} }
void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool, void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
const size_t queryPoolIndex, const size_t queryPoolIndex,
uint32_t query) uint32_t query,
uint32_t queryCount)
{ {
mDynamicQueryPool = dynamicQueryPool; mDynamicQueryPool = dynamicQueryPool;
mQueryPoolIndex = queryPoolIndex; mQueryPoolIndex = queryPoolIndex;
mQuery = query; mQuery = query;
mQueryCount = queryCount;
ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
} }
void QueryHelper::deinit() void QueryHelper::deinit()
...@@ -2774,6 +2804,7 @@ void QueryHelper::deinit() ...@@ -2774,6 +2804,7 @@ void QueryHelper::deinit()
mDynamicQueryPool = nullptr; mDynamicQueryPool = nullptr;
mQueryPoolIndex = 0; mQueryPoolIndex = 0;
mQuery = 0; mQuery = 0;
mQueryCount = 0;
mUse.release(); mUse.release();
mUse.init(); mUse.init();
} }
...@@ -2783,7 +2814,7 @@ void QueryHelper::beginQueryImpl(ContextVk *contextVk, ...@@ -2783,7 +2814,7 @@ void QueryHelper::beginQueryImpl(ContextVk *contextVk,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
resetCommandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, 1); resetCommandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, mQueryCount);
commandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0); commandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0);
} }
...@@ -2866,14 +2897,14 @@ void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBu ...@@ -2866,14 +2897,14 @@ void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBu
// Note that commands may not be flushed at this point. // Note that commands may not be flushed at this point.
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
primary->resetQueryPool(queryPool, mQuery, 1); primary->resetQueryPool(queryPool, mQuery, mQueryCount);
primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery); primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
} }
void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuffer) void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuffer)
{ {
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
commandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, 1); commandBuffer->resetQueryPool(queryPool.getHandle(), mQuery, mQueryCount);
commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool.getHandle(), commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool.getHandle(),
mQuery); mQuery);
// timestamp results are available immediately, retain this query so that we get its serial // timestamp results are available immediately, retain this query so that we get its serial
...@@ -2897,11 +2928,8 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk, ...@@ -2897,11 +2928,8 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
// wait forever and trigger GPU timeout. // wait forever and trigger GPU timeout.
if (hasSubmittedCommands()) if (hasSubmittedCommands())
{ {
VkDevice device = contextVk->getDevice();
constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT; constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
result = result = getResultImpl(contextVk, kFlags, resultOut);
getQueryPool().getResults(device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags);
} }
else else
{ {
...@@ -2927,11 +2955,8 @@ angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *re ...@@ -2927,11 +2955,8 @@ angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *re
ASSERT(valid()); ASSERT(valid());
if (hasSubmittedCommands()) if (hasSubmittedCommands())
{ {
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( ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags));
} }
else else
{ {
...@@ -2940,6 +2965,24 @@ angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *re ...@@ -2940,6 +2965,24 @@ angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *re
return angle::Result::Continue; return angle::Result::Continue;
} }
VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
const VkQueryResultFlags flags,
QueryResult *resultOut)
{
std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
VkDevice device = contextVk->getDevice();
VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
results.data(), sizeof(uint64_t), flags);
if (result == VK_SUCCESS)
{
resultOut->setResults(results.data(), mQueryCount);
}
return result;
}
// DynamicSemaphorePool implementation // DynamicSemaphorePool implementation
DynamicSemaphorePool::DynamicSemaphorePool() = default; DynamicSemaphorePool::DynamicSemaphorePool() = default;
......
...@@ -414,7 +414,7 @@ class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool> ...@@ -414,7 +414,7 @@ class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool>
angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize); angle::Result init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize);
void destroy(VkDevice device); void destroy(VkDevice device);
angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut); angle::Result allocateQuery(ContextVk *contextVk, QueryHelper *queryOut, uint32_t queryCount);
void freeQuery(ContextVk *contextVk, QueryHelper *query); void freeQuery(ContextVk *contextVk, QueryHelper *query);
const QueryPool &getQueryPool(size_t index) const { return mPools[index]; } const QueryPool &getQueryPool(size_t index) const { return mPools[index]; }
...@@ -439,12 +439,12 @@ class QueryResult final ...@@ -439,12 +439,12 @@ class QueryResult final
} }
size_t getDataSize() const { return mIntsPerResult * sizeof(uint64_t); } size_t getDataSize() const { return mIntsPerResult * sizeof(uint64_t); }
void setResults(uint64_t *results, uint32_t queryCount);
uint64_t getResult(size_t index) const uint64_t getResult(size_t index) const
{ {
ASSERT(index < mIntsPerResult); ASSERT(index < mIntsPerResult);
return mResults[index]; return mResults[index];
} }
uint64_t *getPointerToResults() { return mResults.data(); }
static constexpr size_t kDefaultResultIndex = 0; static constexpr size_t kDefaultResultIndex = 0;
static constexpr size_t kTransformFeedbackPrimitivesWrittenIndex = 0; static constexpr size_t kTransformFeedbackPrimitivesWrittenIndex = 0;
...@@ -455,7 +455,7 @@ class QueryResult final ...@@ -455,7 +455,7 @@ class QueryResult final
std::array<uint64_t, 2> mResults; 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
// integer index. // integer index.
...@@ -463,7 +463,9 @@ class QueryResult final ...@@ -463,7 +463,9 @@ class QueryResult final
// Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools // Furthermore, to support arbitrarily large number of queries, DynamicQueryPool creates query pools
// of a fixed size as needed and allocates indices within those pools. // of a fixed size as needed and allocates indices within those pools.
// //
// The QueryHelper class below keeps the pool and index pair together. // The QueryHelper class below keeps the pool and index pair together. For multiview, multiple
// consecutive query indices are implicitly written to by the driver, so the query count is
// additionally kept.
class QueryHelper final : public Resource class QueryHelper final : public Resource
{ {
public: public:
...@@ -473,7 +475,8 @@ class QueryHelper final : public Resource ...@@ -473,7 +475,8 @@ class QueryHelper final : public Resource
QueryHelper &operator=(QueryHelper &&rhs); QueryHelper &operator=(QueryHelper &&rhs);
void init(const DynamicQueryPool *dynamicQueryPool, void init(const DynamicQueryPool *dynamicQueryPool,
const size_t queryPoolIndex, const size_t queryPoolIndex,
uint32_t query); uint32_t query,
uint32_t queryCount);
void deinit(); void deinit();
bool valid() const { return mDynamicQueryPool != nullptr; } bool valid() const { return mDynamicQueryPool != nullptr; }
...@@ -513,10 +516,14 @@ class QueryHelper final : public Resource ...@@ -513,10 +516,14 @@ class QueryHelper final : public Resource
CommandBuffer *resetCommandBuffer, CommandBuffer *resetCommandBuffer,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
void endQueryImpl(ContextVk *contextVk, CommandBuffer *commandBuffer); void endQueryImpl(ContextVk *contextVk, CommandBuffer *commandBuffer);
VkResult getResultImpl(ContextVk *contextVk,
const VkQueryResultFlags flags,
QueryResult *resultOut);
const DynamicQueryPool *mDynamicQueryPool; const DynamicQueryPool *mDynamicQueryPool;
size_t mQueryPoolIndex; size_t mQueryPoolIndex;
uint32_t mQuery; uint32_t mQuery;
uint32_t mQueryCount;
}; };
// DynamicSemaphorePool allocates semaphores as needed. It uses a std::vector // DynamicSemaphorePool allocates semaphores as needed. It uses a std::vector
......
...@@ -1440,9 +1440,6 @@ TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible) ...@@ -1440,9 +1440,6 @@ TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
ANGLE_SKIP_TEST_IF(!requestMultiviewExtension()); ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension()); ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
// TODO: fix occlusion queries with multiview on Vulkan. http://anglebug.com/6048
ANGLE_SKIP_TEST_IF(IsVulkan());
const std::string VS = const std::string VS =
"#version 300 es\n" "#version 300 es\n"
"#extension " + "#extension " +
......
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