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:
parent
67af844346
commit
131c422489
12
dawn.json
12
dawn.json
|
@ -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"},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue