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>
using TransformFeedbackBuffersArray =
std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
template <typename T>
using QueryTypeMap = angle::PackedEnumMap<QueryType, T>;
constexpr size_t kBarrierVectorDefaultSize = 16;
template <typename T>
......
......@@ -39,17 +39,20 @@ class QueryImpl : angle::NonCopyable
gl::QueryType getType() const { return mType; }
// Convenient functions
// Convenience functions
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
{
return getType() == gl::QueryType::AnySamplesConservative;
return mType == gl::QueryType::AnySamplesConservative;
}
bool isTransformFeedbackQuery() const
{
return mType == gl::QueryType::TransformFeedbackPrimitivesWritten;
}
private:
gl::QueryType mType;
protected:
const gl::QueryType mType;
};
} // namespace rx
......
......@@ -60,7 +60,6 @@ StandardQueryGL::StandardQueryGL(gl::QueryType type,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: QueryGL(type),
mType(type),
mFunctions(functions),
mStateManager(stateManager),
mActiveQuery(0),
......
......@@ -59,8 +59,6 @@ class StandardQueryGL : public QueryGL
template <typename T>
angle::Result getResultBase(const gl::Context *context, T *params);
gl::QueryType mType;
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
......
......@@ -364,12 +364,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mCurrentWindowSurface(nullptr),
mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity),
mCurrentRotationReadFramebuffer(SurfaceRotation::Identity),
mRenderPassQueries{},
mVertexArray(nullptr),
mDrawFramebuffer(nullptr),
mProgram(nullptr),
mExecutable(nullptr),
mActiveQueryAnySamples(nullptr),
mActiveQueryAnySamplesConservative(nullptr),
mLastIndexBufferOffset(0),
mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
mXfbBaseVertex(0),
......@@ -558,6 +557,13 @@ angle::Result ContextVk::initialize()
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
initIndexTypeMap();
......@@ -1725,13 +1731,13 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
// another thread had submitted work.
ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
uint64_t gpuTimestampCycles = 0;
vk::QueryResult gpuTimestampCycles(1);
ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
// Use the first timestamp queried as origin.
if (mGpuEventTimestampOrigin == 0)
{
mGpuEventTimestampOrigin = gpuTimestampCycles;
mGpuEventTimestampOrigin = gpuTimestampCycles.getResult();
}
// Take these CPU and GPU timestamps if there is better confidence.
......@@ -1740,7 +1746,7 @@ angle::Result ContextVk::synchronizeCpuGpuTime()
{
tightestRangeS = confidenceRangeS;
TcpuS = cpuTimestampS;
TgpuCycles = gpuTimestampCycles;
TgpuCycles = gpuTimestampCycles.getResult();
}
}
......@@ -1797,8 +1803,8 @@ angle::Result ContextVk::checkCompletedGpuEvents()
}
// See if the results are available.
uint64_t gpuTimestampCycles = 0;
bool available = false;
vk::QueryResult gpuTimestampCycles(1);
bool available = false;
ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
&available));
if (!available)
......@@ -1809,7 +1815,7 @@ angle::Result ContextVk::checkCompletedGpuEvents()
mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
GpuEvent gpuEvent;
gpuEvent.gpuTimestampCycles = gpuTimestampCycles;
gpuEvent.gpuTimestampCycles = gpuTimestampCycles.getResult();
gpuEvent.name = eventQuery.name;
gpuEvent.phase = eventQuery.phase;
......@@ -3589,6 +3595,7 @@ vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
{
ASSERT(queryType == gl::QueryType::AnySamples ||
queryType == gl::QueryType::AnySamplesConservative ||
queryType == gl::QueryType::TransformFeedbackPrimitivesWritten ||
queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
// Assert that timestamp extension is available if needed.
......@@ -4363,7 +4370,9 @@ angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial);
// 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);
// Convert results to nanoseconds.
......@@ -4490,7 +4499,7 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer));
ANGLE_TRY(resumeOcclusionQueryIfActive());
resumeRenderPassQueryIfActive();
const gl::DepthStencilState &dsState = mState.getDepthStencilState();
vk::ResourceAccess depthAccess = GetDepthAccess(dsState);
......@@ -4557,7 +4566,7 @@ angle::Result ContextVk::flushCommandsAndEndRenderPass()
return angle::Result::Continue;
}
ANGLE_TRY(pauseOcclusionQueryIfActive());
ANGLE_TRY(pauseRenderPassQueryIfActive());
mCurrentTransformFeedbackBuffers.clear();
mCurrentIndirectBuffer = nullptr;
......@@ -4714,88 +4723,56 @@ angle::Result ContextVk::flushOutsideRenderPassCommands()
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
// not yet started, we just remember it and defer the start call.
if (mRenderPassCommands->started())
{
queryVk->getQueryHelper()->beginOcclusionQuery(this, mRenderPassCommandBuffer);
}
if (queryVk->isAnySamplesQuery())
{
ASSERT(mActiveQueryAnySamples == nullptr);
mActiveQueryAnySamples = queryVk;
}
else if (queryVk->isAnySamplesConservativeQuery())
{
ASSERT(mActiveQueryAnySamplesConservative == nullptr);
mActiveQueryAnySamplesConservative = queryVk;
}
else
{
UNREACHABLE();
queryVk->getQueryHelper()->beginRenderPassQuery(this, mRenderPassCommandBuffer);
}
mRenderPassQueries[queryVk->getType()] = queryVk;
}
void ContextVk::endOcclusionQuery(QueryVk *queryVk)
void ContextVk::endRenderPassQuery(QueryVk *queryVk)
{
if (mRenderPassCommands->started() && mRenderPassCommandBuffer)
{
queryVk->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer);
}
if (queryVk->isAnySamplesQuery())
{
ASSERT(mActiveQueryAnySamples == queryVk);
mActiveQueryAnySamples = nullptr;
}
else if (queryVk->isAnySamplesConservativeQuery())
{
ASSERT(mActiveQueryAnySamplesConservative == queryVk);
mActiveQueryAnySamplesConservative = nullptr;
}
else
{
UNREACHABLE();
queryVk->getQueryHelper()->endRenderPassQuery(this, mRenderPassCommandBuffer);
}
mRenderPassQueries[queryVk->getType()] = nullptr;
}
angle::Result ContextVk::pauseOcclusionQueryIfActive()
angle::Result ContextVk::pauseRenderPassQueryIfActive()
{
if (mRenderPassCommandBuffer == nullptr)
{
return angle::Result::Continue;
}
if (mActiveQueryAnySamples)
{
mActiveQueryAnySamples->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer);
ANGLE_TRY(mActiveQueryAnySamples->stashQueryHelper(this));
}
if (mActiveQueryAnySamplesConservative)
for (QueryVk *activeQuery : mRenderPassQueries)
{
mActiveQueryAnySamplesConservative->getQueryHelper()->endOcclusionQuery(
this, mRenderPassCommandBuffer);
ANGLE_TRY(mActiveQueryAnySamplesConservative->stashQueryHelper(this));
if (activeQuery)
{
activeQuery->getQueryHelper()->endRenderPassQuery(this, mRenderPassCommandBuffer);
ANGLE_TRY(activeQuery->stashQueryHelper(this));
}
}
return angle::Result::Continue;
}
angle::Result ContextVk::resumeOcclusionQueryIfActive()
void ContextVk::resumeRenderPassQueryIfActive()
{
if (mActiveQueryAnySamples)
{
mActiveQueryAnySamples->getQueryHelper()->beginOcclusionQuery(this,
mRenderPassCommandBuffer);
}
if (mActiveQueryAnySamplesConservative)
for (QueryVk *activeQuery : mRenderPassQueries)
{
mActiveQueryAnySamplesConservative->getQueryHelper()->beginOcclusionQuery(
this, mRenderPassCommandBuffer);
if (activeQuery)
{
activeQuery->getQueryHelper()->beginRenderPassQuery(this, mRenderPassCommandBuffer);
}
}
return angle::Result::Continue;
}
bool ContextVk::isRobustResourceInitEnabled() const
......
......@@ -536,11 +536,11 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
bool isRobustResourceInitEnabled() const;
// occlusion query
void beginOcclusionQuery(QueryVk *queryVk);
void endOcclusionQuery(QueryVk *queryVk);
void beginRenderPassQuery(QueryVk *queryVk);
void endRenderPassQuery(QueryVk *queryVk);
angle::Result pauseOcclusionQueryIfActive();
angle::Result resumeOcclusionQueryIfActive();
angle::Result pauseRenderPassQueryIfActive();
void resumeRenderPassQueryIfActive();
void updateOverlayOnPresent();
void addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer);
......@@ -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
// we'd instead share a single set of pools between the share groups.
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.
DirtyBits mGraphicsDirtyBits;
......@@ -910,10 +913,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
ProgramPipelineVk *mProgramPipeline;
ProgramExecutableVk *mExecutable;
// occlusion query
QueryVk *mActiveQueryAnySamples;
QueryVk *mActiveQueryAnySamplesConservative;
// The offset we had the last time we bound the index buffer.
const GLvoid *mLastIndexBufferOffset;
gl::DrawElementsType mCurrentDrawElementsType;
......
......@@ -41,24 +41,22 @@ void QueryVk::onDestroy(const gl::Context *context)
angle::Result QueryVk::stashQueryHelper(ContextVk *contextVk)
{
ASSERT(isOcclusionQuery());
ASSERT(isRenderPassQuery(contextVk));
mStashedQueryHelpers.emplace_back(std::move(mQueryHelper));
mQueryHelper.deinit();
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
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)
{
uint64_t v;
vk::QueryResult v(getQueryResultCount());
ANGLE_TRY(query.getUint64Result(contextVk, &v));
total += v;
*result += v;
}
mStashedQueryHelpers.clear();
*result = total;
return angle::Result::Continue;
}
......@@ -68,12 +66,16 @@ angle::Result QueryVk::begin(const gl::Context *context)
mCachedResultValid = false;
// Transform feedback query is a handled by a CPU-calculated value when emulated.
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
if (isTransformFeedbackQuery())
{
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())
......@@ -81,7 +83,7 @@ angle::Result QueryVk::begin(const gl::Context *context)
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
// 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)
mQueryHelper.deinit();
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
}
contextVk->beginOcclusionQuery(this);
contextVk->beginRenderPassQuery(this);
}
else if (getType() == gl::QueryType::TimeElapsed)
{
......@@ -120,12 +122,18 @@ angle::Result QueryVk::end(const gl::Context *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;
// There could be transform feedback in progress, so add the primitives drawn so far from
// the current transform feedback object.
// There could be transform feedback in progress, so add the primitives drawn so far
// from the current transform feedback object.
gl::TransformFeedback *transformFeedback =
context->getState().getCurrentTransformFeedback();
if (transformFeedback)
......@@ -133,11 +141,6 @@ angle::Result QueryVk::end(const gl::Context *context)
mCachedResult += transformFeedback->getPrimitivesDrawn();
}
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)
{
......@@ -268,25 +271,23 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
ANGLE_TRY(finishRunningCommands(contextVk));
}
vk::QueryResult result(getQueryResultCount());
if (wait)
{
ANGLE_TRY(mQueryHelper.getUint64Result(contextVk, &mCachedResult));
uint64_t v;
ANGLE_TRY(retrieveStashedQueryResult(contextVk, &v));
mCachedResult += v;
ANGLE_TRY(mQueryHelper.getUint64Result(contextVk, &result));
ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
}
else
{
bool available = false;
ANGLE_TRY(mQueryHelper.getUint64ResultNonBlocking(contextVk, &mCachedResult, &available));
ANGLE_TRY(mQueryHelper.getUint64ResultNonBlocking(contextVk, &result, &available));
if (!available)
{
// If the results are not ready, do nothing. mCachedResultValid remains false.
return angle::Result::Continue;
}
uint64_t v;
ANGLE_TRY(retrieveStashedQueryResult(contextVk, &v));
mCachedResult += v;
ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
}
double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod;
......@@ -297,24 +298,26 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
case gl::QueryType::AnySamples:
case gl::QueryType::AnySamplesConservative:
// OpenGL query result in these cases is binary
mCachedResult = !!mCachedResult;
mCachedResult = !!result.getResult();
break;
case gl::QueryType::Timestamp:
mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod);
mCachedResult = static_cast<uint64_t>(result.getResult() * timestampPeriod);
break;
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
// result of begin query must be available too.
ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &mCachedResult));
mCachedResult = timeElapsedEnd - mCachedResult;
mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod);
ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &timeElapsedBegin));
uint64_t delta = result.getResult() - timeElapsedBegin.getResult();
mCachedResult = static_cast<uint64_t>(delta * timestampPeriod);
break;
}
case gl::QueryType::TransformFeedbackPrimitivesWritten:
mCachedResult = result.getResult();
break;
default:
UNREACHABLE();
break;
......@@ -363,4 +366,16 @@ void QueryVk::onTransformFeedbackEnd(GLsizeiptr 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
......@@ -37,7 +37,8 @@ class QueryVk : public QueryImpl
void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn);
vk::QueryHelper *getQueryHelper() { return &mQueryHelper; }
angle::Result stashQueryHelper(ContextVk *contextVk);
angle::Result retrieveStashedQueryResult(ContextVk *contextVk, uint64_t *result);
bool isRenderPassQuery(ContextVk *contextVk) const;
private:
angle::Result getResult(const gl::Context *context, bool wait);
......@@ -45,6 +46,8 @@ class QueryVk : public QueryImpl
bool isUsedInRecordedCommands() const;
bool isCurrentlyInUse(Serial lastCompletedSerial) const;
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).
vk::QueryHelper mQueryHelper;
......
......@@ -1598,10 +1598,10 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
sizeof(shaderParams), commandBuffer));
// 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->draw(3, 0);
ANGLE_TRY(contextVk->resumeOcclusionQueryIfActive());
contextVk->resumeRenderPassQueryIfActive();
// Make sure what's bound here is correctly reverted on the next draw.
contextVk->invalidateGraphicsPipelineAndDescriptorSets();
......
......@@ -2487,14 +2487,14 @@ angle::Result QueryHelper::endQuery(ContextVk *contextVk)
return angle::Result::Continue;
}
void QueryHelper::beginOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
void QueryHelper::beginRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
{
const QueryPool &queryPool = getQueryPool();
renderPassCommandBuffer->queueResetQueryPool(queryPool.getHandle(), mQuery, 1);
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);
......@@ -2537,7 +2537,7 @@ void QueryHelper::writeTimestamp(ContextVk *contextVk, CommandBuffer *commandBuf
}
angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
uint64_t *resultOut,
QueryResult *resultOut,
bool *availableOut)
{
ASSERT(valid());
......@@ -2549,8 +2549,9 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
{
VkDevice device = contextVk->getDevice();
constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
result = getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t), resultOut,
sizeof(uint64_t), kFlags);
result =
getQueryPool().getResults(device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags);
}
else
{
......@@ -2571,15 +2572,16 @@ angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
return angle::Result::Continue;
}
angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, uint64_t *resultOut)
angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
{
ASSERT(valid());
if (mUse.getSerial().valid())
{
VkDevice device = contextVk->getDevice();
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),
resultOut, sizeof(uint64_t), kFlags));
ANGLE_VK_TRY(contextVk, getQueryPool().getResults(
device, mQuery, 1, resultOut->getDataSize(),
resultOut->getPointerToResults(), sizeof(uint64_t), kFlags));
}
else
{
......
......@@ -380,8 +380,9 @@ class DynamicallyGrowingPool : angle::NonCopyable
// another is created. The query pools live permanently, but are recycled as indices get freed.
// These are arbitrary default sizes for query pools.
constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64;
constexpr uint32_t kDefaultTimestampQueryPoolSize = 64;
constexpr uint32_t kDefaultOcclusionQueryPoolSize = 64;
constexpr uint32_t kDefaultTimestampQueryPoolSize = 64;
constexpr uint32_t kDefaultTransformFeedbackQueryPoolSize = 128;
class QueryHelper;
......@@ -406,6 +407,27 @@ class DynamicQueryPool final : public DynamicallyGrowingPool<QueryPool>
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.
// 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
......@@ -435,8 +457,8 @@ class QueryHelper final : public Resource
// for occlusion query
// Must resetQueryPool outside of RenderPass before beginning occlusion query.
void resetQueryPool(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
void beginOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
void endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
void beginRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
void endRenderPassQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer);
angle::Result flushAndWriteTimestamp(ContextVk *contextVk);
// When syncing gpu/cpu time, main thread accesses primary directly
......@@ -445,9 +467,9 @@ class QueryHelper final : public Resource
void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
angle::Result getUint64ResultNonBlocking(ContextVk *contextVk,
uint64_t *resultOut,
QueryResult *resultOut,
bool *availableOut);
angle::Result getUint64Result(ContextVk *contextVk, uint64_t *resultOut);
angle::Result getUint64Result(ContextVk *contextVk, QueryResult *resultOut);
private:
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