Add validation for GPURender/ComputePassTimestampLocation
Disallow duplicate location in timestampWrites in a render/compute pass
to match WebGPU SPEC.
Bug: dawn:1250
Change-Id: Id9e3b54530d37ffc0c00aa15c23312bb1ea30d00
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90460
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp
index 9f2a5d1..51fee4b 100644
--- a/src/dawn/native/CommandEncoder.cpp
+++ b/src/dawn/native/CommandEncoder.cpp
@@ -14,6 +14,7 @@
#include "dawn/native/CommandEncoder.h"
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -414,6 +415,30 @@
return {};
}
+MaybeError ValidateTimestampLocationOnRenderPass(
+ wgpu::RenderPassTimestampLocation location,
+ const std::unordered_set<wgpu::RenderPassTimestampLocation>& writtenLocations) {
+ DAWN_TRY(ValidateRenderPassTimestampLocation(location));
+
+ DAWN_INVALID_IF(writtenLocations.find(location) != writtenLocations.end(),
+ "There are two same RenderPassTimestampLocation %u in a render pass.",
+ location);
+
+ return {};
+}
+
+MaybeError ValidateTimestampLocationOnComputePass(
+ wgpu::ComputePassTimestampLocation location,
+ const std::unordered_set<wgpu::ComputePassTimestampLocation>& writtenLocations) {
+ DAWN_TRY(ValidateComputePassTimestampLocation(location));
+
+ DAWN_INVALID_IF(writtenLocations.find(location) != writtenLocations.end(),
+ "There are two same ComputePassTimestampLocation %u in a compute pass.",
+ location);
+
+ return {};
+}
+
MaybeError ValidateRenderPassDescriptor(DeviceBase* device,
const RenderPassDescriptor* descriptor,
uint32_t* width,
@@ -465,15 +490,22 @@
// not validated and encoded one by one, but encoded together after passing the
// validation.
QueryAvailabilityMap usedQueries;
+ // TODO(https://crbug.com/dawn/1452):
+ // 1. Add an enum that's TimestampLocationMask and has bit values.
+ // 2. Add a function with a switch that converts from one to the other.
+ // 3. type alias the ityp::bitset for that to call it TimestampLocationSet.
+ // 4. Use it here.
+ std::unordered_set<wgpu::RenderPassTimestampLocation> writtenLocations;
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);
+ DAWN_TRY_CONTEXT(ValidateTimestampLocationOnRenderPass(
+ descriptor->timestampWrites[i].location, writtenLocations),
+ "validating location of timestampWrites[%u].", i);
+ writtenLocations.insert(descriptor->timestampWrites[i].location);
auto checkIt = usedQueries.find(querySet);
DAWN_INVALID_IF(checkIt != usedQueries.end() && checkIt->second[queryIndex],
@@ -503,14 +535,21 @@
if (descriptor->timestampWriteCount > 0) {
DAWN_ASSERT(descriptor->timestampWrites != nullptr);
+ // TODO(https://crbug.com/dawn/1452):
+ // 1. Add an enum that's TimestampLocationMask and has bit values.
+ // 2. Add a function with a switch that converts from one to the other.
+ // 3. type alias the ityp::bitset for that to call it TimestampLocationSet.
+ // 4. Use it here.
+ std::unordered_set<wgpu::ComputePassTimestampLocation> writtenLocations;
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);
+ DAWN_TRY_CONTEXT(ValidateTimestampLocationOnComputePass(
+ descriptor->timestampWrites[i].location, writtenLocations),
+ "validating location of timestampWrites[%u].", i);
+ writtenLocations.insert(descriptor->timestampWrites[i].location);
}
}
diff --git a/src/dawn/tests/unittests/validation/QueryValidationTests.cpp b/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
index 04899ad..fdc863e 100644
--- a/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/QueryValidationTests.cpp
@@ -352,13 +352,23 @@
encoder.Finish();
}
- // Success to write timestamps at same location of compute pass
+ // Success to write timestamps at same location of different compute pass
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ EncodeComputePassWithTimestampWrites(
+ encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning}});
+ EncodeComputePassWithTimestampWrites(
+ encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning}});
+ encoder.Finish();
+ }
+
+ // Fail to write timestamps at same location of a compute pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeComputePassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
{querySet, 1, wgpu::ComputePassTimestampLocation::Beginning}});
- encoder.Finish();
+ ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps at invalid location of compute pass
@@ -427,7 +437,8 @@
ASSERT_DEVICE_ERROR(encoder.Finish());
}
- // Success to write timestamps to the same query index twice on different render pass
+ // Success to write timestamps to the same query index and location twice on different render
+ // pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
@@ -449,13 +460,13 @@
ASSERT_DEVICE_ERROR(encoder.Finish());
}
- // Success to write timestamps at same location of render pass
+ // Fail to write timestamps at same location of a render pass
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeRenderPassWithTimestampWrites(
encoder, {{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
{querySet, 1, wgpu::RenderPassTimestampLocation::Beginning}});
- encoder.Finish();
+ ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamps at invalid location of render pass