Update destinationOffset alignment to 256 in resolveQuerySet

From macOS 11+, Metal requires the minimum buffer offset alignment to be
256 bytes. We have updated the destinationOffset alignment of
resolveQuerySet to 256 in SPEC. This PR is changing the implementation.

Bug: dawn:940
Change-Id: Ie3c69d6a90adb76038dbac95ae2158a38da583f3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63762
Commit-Queue: Hao Li <hao.x.li@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Li Hao 2021-09-22 02:51:20 +00:00 committed by Dawn LUCI CQ
parent c9c366e825
commit a10f5331f2
5 changed files with 151 additions and 171 deletions

View File

@ -382,10 +382,9 @@ namespace dawn_native {
"set"); "set");
} }
// The destinationOffset must be a multiple of 8 bytes on D3D12 and Vulkan if (destinationOffset % 256 != 0) {
if (destinationOffset % 8 != 0) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The alignment offset into the destination buffer must be a multiple of 8 " "The alignment offset into the destination buffer must be a multiple of 256 "
"bytes"); "bytes");
} }

View File

@ -1362,9 +1362,9 @@ TEST_P(BufferZeroInitTest, ResolveQuerySet) {
// destinationOffset > 0 and destinationOffset + 8 * queryCount <= kBufferSize // destinationOffset > 0 and destinationOffset + 8 * queryCount <= kBufferSize
{ {
constexpr uint32_t kQueryCount = 1; constexpr uint32_t kQueryCount = 1;
constexpr uint64_t kDestinationOffset = 8u; constexpr uint64_t kDestinationOffset = 256u;
wgpu::Buffer destination = CreateBuffer(kBufferSize, kBufferUsage); wgpu::Buffer destination = CreateBuffer(kBufferSize + kDestinationOffset, kBufferUsage);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(querySet, 0); encoder.WriteTimestamp(querySet, 0);
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, kDestinationOffset); encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, kDestinationOffset);

View File

@ -31,6 +31,8 @@ class QueryTests : public DawnTest {
// Clear the content of the result buffer into 0xFFFFFFFF. // Clear the content of the result buffer into 0xFFFFFFFF.
constexpr static uint64_t kSentinelValue = ~uint64_t(0u); constexpr static uint64_t kSentinelValue = ~uint64_t(0u);
constexpr static uint64_t kZero = 0u; constexpr static uint64_t kZero = 0u;
constexpr uint64_t kMinDestinationOffset = 256;
constexpr uint64_t kMinCount = kMinDestinationOffset / sizeof(uint64_t);
class OcclusionExpectation : public detail::Expectation { class OcclusionExpectation : public detail::Expectation {
public: public:
@ -405,12 +407,15 @@ TEST_P(OcclusionQueryTests, ResolveToBufferWithOffset) {
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);
constexpr uint64_t kBufferSize = kQueryCount * sizeof(uint64_t) + kMinDestinationOffset;
constexpr uint64_t kCount = kQueryCount + kMinCount;
// Resolve the query result to first slot in the buffer, other slots should not be written. // Resolve the query result to first slot in the buffer, other slots should not be written.
{ {
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t)); wgpu::Buffer destination = CreateResolveBuffer(kBufferSize);
// Set sentinel values to check the query is resolved to the correct slot of the buffer. // Set sentinel values to check the query is resolved to the correct slot of the buffer.
std::vector<uint64_t> sentinelValues(kQueryCount, kSentinelValue); std::vector<uint64_t> sentinelValues(kCount, kSentinelValue);
queue.WriteBuffer(destination, 0, sentinelValues.data(), kQueryCount * sizeof(uint64_t)); queue.WriteBuffer(destination, 0, sentinelValues.data(), kBufferSize);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.ResolveQuerySet(querySet, 0, 1, destination, 0); encoder.ResolveQuerySet(querySet, 0, 1, destination, 0);
@ -419,23 +424,24 @@ TEST_P(OcclusionQueryTests, ResolveToBufferWithOffset) {
EXPECT_BUFFER(destination, 0, sizeof(uint64_t), EXPECT_BUFFER(destination, 0, sizeof(uint64_t),
new OcclusionExpectation(OcclusionExpectation::Result::NonZero)); new OcclusionExpectation(OcclusionExpectation::Result::NonZero));
EXPECT_BUFFER_U64_RANGE_EQ(&kSentinelValue, destination, sizeof(uint64_t), 1); EXPECT_BUFFER_U64_RANGE_EQ(sentinelValues.data(), destination, sizeof(uint64_t),
kCount - 1);
} }
// Resolve the query result to second slot in the buffer, the first one should not be written. // Resolve the query result to second slot in the buffer, the first one should not be written.
{ {
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t)); wgpu::Buffer destination = CreateResolveBuffer(kBufferSize);
// Set sentinel values to check the query is resolved to the correct slot of the buffer. // Set sentinel values to check the query is resolved to the correct slot of the buffer.
std::vector<uint64_t> sentinelValues(kQueryCount, kSentinelValue); std::vector<uint64_t> sentinelValues(kCount, kSentinelValue);
queue.WriteBuffer(destination, 0, sentinelValues.data(), kQueryCount * sizeof(uint64_t)); queue.WriteBuffer(destination, 0, sentinelValues.data(), kBufferSize);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.ResolveQuerySet(querySet, 0, 1, destination, sizeof(uint64_t)); encoder.ResolveQuerySet(querySet, 0, 1, destination, kMinDestinationOffset);
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);
EXPECT_BUFFER_U64_RANGE_EQ(&kSentinelValue, destination, 0, 1); EXPECT_BUFFER_U64_RANGE_EQ(sentinelValues.data(), destination, 0, kMinCount);
EXPECT_BUFFER(destination, sizeof(uint64_t), sizeof(uint64_t), EXPECT_BUFFER(destination, kMinDestinationOffset, sizeof(uint64_t),
new OcclusionExpectation(OcclusionExpectation::Result::NonZero)); new OcclusionExpectation(OcclusionExpectation::Result::NonZero));
} }
} }
@ -769,35 +775,44 @@ TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel()); DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
constexpr uint32_t kQueryCount = 2; constexpr uint32_t kQueryCount = 2;
constexpr uint64_t kZero = 0; constexpr uint64_t kBufferSize = kQueryCount * sizeof(uint64_t) + kMinDestinationOffset;
constexpr uint64_t kCount = kQueryCount + kMinCount;
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
// Resolve the query result to first slot in the buffer, other slots should not be written // Resolve the query result to first slot in the buffer, other slots should not be written
{ {
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t)); wgpu::Buffer destination = CreateResolveBuffer(kBufferSize);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(querySet, 0); encoder.WriteTimestamp(querySet, 0);
encoder.ResolveQuerySet(querySet, 0, 1, destination, 0); encoder.ResolveQuerySet(querySet, 0, 1, destination, 0);
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);
std::vector<uint64_t> zeros(kCount - 1, kZero);
EXPECT_BUFFER(destination, 0, sizeof(uint64_t), new TimestampExpectation); EXPECT_BUFFER(destination, 0, sizeof(uint64_t), new TimestampExpectation);
EXPECT_BUFFER_U64_RANGE_EQ(&kZero, destination, sizeof(uint64_t), 1); EXPECT_BUFFER_U64_RANGE_EQ(zeros.data(), destination, sizeof(uint64_t), kCount - 1);
} }
// Resolve the query result to the buffer with offset, the slots before the offset // Resolve the query result to the buffer with offset, the slots before the offset
// should not be written // should not be written
{ {
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t)); wgpu::Buffer destination = CreateResolveBuffer(kBufferSize);
// Set sentinel values to check the query is resolved to the correct slot of the buffer.
std::vector<uint64_t> sentinelValues(kCount, kZero);
queue.WriteBuffer(destination, 0, sentinelValues.data(), kBufferSize);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(querySet, 0); encoder.WriteTimestamp(querySet, 0);
encoder.ResolveQuerySet(querySet, 0, 1, destination, sizeof(uint64_t)); encoder.ResolveQuerySet(querySet, 0, 1, destination, kMinDestinationOffset);
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);
EXPECT_BUFFER_U64_RANGE_EQ(&kZero, destination, 0, 1); std::vector<uint64_t> zeros(kMinCount, kZero);
EXPECT_BUFFER(destination, sizeof(uint64_t), sizeof(uint64_t), new TimestampExpectation); EXPECT_BUFFER_U64_RANGE_EQ(zeros.data(), destination, 0, kMinCount);
EXPECT_BUFFER(destination, kMinDestinationOffset, sizeof(uint64_t),
new TimestampExpectation);
} }
} }
@ -809,17 +824,17 @@ TEST_P(TimestampQueryTests, ResolveTwiceToSameBuffer) {
// the issue is fixed. // the issue is fixed.
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel()); DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
constexpr uint32_t kQueryCount = 3; constexpr uint32_t kQueryCount = kMinCount + 2;
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t)); wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(querySet, 0); for (uint32_t i = 0; i < kQueryCount; i++) {
encoder.WriteTimestamp(querySet, 1); encoder.WriteTimestamp(querySet, i);
encoder.WriteTimestamp(querySet, 2); }
encoder.ResolveQuerySet(querySet, 0, 2, destination, 0); encoder.ResolveQuerySet(querySet, 0, kMinCount + 1, destination, 0);
encoder.ResolveQuerySet(querySet, 1, 2, destination, sizeof(uint64_t)); encoder.ResolveQuerySet(querySet, kMinCount, 2, destination, kMinDestinationOffset);
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);

View File

@ -555,7 +555,8 @@ TEST_F(ResolveQuerySetValidationTest, ResolveInvalidQuerySetAndIndexCount) {
// Test resolve query set with invalid query set, first query and query count // Test resolve query set with invalid query set, first query and query count
TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) { TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) {
constexpr uint32_t kQueryCount = 4; constexpr uint32_t kQueryCount = 4;
constexpr uint64_t kBufferSize = kQueryCount * sizeof(uint64_t); constexpr uint64_t kBufferSize =
(kQueryCount - 1) * sizeof(uint64_t) + 256 /*destinationOffset*/;
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, kQueryCount); wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, kQueryCount);
wgpu::Buffer destination = CreateBuffer(device, kBufferSize, wgpu::BufferUsage::QueryResolve); wgpu::Buffer destination = CreateBuffer(device, kBufferSize, wgpu::BufferUsage::QueryResolve);
@ -563,7 +564,7 @@ TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) {
// Success // Success
{ {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.ResolveQuerySet(querySet, 1, kQueryCount - 1, destination, 8); encoder.ResolveQuerySet(querySet, 1, kQueryCount - 1, destination, 256);
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = device.GetQueue(); wgpu::Queue queue = device.GetQueue();
@ -580,17 +581,17 @@ TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) {
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Fail to resolve query set to a buffer if offset is not a multiple of 8 bytes // Fail to resolve query set to a buffer if offset is not a multiple of 256 bytes
{ {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 4); encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 128);
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Fail to resolve query set to a buffer if the data size overflow the buffer // Fail to resolve query set to a buffer if the data size overflow the buffer
{ {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 8); encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 256);
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }

View File

@ -71,7 +71,101 @@ namespace {
} // anonymous namespace } // anonymous namespace
class QueryInternalShaderTests : public DawnTest {}; constexpr static uint64_t kSentinelValue = ~uint64_t(0u);
// A gpu frequency on Intel D3D12 (ticks/second)
constexpr uint64_t kGPUFrequency = 12000048u;
constexpr uint64_t kNsPerSecond = 1000000000u;
// Timestamp period in nanoseconds
constexpr float kPeriod = static_cast<float>(kNsPerSecond) / kGPUFrequency;
class QueryInternalShaderTests : public DawnTest {
protected:
// Original timestamp values in query set for testing
const std::vector<uint64_t> querySetValues = {
kSentinelValue, // garbage data which is not written at beginning
10079569507, // t0
10394415012, // t1
kSentinelValue, // garbage data which is not written between timestamps
11713454943, // t2
38912556941, // t3 (big value)
10080295766, // t4 (reset)
12159966783, // t5 (after reset)
12651224612, // t6
39872473956, // t7
};
const uint32_t kQueryCount = querySetValues.size();
// Timestamps available state
const std::vector<uint32_t> availabilities = {0, 1, 1, 0, 1, 1, 1, 1, 1, 1};
const std::vector<uint64_t> GetExpectedResults(const std::vector<uint64_t>& origin,
uint32_t start,
uint32_t firstQuery,
uint32_t queryCount) {
std::vector<uint64_t> expected(origin.begin(), origin.end());
for (size_t i = 0; i < queryCount; i++) {
if (availabilities[firstQuery + i] == 0) {
// Not a available timestamp, write 0
expected[start + i] = 0u;
} else {
// Maybe the timestamp * period is larger than the maximum of uint64, so cast the
// delta value to double (higher precision than float)
expected[start + i] =
static_cast<uint64_t>(static_cast<double>(origin[start + i]) * kPeriod);
}
}
return expected;
}
void RunTest(uint32_t firstQuery, uint32_t queryCount, uint32_t destinationOffset) {
ASSERT(destinationOffset % 256 == 0);
uint64_t size = queryCount * sizeof(uint64_t) + destinationOffset;
// The resolve buffer storing original timestamps and the converted values
wgpu::BufferDescriptor timestampsDesc;
timestampsDesc.size = size;
timestampsDesc.usage = wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc |
wgpu::BufferUsage::CopyDst;
wgpu::Buffer timestampsBuffer = device.CreateBuffer(&timestampsDesc);
// Set sentinel values to check the slots before the destination offset should not be
// converted
std::vector<uint64_t> timestampValues(size / sizeof(uint64_t), 1u);
uint32_t start = destinationOffset / sizeof(uint64_t);
for (uint32_t i = 0; i < queryCount; i++) {
timestampValues[start + i] = querySetValues[firstQuery + 1];
}
// Write sentinel values and orignal timestamps to timestamps buffer
queue.WriteBuffer(timestampsBuffer, 0, timestampValues.data(), size);
// The buffer indicating which values are available timestamps
wgpu::Buffer availabilityBuffer =
utils::CreateBufferFromData(device, availabilities.data(),
kQueryCount * sizeof(uint32_t), wgpu::BufferUsage::Storage);
// The params uniform buffer
dawn_native::TimestampParams params = {firstQuery, queryCount, destinationOffset, kPeriod};
wgpu::Buffer paramsBuffer = utils::CreateBufferFromData(device, &params, sizeof(params),
wgpu::BufferUsage::Uniform);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeConvertTimestampsToNanoseconds(encoder, timestampsBuffer, availabilityBuffer,
paramsBuffer);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
const std::vector<uint64_t> expected =
GetExpectedResults(timestampValues, start, firstQuery, queryCount);
EXPECT_BUFFER(timestampsBuffer, 0, size,
new InternalShaderExpectation(expected.data(), size / sizeof(uint64_t)));
}
private:
};
// Test the accuracy of timestamp compute shader which uses unsigned 32-bit integers to simulate // Test the accuracy of timestamp compute shader which uses unsigned 32-bit integers to simulate
// unsigned 64-bit integers (timestamps) multiplied by float (period). // unsigned 64-bit integers (timestamps) multiplied by float (period).
@ -91,146 +185,17 @@ TEST_P(QueryInternalShaderTests, TimestampComputeShader) {
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); DAWN_TEST_UNSUPPORTED_IF(UsesWire());
constexpr uint32_t kTimestampCount = 10u;
// A gpu frequency on Intel D3D12 (ticks/second)
constexpr uint64_t kGPUFrequency = 12000048u;
constexpr uint64_t kNsPerSecond = 1000000000u;
// Timestamp period in nanoseconds
constexpr float kPeriod = static_cast<float>(kNsPerSecond) / kGPUFrequency;
// Original timestamp values for testing
std::vector<uint64_t> timestamps = {
1, // garbage data which is not written at beginning
10079569507, // t0
10394415012, // t1
1, // garbage data which is not written between timestamps
11713454943, // t2
38912556941, // t3 (big value)
10080295766, // t4 (reset)
12159966783, // t5 (after reset)
12651224612, // t6
39872473956, // t7
};
// The buffer indicating which values are available timestamps
std::vector<uint32_t> availabilities = {0, 1, 1, 0, 1, 1, 1, 1, 1, 1};
wgpu::Buffer availabilityBuffer =
utils::CreateBufferFromData(device, availabilities.data(),
kTimestampCount * sizeof(uint32_t), wgpu::BufferUsage::Storage);
// The resolve buffer storing original timestamps and the converted values
wgpu::BufferDescriptor timestampsDesc;
timestampsDesc.size = kTimestampCount * sizeof(uint64_t);
timestampsDesc.usage =
wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
wgpu::Buffer timestampsBuffer = device.CreateBuffer(&timestampsDesc);
auto PrepareExpectedResults = [&](uint32_t first, uint32_t count,
uint32_t offset) -> std::vector<uint64_t> {
ASSERT(offset % sizeof(uint64_t) == 0);
std::vector<uint64_t> expected;
for (size_t i = 0; i < kTimestampCount; i++) {
// The data out of the rang [first, first + count] remains as it is
if (i < first || i >= first + count) {
expected.push_back(timestamps[i]);
continue;
}
if (availabilities[i] == 0) {
// Not a available timestamp, write 0
expected.push_back(0u);
} else {
// Maybe the timestamp * period is larger than the maximum of uint64, so cast the
// delta value to double (higher precision than float)
expected.push_back(
static_cast<uint64_t>(static_cast<double>(timestamps[i]) * kPeriod));
}
}
return expected;
};
// Convert timestamps in timestamps buffer with offset 0 // Convert timestamps in timestamps buffer with offset 0
// Test for ResolveQuerySet(querySet, 0, kTimestampCount, timestampsBuffer, 0) // Test for ResolveQuerySet(querySet, 0, kQueryCount, timestampsBuffer, 0)
{ RunTest(0, kQueryCount, 0);
constexpr uint32_t kFirst = 0u;
constexpr uint32_t kOffset = 0u;
// Write orignal timestamps to timestamps buffer // Convert timestamps in timestamps buffer with offset 256
queue.WriteBuffer(timestampsBuffer, 0, timestamps.data(), // Test for ResolveQuerySet(querySet, 1, kQueryCount - 1, timestampsBuffer, 256)
kTimestampCount * sizeof(uint64_t)); RunTest(1, kQueryCount - 1, 256);
// The params uniform buffer // Convert partial timestamps in timestamps buffer with offset 256
dawn_native::TimestampParams params = {kFirst, kTimestampCount, kOffset, kPeriod}; // Test for ResolveQuerySet(querySet, 1, 4, timestampsBuffer, 256)
wgpu::Buffer paramsBuffer = utils::CreateBufferFromData(device, &params, sizeof(params), RunTest(1, 4, 256);
wgpu::BufferUsage::Uniform);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeConvertTimestampsToNanoseconds(encoder, timestampsBuffer, availabilityBuffer,
paramsBuffer);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Expected results: Timestamp * period
std::vector<uint64_t> expected = PrepareExpectedResults(0, kTimestampCount, kOffset);
EXPECT_BUFFER(timestampsBuffer, 0, kTimestampCount * sizeof(uint64_t),
new InternalShaderExpectation(expected.data(), kTimestampCount));
}
// Convert timestamps in timestamps buffer with offset 8
// Test for ResolveQuerySet(querySet, 1, kTimestampCount - 1, timestampsBuffer, 8)
{
constexpr uint32_t kFirst = 1u;
constexpr uint32_t kOffset = 8u;
// Write orignal timestamps to timestamps buffer
queue.WriteBuffer(timestampsBuffer, 0, timestamps.data(),
kTimestampCount * sizeof(uint64_t));
// The params uniform buffer
dawn_native::TimestampParams params = {kFirst, kTimestampCount - kFirst, kOffset, kPeriod};
wgpu::Buffer paramsBuffer = utils::CreateBufferFromData(device, &params, sizeof(params),
wgpu::BufferUsage::Uniform);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeConvertTimestampsToNanoseconds(encoder, timestampsBuffer, availabilityBuffer,
paramsBuffer);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Expected results: Timestamp * period
std::vector<uint64_t> expected =
PrepareExpectedResults(kFirst, kTimestampCount - kFirst, kOffset);
EXPECT_BUFFER(timestampsBuffer, 0, kTimestampCount * sizeof(uint64_t),
new InternalShaderExpectation(expected.data(), kTimestampCount));
}
// Convert partial timestamps in timestamps buffer with offset 8
// Test for ResolveQuerySet(querySet, 1, 3, timestampsBuffer, 8)
{
constexpr uint32_t kFirst = 1u;
constexpr uint32_t kCount = 3u;
constexpr uint32_t kOffset = 8u;
// Write orignal timestamps to timestamps buffer
queue.WriteBuffer(timestampsBuffer, 0, timestamps.data(),
kTimestampCount * sizeof(uint64_t));
// The params uniform buffer
dawn_native::TimestampParams params = {kFirst, kCount, kOffset, kPeriod};
wgpu::Buffer paramsBuffer = utils::CreateBufferFromData(device, &params, sizeof(params),
wgpu::BufferUsage::Uniform);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
EncodeConvertTimestampsToNanoseconds(encoder, timestampsBuffer, availabilityBuffer,
paramsBuffer);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Expected results: Timestamp * period
std::vector<uint64_t> expected = PrepareExpectedResults(kFirst, kCount, kOffset);
EXPECT_BUFFER(timestampsBuffer, 0, kTimestampCount * sizeof(uint64_t),
new InternalShaderExpectation(expected.data(), kTimestampCount));
}
} }
DAWN_INSTANTIATE_TEST(QueryInternalShaderTests, D3D12Backend(), MetalBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(QueryInternalShaderTests, D3D12Backend(), MetalBackend(), VulkanBackend());