Add timestampWrites on render/compute passes

The timestampWrites in render/compute pass descriptor store the
timestamps at the beginning and end of passes, this requires validating
all timestampWrite members in BeginXxxPass and inserting the
timestampWrite cmd as close as possible to the BeginXxxPass and
EndXxxPass. To do that, we first record only the querySets and
queryIndexes that need to be used in BeginXxxPassCmd and EndXxxPassCmd,
then insert timestampWrite cmd after the native BeginXxxPass and before
the native EndXxxPass in backends.

This CL adds timestampWrites in render/compute pass descriptor
including the validation and tests first.

Implement timestampWrites in backends in following CL.

Bug: dawn:1250

Change-Id: I39b50975aa03cc1afe7a736c3b39df284f54d163
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/82100
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Li Hao 2022-03-05 01:22:52 +00:00 committed by Dawn LUCI CQ
parent 67af844346
commit 131c422489
10 changed files with 368 additions and 35 deletions

View File

@ -750,8 +750,8 @@
"extensible": "in",
"members": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
{"name": "timestamp write count", "type": "uint32_t", "default": 0, "tags": ["upstream"]},
{"name": "timestamp writes", "type": "compute pass timestamp write", "annotation": "const*", "length": "timestamp write count", "tags": ["upstream"]}
{"name": "timestamp write count", "type": "uint32_t", "default": 0},
{"name": "timestamp writes", "type": "compute pass timestamp write", "annotation": "const*", "length": "timestamp write count"}
]
},
"compute pass encoder": {
@ -843,7 +843,6 @@
},
"compute pass timestamp location": {
"category": "enum",
"tags": ["upstream"],
"values": [
{"value": 0, "name": "beginning"},
{"value": 1, "name": "end"}
@ -851,7 +850,6 @@
},
"compute pass timestamp write": {
"category": "structure",
"tags": ["upstream"],
"members": [
{"name": "query set", "type": "query set"},
{"name": "query index", "type": "uint32_t"},
@ -1839,8 +1837,8 @@
{"name": "color attachments", "type": "render pass color attachment", "annotation": "const*", "length": "color attachment count"},
{"name": "depth stencil attachment", "type": "render pass depth stencil attachment", "annotation": "const*", "optional": true},
{"name": "occlusion query set", "type": "query set", "optional": true},
{"name": "timestamp write count", "type": "uint32_t", "default": 0, "tags": ["upstream"]},
{"name": "timestamp writes", "type": "render pass timestamp write", "annotation": "const*", "length": "timestamp write count", "tags": ["upstream"]}
{"name": "timestamp write count", "type": "uint32_t", "default": 0},
{"name": "timestamp writes", "type": "render pass timestamp write", "annotation": "const*", "length": "timestamp write count"}
]
},
"render pass encoder": {
@ -2016,7 +2014,6 @@
},
"render pass timestamp location": {
"category": "enum",
"tags": ["upstream"],
"values": [
{"value": 0, "name": "beginning"},
{"value": 1, "name": "end"}
@ -2024,7 +2021,6 @@
},
"render pass timestamp write": {
"category": "structure",
"tags": ["upstream"],
"members": [
{"name": "query set", "type": "query set"},
{"name": "query index", "type": "uint32_t"},

View File

@ -36,9 +36,6 @@
#include "dawn/platform/DawnPlatform.h"
#include "dawn/platform/tracing/TraceEvent.h"
#include <cmath>
#include <map>
namespace dawn::native {
namespace {
@ -416,6 +413,38 @@ namespace dawn::native {
descriptor->occlusionQuerySet->GetQueryType(), wgpu::QueryType::Occlusion);
}
if (descriptor->timestampWriteCount > 0) {
DAWN_ASSERT(descriptor->timestampWrites != nullptr);
// Record the query set and query index used on render passes for validating query
// index overwrite. The TrackQueryAvailability of
// RenderPassResourceUsageTracker is not used here because the timestampWrites are
// not validated and encoded one by one, but encoded together after passing the
// validation.
QueryAvailabilityMap usedQueries;
for (uint32_t i = 0; i < descriptor->timestampWriteCount; ++i) {
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
DAWN_ASSERT(querySet != nullptr);
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
DAWN_TRY_CONTEXT(ValidateTimestampQuery(device, querySet, queryIndex),
"validating querySet and queryIndex of timestampWrites[%u].",
i);
DAWN_TRY_CONTEXT(ValidateRenderPassTimestampLocation(
descriptor->timestampWrites[i].location),
"validating location of timestampWrites[%u].", i);
auto checkIt = usedQueries.find(querySet);
DAWN_INVALID_IF(checkIt != usedQueries.end() && checkIt->second[queryIndex],
"Query index %u of %s is written to twice in a render pass.",
queryIndex, querySet);
// Gets the iterator for that querySet or create a new vector of bool set to
// false if the querySet wasn't registered.
auto addIt = usedQueries.emplace(querySet, querySet->GetQueryCount()).first;
addIt->second[queryIndex] = true;
}
}
DAWN_INVALID_IF(descriptor->colorAttachmentCount == 0 &&
descriptor->depthStencilAttachment == nullptr,
"Render pass has no attachments.");
@ -425,6 +454,25 @@ namespace dawn::native {
MaybeError ValidateComputePassDescriptor(const DeviceBase* device,
const ComputePassDescriptor* descriptor) {
if (descriptor == nullptr) {
return {};
}
if (descriptor->timestampWriteCount > 0) {
DAWN_ASSERT(descriptor->timestampWrites != nullptr);
for (uint32_t i = 0; i < descriptor->timestampWriteCount; ++i) {
DAWN_ASSERT(descriptor->timestampWrites[i].querySet != nullptr);
DAWN_TRY_CONTEXT(
ValidateTimestampQuery(device, descriptor->timestampWrites[i].querySet,
descriptor->timestampWrites[i].queryIndex),
"validating querySet and queryIndex of timestampWrites[%u].", i);
DAWN_TRY_CONTEXT(ValidateComputePassTimestampLocation(
descriptor->timestampWrites[i].location),
"validating location of timestampWrites[%u].", i);
}
}
return {};
}
@ -606,12 +654,40 @@ namespace dawn::native {
const ComputePassDescriptor* descriptor) {
DeviceBase* device = GetDevice();
std::vector<TimestampWrite> timestampWritesAtBeginning;
std::vector<TimestampWrite> timestampWritesAtEnd;
bool success = mEncodingContext.TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
BeginComputePassCmd* cmd =
allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
if (descriptor == nullptr) {
return {};
}
// Split the timestampWrites used in BeginComputePassCmd and EndComputePassCmd
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
switch (descriptor->timestampWrites[i].location) {
case wgpu::ComputePassTimestampLocation::Beginning:
timestampWritesAtBeginning.push_back({querySet, queryIndex});
break;
case wgpu::ComputePassTimestampLocation::End:
timestampWritesAtEnd.push_back({querySet, queryIndex});
break;
default:
break;
}
TrackQueryAvailability(querySet, queryIndex);
}
cmd->timestampWrites = std::move(timestampWritesAtBeginning);
return {};
},
@ -623,8 +699,8 @@ namespace dawn::native {
descriptor = &defaultDescriptor;
}
ComputePassEncoder* passEncoder =
new ComputePassEncoder(device, descriptor, this, &mEncodingContext);
ComputePassEncoder* passEncoder = new ComputePassEncoder(
device, descriptor, this, &mEncodingContext, std::move(timestampWritesAtEnd));
mEncodingContext.EnterPass(passEncoder);
return passEncoder;
}
@ -642,6 +718,8 @@ namespace dawn::native {
bool depthReadOnly = false;
bool stencilReadOnly = false;
Ref<AttachmentState> attachmentState;
std::vector<TimestampWrite> timestampWritesAtBeginning;
std::vector<TimestampWrite> timestampWritesAtEnd;
bool success = mEncodingContext.TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
@ -659,6 +737,28 @@ namespace dawn::native {
cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
attachmentState = cmd->attachmentState;
// Split the timestampWrites used in BeginRenderPassCmd and EndRenderPassCmd
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
switch (descriptor->timestampWrites[i].location) {
case wgpu::RenderPassTimestampLocation::Beginning:
timestampWritesAtBeginning.push_back({querySet, queryIndex});
break;
case wgpu::RenderPassTimestampLocation::End:
timestampWritesAtEnd.push_back({querySet, queryIndex});
break;
default:
break;
}
TrackQueryAvailability(querySet, queryIndex);
// Track the query availability with true on render pass again for rewrite
// validation and query reset on Vulkan
usageTracker.TrackQueryAvailability(querySet, queryIndex);
}
for (ColorAttachmentIndex index :
IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
uint8_t i = static_cast<uint8_t>(index);
@ -747,6 +847,8 @@ namespace dawn::native {
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
cmd->timestampWrites = std::move(timestampWritesAtBeginning);
return {};
},
"encoding %s.BeginRenderPass(%s).", this, descriptor);
@ -754,7 +856,7 @@ namespace dawn::native {
if (success) {
RenderPassEncoder* passEncoder = new RenderPassEncoder(
device, descriptor, this, &mEncodingContext, std::move(usageTracker),
std::move(attachmentState), descriptor->occlusionQuerySet, width, height,
std::move(attachmentState), std::move(timestampWritesAtEnd), width, height,
depthReadOnly, stencilReadOnly);
mEncodingContext.EnterPass(passEncoder);
return passEncoder;
@ -1183,8 +1285,7 @@ namespace dawn::native {
this,
[&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
DAWN_TRY(ValidateTimestampQuery(GetDevice(), querySet, queryIndex));
}
TrackQueryAvailability(querySet, queryIndex);

View File

@ -62,7 +62,11 @@ namespace dawn::native {
return {};
}
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex) {
MaybeError ValidateTimestampQuery(const DeviceBase* device,
const QuerySetBase* querySet,
uint32_t queryIndex) {
DAWN_TRY(device->ValidateObject(querySet));
DAWN_INVALID_IF(querySet->GetQueryType() != wgpu::QueryType::Timestamp,
"The type of %s is not %s.", querySet, wgpu::QueryType::Timestamp);

View File

@ -29,7 +29,9 @@ namespace dawn::native {
MaybeError ValidateSyncScopeResourceUsage(const SyncScopeResourceUsage& usage);
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
MaybeError ValidateTimestampQuery(const DeviceBase* device,
const QuerySetBase* querySet,
uint32_t queryIndex);
MaybeError ValidateWriteBuffer(const DeviceBase* device,
const BufferBase* buffer,

View File

@ -68,7 +68,14 @@ namespace dawn::native {
WriteTimestamp,
};
struct BeginComputePassCmd {};
struct TimestampWrite {
Ref<QuerySetBase> querySet;
uint32_t queryIndex;
};
struct BeginComputePassCmd {
std::vector<TimestampWrite> timestampWrites;
};
struct BeginOcclusionQueryCmd {
Ref<QuerySetBase> querySet;
@ -106,6 +113,7 @@ namespace dawn::native {
uint32_t height;
Ref<QuerySetBase> occlusionQuerySet;
std::vector<TimestampWrite> timestampWrites;
};
struct BufferCopy {
@ -184,14 +192,18 @@ namespace dawn::native {
uint64_t indirectOffset;
};
struct EndComputePassCmd {};
struct EndComputePassCmd {
std::vector<TimestampWrite> timestampWrites;
};
struct EndOcclusionQueryCmd {
Ref<QuerySetBase> querySet;
uint32_t queryIndex;
};
struct EndRenderPassCmd {};
struct EndRenderPassCmd {
std::vector<TimestampWrite> timestampWrites;
};
struct ExecuteBundlesCmd {
uint32_t count;

View File

@ -113,9 +113,11 @@ namespace dawn::native {
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
const ComputePassDescriptor* descriptor,
CommandEncoder* commandEncoder,
EncodingContext* encodingContext)
EncodingContext* encodingContext,
std::vector<TimestampWrite> timestampWritesAtEnd)
: ProgrammableEncoder(device, descriptor->label, encodingContext),
mCommandEncoder(commandEncoder) {
mCommandEncoder(commandEncoder),
mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
TrackInDevice();
}
@ -150,7 +152,11 @@ namespace dawn::native {
DAWN_TRY(ValidateProgrammableEncoderEnd());
}
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
EndComputePassCmd* cmd =
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
// The query availability has already been updated at the beginning of compute
// pass, and no need to do update here.
cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
return {};
},
@ -415,8 +421,7 @@ namespace dawn::native {
this,
[&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
DAWN_TRY(ValidateTimestampQuery(GetDevice(), querySet, queryIndex));
}
mCommandEncoder->TrackQueryAvailability(querySet, queryIndex);

View File

@ -30,7 +30,8 @@ namespace dawn::native {
ComputePassEncoder(DeviceBase* device,
const ComputePassDescriptor* descriptor,
CommandEncoder* commandEncoder,
EncodingContext* encodingContext);
EncodingContext* encodingContext,
std::vector<TimestampWrite> timestampWritesAtEnd);
static ComputePassEncoder* MakeError(DeviceBase* device,
CommandEncoder* commandEncoder,
@ -84,6 +85,8 @@ namespace dawn::native {
// For render and compute passes, the encoding context is borrowed from the command encoder.
// Keep a reference to the encoder to make sure the context isn't freed.
Ref<CommandEncoder> mCommandEncoder;
std::vector<TimestampWrite> mTimestampWritesAtEnd;
};
} // namespace dawn::native

View File

@ -54,7 +54,7 @@ namespace dawn::native {
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
QuerySetBase* occlusionQuerySet,
std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
@ -68,7 +68,8 @@ namespace dawn::native {
mCommandEncoder(commandEncoder),
mRenderTargetWidth(renderTargetWidth),
mRenderTargetHeight(renderTargetHeight),
mOcclusionQuerySet(occlusionQuerySet) {
mOcclusionQuerySet(descriptor->occlusionQuerySet),
mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
mUsageTracker = std::move(usageTracker);
TrackInDevice();
}
@ -121,7 +122,12 @@ namespace dawn::native {
this, mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
}
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
EndRenderPassCmd* cmd =
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
// The query availability has already been updated at the beginning of render
// pass, and no need to do update here.
cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
mCommandEncoder.Get(),
std::move(mIndirectDrawMetadata)));
@ -375,8 +381,7 @@ namespace dawn::native {
this,
[&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
DAWN_TRY(ValidateTimestampQuery(GetDevice(), querySet, queryIndex));
DAWN_TRY_CONTEXT(
ValidateQueryIndexOverwrite(querySet, queryIndex,
mUsageTracker.GetQueryAvailabilityMap()),

View File

@ -31,7 +31,7 @@ namespace dawn::native {
EncodingContext* encodingContext,
RenderPassResourceUsageTracker usageTracker,
Ref<AttachmentState> attachmentState,
QuerySetBase* occlusionQuerySet,
std::vector<TimestampWrite> timestampWritesAtEnd,
uint32_t renderTargetWidth,
uint32_t renderTargetHeight,
bool depthReadOnly,
@ -84,6 +84,8 @@ namespace dawn::native {
Ref<QuerySetBase> mOcclusionQuerySet;
uint32_t mCurrentOcclusionQueryIndex = 0;
bool mOcclusionQueryActive = false;
std::vector<TimestampWrite> mTimestampWritesAtEnd;
};
} // namespace dawn::native

View File

@ -238,6 +238,28 @@ class TimestampQueryValidationTest : public QuerySetValidationTest {
return adapter.CreateDevice(&descriptor);
}
void EncodeRenderPassWithTimestampWrites(
wgpu::CommandEncoder encoder,
const std::vector<wgpu::RenderPassTimestampWrite>& timestampWrites) {
DummyRenderPass renderPass(device);
renderPass.timestampWriteCount = timestampWrites.size();
renderPass.timestampWrites = timestampWrites.data();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.End();
}
void EncodeComputePassWithTimestampWrites(
wgpu::CommandEncoder encoder,
const std::vector<wgpu::ComputePassTimestampWrite>& timestampWrites) {
wgpu::ComputePassDescriptor descriptor;
descriptor.timestampWriteCount = timestampWrites.size();
descriptor.timestampWrites = timestampWrites.data();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&descriptor);
pass.End();
}
};
// Test creating query set with only the timestamp feature enabled.
@ -265,7 +287,7 @@ TEST_F(TimestampQueryValidationTest, UnnecessaryPipelineStatistics) {
}
// Test query set with type of timestamp is set to the occlusionQuerySet of RenderPassDescriptor.
TEST_F(TimestampQueryValidationTest, BeginRenderPassWithTimestampQuerySet) {
TEST_F(TimestampQueryValidationTest, SetOcclusionQueryWithTimestampQuerySet) {
// Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 1);
DummyRenderPass renderPass(device);
@ -276,6 +298,187 @@ TEST_F(TimestampQueryValidationTest, BeginRenderPassWithTimestampQuerySet) {
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test timestampWrites in compute pass descriptor
TEST_F(TimestampQueryValidationTest, TimestampWritesOnComputePass) {
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
// Success
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySet, 1, wgpu::ComputePassTimestampLocation::End}});
encoder.Finish();
}
// Fail to write timestamps to other type of query set
{
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{occlusionQuerySet, 0, wgpu::ComputePassTimestampLocation::Beginning}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to a query set created from another device
{
wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
wgpu::QuerySet querySetFromOtherDevice =
CreateQuerySet(otherDevice, wgpu::QueryType::Timestamp, 2);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySetFromOtherDevice, 1, wgpu::ComputePassTimestampLocation::End}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to the query index which exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 2, wgpu::ComputePassTimestampLocation::Beginning}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Success to write timestamps to the same query index twice on same compute pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySet, 0, wgpu::ComputePassTimestampLocation::End}});
encoder.Finish();
}
// Success to write timestamps at same location of compute pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySet, 1, wgpu::ComputePassTimestampLocation::Beginning}});
encoder.Finish();
}
// Fail to write timestamps at invalid location of compute pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, static_cast<wgpu::ComputePassTimestampLocation>(0xFFFFFFFF)}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to a destroyed query set
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySet, 1, wgpu::ComputePassTimestampLocation::End}});
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = device.GetQueue();
querySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test timestampWrites in render pass descriptor
TEST_F(TimestampQueryValidationTest, TimestampWritesOnRenderPass) {
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
// Success
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
encoder.Finish();
}
// Fail to write timestamps to other type of query set
{
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{occlusionQuerySet, 0, wgpu::RenderPassTimestampLocation::Beginning}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to a query set created from another device
{
wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
wgpu::QuerySet querySetFromOtherDevice =
CreateQuerySet(otherDevice, wgpu::QueryType::Timestamp, 2);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySetFromOtherDevice, 1, wgpu::RenderPassTimestampLocation::End}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to the query index which exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 2, wgpu::RenderPassTimestampLocation::Beginning}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Success to write timestamps to the same query index twice on different render pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
// Encodee other render pass
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
encoder.Finish();
}
// Fail to write timestamps to the same query index twice on same render pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 0, wgpu::RenderPassTimestampLocation::End}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Success to write timestamps at same location of render pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::Beginning}});
encoder.Finish();
}
// Fail to write timestamps at invalid location of render pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, static_cast<wgpu::RenderPassTimestampLocation>(0xFFFFFFFF)}});
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps to a destroyed query set
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = device.GetQueue();
querySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test write timestamp on command encoder
TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);