Query API: Record used query index in command encoder

- There are some methods need to know which query indexes are used in
encoders: endOcclusionQuery, endPipelineStatisticsQuery, resolveQuerySet.
- On Vulkan, we also need to use the used query indexes to reset each
queries between uses. And because the reset command must be called
outside render pass, we need to check whether a query index is writen
twice on command encoder and render/compute encoders.
- Add validation on writeTimestamp for duplicate writes at same index.

Bug: dawn:434
Change-Id: I6d00dd91e565d960246b6d01ad434d2d5c095deb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/27561
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
Hao Li 2020-10-21 08:38:31 +00:00 committed by Commit Bot service account
parent 3f6bb08d00
commit e2cbcc9565
7 changed files with 101 additions and 5 deletions

View File

@ -467,6 +467,24 @@ namespace dawn_native {
mUsedQuerySets.insert(querySet); mUsedQuerySets.insert(querySet);
} }
void CommandEncoder::TrackUsedQueryIndex(QuerySetBase* querySet, uint32_t queryIndex) {
UsedQueryMap::iterator it = mUsedQueryIndices.find(querySet);
if (it != mUsedQueryIndices.end()) {
// Record index on existing query set
std::vector<bool>& queryIndices = it->second;
queryIndices[queryIndex] = 1;
} else {
// Record index on new query set
std::vector<bool> queryIndices(querySet->GetQueryCount(), 0);
queryIndices[queryIndex] = 1;
mUsedQueryIndices.insert({querySet, std::move(queryIndices)});
}
}
const UsedQueryMap& CommandEncoder::GetUsedQueryIndices() const {
return mUsedQueryIndices;
}
// Implementation of the API's command recording methods // Implementation of the API's command recording methods
ComputePassEncoder* CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) { ComputePassEncoder* CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
@ -850,10 +868,12 @@ namespace dawn_native {
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet)); DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex)); DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex, GetUsedQueryIndices()));
TrackUsedQuerySet(querySet); TrackUsedQuerySet(querySet);
} }
TrackUsedQueryIndex(querySet, queryIndex);
WriteTimestampCmd* cmd = WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp); allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet; cmd->querySet = querySet;

View File

@ -22,12 +22,15 @@
#include "dawn_native/ObjectBase.h" #include "dawn_native/ObjectBase.h"
#include "dawn_native/PassResourceUsage.h" #include "dawn_native/PassResourceUsage.h"
#include <map>
#include <string> #include <string>
namespace dawn_native { namespace dawn_native {
struct BeginRenderPassCmd; struct BeginRenderPassCmd;
using UsedQueryMap = std::map<QuerySetBase*, std::vector<bool>>;
class CommandEncoder final : public ObjectBase { class CommandEncoder final : public ObjectBase {
public: public:
CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor); CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor);
@ -36,6 +39,8 @@ namespace dawn_native {
CommandBufferResourceUsage AcquireResourceUsages(); CommandBufferResourceUsage AcquireResourceUsages();
void TrackUsedQuerySet(QuerySetBase* querySet); void TrackUsedQuerySet(QuerySetBase* querySet);
void TrackUsedQueryIndex(QuerySetBase* querySet, uint32_t queryIndex);
const UsedQueryMap& GetUsedQueryIndices() const;
// Dawn API // Dawn API
ComputePassEncoder* BeginComputePass(const ComputePassDescriptor* descriptor); ComputePassEncoder* BeginComputePass(const ComputePassDescriptor* descriptor);
@ -77,6 +82,7 @@ namespace dawn_native {
std::set<BufferBase*> mTopLevelBuffers; std::set<BufferBase*> mTopLevelBuffers;
std::set<TextureBase*> mTopLevelTextures; std::set<TextureBase*> mTopLevelTextures;
std::set<QuerySetBase*> mUsedQuerySets; std::set<QuerySetBase*> mUsedQuerySets;
UsedQueryMap mUsedQueryIndices;
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -351,7 +351,9 @@ namespace dawn_native {
return {}; return {};
} }
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex) { MaybeError ValidateTimestampQuery(QuerySetBase* querySet,
uint32_t queryIndex,
const UsedQueryMap& usedQueryIndices) {
if (querySet->GetQueryType() != wgpu::QueryType::Timestamp) { if (querySet->GetQueryType() != wgpu::QueryType::Timestamp) {
return DAWN_VALIDATION_ERROR("The query type of query set must be Timestamp"); return DAWN_VALIDATION_ERROR("The query type of query set must be Timestamp");
} }
@ -360,6 +362,15 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Query index exceeds the number of queries in query set"); return DAWN_VALIDATION_ERROR("Query index exceeds the number of queries in query set");
} }
UsedQueryMap::const_iterator it = usedQueryIndices.find(querySet);
if (it != usedQueryIndices.end()) {
// Get the used query index records
const std::vector<bool>& queryIndices = it->second;
if (queryIndices[queryIndex] == 1) {
return DAWN_VALIDATION_ERROR("Duplicated query index writen");
}
}
return {}; return {};
} }

View File

@ -19,6 +19,7 @@
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
#include "dawn_native/Texture.h" #include "dawn_native/Texture.h"
#include <map>
#include <vector> #include <vector>
namespace dawn_native { namespace dawn_native {
@ -29,6 +30,8 @@ namespace dawn_native {
struct PassResourceUsage; struct PassResourceUsage;
struct TexelBlockInfo; struct TexelBlockInfo;
using UsedQueryMap = std::map<QuerySetBase*, std::vector<bool>>;
MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize); MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize);
MaybeError ValidateFinalDebugGroupStackSize(uint64_t debugGroupStackSize); MaybeError ValidateFinalDebugGroupStackSize(uint64_t debugGroupStackSize);
@ -39,7 +42,9 @@ namespace dawn_native {
MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage); MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex); MaybeError ValidateTimestampQuery(QuerySetBase* querySet,
uint32_t queryIndex,
const UsedQueryMap& usedQueryIndices);
ResultOrError<uint64_t> ComputeRequiredBytesInCopy(const TexelBlockInfo& blockInfo, ResultOrError<uint64_t> ComputeRequiredBytesInCopy(const TexelBlockInfo& blockInfo,
const Extent3D& copySize, const Extent3D& copySize,

View File

@ -106,10 +106,13 @@ namespace dawn_native {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet)); DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex)); DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex,
mCommandEncoder->GetUsedQueryIndices()));
mCommandEncoder->TrackUsedQuerySet(querySet); mCommandEncoder->TrackUsedQuerySet(querySet);
} }
mCommandEncoder->TrackUsedQueryIndex(querySet, queryIndex);
WriteTimestampCmd* cmd = WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp); allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet; cmd->querySet = querySet;

View File

@ -180,10 +180,13 @@ namespace dawn_native {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet)); DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex)); DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex,
mCommandEncoder->GetUsedQueryIndices()));
mCommandEncoder->TrackUsedQuerySet(querySet); mCommandEncoder->TrackUsedQuerySet(querySet);
} }
mCommandEncoder->TrackUsedQueryIndex(querySet, queryIndex);
WriteTimestampCmd* cmd = WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp); allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet; cmd->querySet = querySet;

View File

@ -185,6 +185,14 @@ TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Fail to write timestamp to the same index twice on command encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
encoder.WriteTimestamp(timestampQuerySet, 0);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set // Fail to submit timestamp query with a destroyed query set
{ {
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder(); wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
@ -241,6 +249,26 @@ TEST_F(TimestampQueryValidationTest, WriteTimestampOnComputePassEncoder) {
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Fail to write timestamp to the same index twice on compute encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 0);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamp to the same index twice on command encoder and compute encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set // Fail to submit timestamp query with a destroyed query set
{ {
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder(); wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
@ -301,6 +329,26 @@ TEST_F(TimestampQueryValidationTest, WriteTimestampOnRenderPassEncoder) {
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Fail to write timestamp to the same index twice on command encoder and render encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamp to the same index twice on command encoder and render encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set // Fail to submit timestamp query with a destroyed query set
{ {
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder(); wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();