mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 15:46:28 +00:00
Query API: Timestamp Query on D3D12
- Add implementation of WriteTimestamp and ResolveQuerySet on D3D12, but not add compute shader to post-process the result yet. - Add end2end tests for timestamp query on command encoder/render pass/compute pass. Bug: dawn:434 Change-Id: I7f763bc46d651818da3f69bc72ea2e403cf2674d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/25845 Commit-Queue: Hao Li <hao.x.li@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
1ea3a22f52
commit
c0acb25318
@@ -1157,6 +1157,7 @@ namespace detail {
|
||||
template class ExpectEq<uint8_t>;
|
||||
template class ExpectEq<uint16_t>;
|
||||
template class ExpectEq<uint32_t>;
|
||||
template class ExpectEq<uint64_t>;
|
||||
template class ExpectEq<RGBA8>;
|
||||
template class ExpectEq<float>;
|
||||
} // namespace detail
|
||||
|
||||
@@ -30,29 +30,34 @@
|
||||
// until the end of the test. Also expectations use a copy to a MapRead buffer to get the data
|
||||
// so resources should have the CopySrc allowed usage bit if you want to add expectations on
|
||||
// them.
|
||||
#define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint16_t), \
|
||||
new ::detail::ExpectEq<uint16_t>(expected))
|
||||
|
||||
#define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint16_t) * (count), \
|
||||
new ::detail::ExpectEq<uint16_t>(expected, count))
|
||||
#define EXPECT_BUFFER(buffer, offset, size, expectation) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, size, expectation)
|
||||
|
||||
#define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t), \
|
||||
new ::detail::ExpectEq<uint32_t>(expected))
|
||||
#define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(uint16_t), new ::detail::ExpectEq<uint16_t>(expected))
|
||||
|
||||
#define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t) * (count), \
|
||||
new ::detail::ExpectEq<uint32_t>(expected, count))
|
||||
#define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(uint16_t) * (count), \
|
||||
new ::detail::ExpectEq<uint16_t>(expected, count))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t), \
|
||||
new ::detail::ExpectEq<float>(expected))
|
||||
#define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(uint32_t), new ::detail::ExpectEq<uint32_t>(expected))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) \
|
||||
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count))
|
||||
#define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(uint32_t) * (count), \
|
||||
new ::detail::ExpectEq<uint32_t>(expected, count))
|
||||
|
||||
#define EXPECT_BUFFER_U64_RANGE_EQ(expected, buffer, offset, count) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(uint64_t) * (count), \
|
||||
new ::detail::ExpectEq<uint64_t>(expected, count))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(float), new ::detail::ExpectEq<float>(expected))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count))
|
||||
|
||||
// Test a pixel of the mip level 0 of a 2D texture.
|
||||
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
|
||||
@@ -436,6 +441,7 @@ namespace detail {
|
||||
extern template class ExpectEq<uint8_t>;
|
||||
extern template class ExpectEq<int16_t>;
|
||||
extern template class ExpectEq<uint32_t>;
|
||||
extern template class ExpectEq<uint64_t>;
|
||||
extern template class ExpectEq<RGBA8>;
|
||||
extern template class ExpectEq<float>;
|
||||
} // namespace detail
|
||||
|
||||
@@ -19,7 +19,26 @@
|
||||
|
||||
#include "tests/DawnTest.h"
|
||||
|
||||
class OcclusionQueryTests : public DawnTest {};
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
class QueryTests : public DawnTest {
|
||||
protected:
|
||||
wgpu::Buffer CreateResolveBuffer(uint64_t size) {
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = size;
|
||||
descriptor.usage = wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc |
|
||||
wgpu::BufferUsage::CopyDst;
|
||||
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
|
||||
|
||||
// Initialize the buffer values to 0.
|
||||
std::vector<uint64_t> myData = {0, 0};
|
||||
device.GetDefaultQueue().WriteBuffer(buffer, 0, myData.data(), size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
class OcclusionQueryTests : public QueryTests {};
|
||||
|
||||
// Test creating query set with the type of Occlusion
|
||||
TEST_P(OcclusionQueryTests, QuerySetCreation) {
|
||||
@@ -40,7 +59,7 @@ TEST_P(OcclusionQueryTests, QuerySetDestroy) {
|
||||
|
||||
DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend());
|
||||
|
||||
class PipelineStatisticsQueryTests : public DawnTest {
|
||||
class PipelineStatisticsQueryTests : public QueryTests {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
DawnTest::SetUp();
|
||||
@@ -74,7 +93,26 @@ TEST_P(PipelineStatisticsQueryTests, QuerySetCreation) {
|
||||
|
||||
DAWN_INSTANTIATE_TEST(PipelineStatisticsQueryTests, D3D12Backend());
|
||||
|
||||
class TimestampQueryTests : public DawnTest {
|
||||
class TimestampExpectation : public detail::Expectation {
|
||||
public:
|
||||
~TimestampExpectation() override = default;
|
||||
|
||||
// Expect the timestamp results are greater than 0.
|
||||
testing::AssertionResult Check(const void* data, size_t size) override {
|
||||
ASSERT(size % sizeof(uint64_t) == 0);
|
||||
const uint64_t* timestamps = static_cast<const uint64_t*>(data);
|
||||
for (size_t i = 0; i < size / sizeof(uint64_t); i++) {
|
||||
if (timestamps[i] == 0) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Expected data[" << i << "] to be greater than 0." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
class TimestampQueryTests : public QueryTests {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
DawnTest::SetUp();
|
||||
@@ -90,14 +128,111 @@ class TimestampQueryTests : public DawnTest {
|
||||
}
|
||||
return requiredExtensions;
|
||||
}
|
||||
|
||||
wgpu::QuerySet CreateQuerySetForTimestamp(uint32_t queryCount) {
|
||||
wgpu::QuerySetDescriptor descriptor;
|
||||
descriptor.count = queryCount;
|
||||
descriptor.type = wgpu::QueryType::Timestamp;
|
||||
return device.CreateQuerySet(&descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
// Test creating query set with the type of Timestamp
|
||||
TEST_P(TimestampQueryTests, QuerySetCreation) {
|
||||
wgpu::QuerySetDescriptor descriptor;
|
||||
descriptor.count = 1;
|
||||
descriptor.type = wgpu::QueryType::Timestamp;
|
||||
device.CreateQuerySet(&descriptor);
|
||||
CreateQuerySetForTimestamp(1);
|
||||
}
|
||||
|
||||
// Test calling timestamp query from command encoder
|
||||
TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
|
||||
constexpr uint32_t kQueryCount = 2;
|
||||
|
||||
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.WriteTimestamp(querySet, 0);
|
||||
encoder.WriteTimestamp(querySet, 1);
|
||||
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_BUFFER(destination, 0, kQueryCount * sizeof(uint64_t), new TimestampExpectation);
|
||||
}
|
||||
|
||||
// Test calling timestamp query from render pass encoder
|
||||
TEST_P(TimestampQueryTests, TimestampOnRenderPass) {
|
||||
constexpr uint32_t kQueryCount = 2;
|
||||
|
||||
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.WriteTimestamp(querySet, 0);
|
||||
pass.WriteTimestamp(querySet, 1);
|
||||
pass.EndPass();
|
||||
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_BUFFER(destination, 0, kQueryCount * sizeof(uint64_t), new TimestampExpectation);
|
||||
}
|
||||
|
||||
// Test calling timestamp query from compute pass encoder
|
||||
TEST_P(TimestampQueryTests, TimestampOnComputePass) {
|
||||
constexpr uint32_t kQueryCount = 2;
|
||||
|
||||
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
pass.WriteTimestamp(querySet, 0);
|
||||
pass.WriteTimestamp(querySet, 1);
|
||||
pass.EndPass();
|
||||
encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_BUFFER(destination, 0, kQueryCount * sizeof(uint64_t), new TimestampExpectation);
|
||||
}
|
||||
|
||||
// Test resolving timestamp query to one slot in the buffer
|
||||
TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
|
||||
constexpr uint32_t kQueryCount = 2;
|
||||
constexpr uint64_t kZero = 0;
|
||||
|
||||
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||
|
||||
// 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::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.WriteTimestamp(querySet, 0);
|
||||
encoder.WriteTimestamp(querySet, 1);
|
||||
encoder.ResolveQuerySet(querySet, 0, 1, destination, 0);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_BUFFER(destination, 0, sizeof(uint64_t), new TimestampExpectation);
|
||||
EXPECT_BUFFER_U64_RANGE_EQ(&kZero, destination, sizeof(uint64_t), 1);
|
||||
}
|
||||
|
||||
// Resolve the query result to the buffer with offset, the slots before the offset
|
||||
// should not be written
|
||||
{
|
||||
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.WriteTimestamp(querySet, 0);
|
||||
encoder.WriteTimestamp(querySet, 1);
|
||||
encoder.ResolveQuerySet(querySet, 0, 1, destination, sizeof(uint64_t));
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_BUFFER_U64_RANGE_EQ(&kZero, destination, 0, 1);
|
||||
EXPECT_BUFFER(destination, sizeof(uint64_t), sizeof(uint64_t), new TimestampExpectation);
|
||||
}
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(TimestampQueryTests, D3D12Backend());
|
||||
|
||||
Reference in New Issue
Block a user