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:
parent
3f6bb08d00
commit
e2cbcc9565
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue