Query API: Non-precise occlusion query on Vulkan
- Implement BeginOcclusionQuery/EndOcclusionQuery on Vulkan
- Add compute pipeline to convert non-zero values to 1.
Bug: dawn:434
Change-Id: Ie0238078dfd26334caf36d23ded1d7742dd829a3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38221
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 47adf79..1c7cdd2 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -1188,11 +1188,19 @@
}
case Command::BeginOcclusionQuery: {
- return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ BeginOcclusionQueryCmd* cmd = mCommands.NextCommand<BeginOcclusionQueryCmd>();
+
+ device->fn.CmdBeginQuery(commands, ToBackend(cmd->querySet.Get())->GetHandle(),
+ cmd->queryIndex, 0);
+ break;
}
case Command::EndOcclusionQuery: {
- return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ EndOcclusionQueryCmd* cmd = mCommands.NextCommand<EndOcclusionQueryCmd>();
+
+ device->fn.CmdEndQuery(commands, ToBackend(cmd->querySet.Get())->GetHandle(),
+ cmd->queryIndex);
+ break;
}
case Command::WriteTimestamp: {
diff --git a/src/tests/end2end/QueryTests.cpp b/src/tests/end2end/QueryTests.cpp
index 7b768fb..951545c 100644
--- a/src/tests/end2end/QueryTests.cpp
+++ b/src/tests/end2end/QueryTests.cpp
@@ -33,6 +33,46 @@
}
};
+// Clear the content of the result buffer into 0xFFFFFFFF.
+constexpr static uint64_t kSentinelValue = ~uint64_t(0);
+
+class OcclusionExpectation : public detail::Expectation {
+ public:
+ enum class Result { Zero, NonZero };
+
+ ~OcclusionExpectation() override = default;
+
+ OcclusionExpectation(Result expected) {
+ mExpected = expected;
+ }
+
+ testing::AssertionResult Check(const void* data, size_t size) override {
+ ASSERT(size % sizeof(uint64_t) == 0);
+ const uint64_t* actual = static_cast<const uint64_t*>(data);
+ for (size_t i = 0; i < size / sizeof(uint64_t); i++) {
+ if (actual[i] == kSentinelValue) {
+ return testing::AssertionFailure()
+ << "Data[" << i << "] was not written (it kept the sentinel value of "
+ << kSentinelValue << ")." << std::endl;
+ }
+ if (mExpected == Result::Zero && actual[i] != 0) {
+ return testing::AssertionFailure()
+ << "Expected data[" << i << "] to be zero, actual: " << actual[i] << "."
+ << std::endl;
+ }
+ if (mExpected == Result::NonZero && actual[i] == 0) {
+ return testing::AssertionFailure()
+ << "Expected data[" << i << "] to be non-zero." << std::endl;
+ }
+ }
+
+ return testing::AssertionSuccess();
+ }
+
+ private:
+ Result mExpected;
+};
+
class OcclusionQueryTests : public QueryTests {
protected:
void SetUp() override {
@@ -80,7 +120,7 @@
void TestOcclusionQueryWithDepthStencilTest(bool depthTestEnabled,
bool stencilTestEnabled,
- uint64_t expected) {
+ OcclusionExpectation::Result expected) {
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
@@ -108,10 +148,9 @@
wgpu::QuerySet querySet = CreateOcclusionQuerySet(kQueryCount);
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
- uint64_t myData = ~uint64_t(1);
// Set all bits in buffer to check 0 is correctly written if there is no sample passed the
// occlusion testing
- queue.WriteBuffer(destination, 0, &myData, sizeof(myData));
+ queue.WriteBuffer(destination, 0, &kSentinelValue, sizeof(kSentinelValue));
utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
renderPass.occlusionQuerySet = querySet;
@@ -129,10 +168,11 @@
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
- EXPECT_BUFFER_U64_EQ(expected, destination, 0);
+ EXPECT_BUFFER(destination, 0, sizeof(uint64_t), new OcclusionExpectation(expected));
}
- void TestOcclusionQueryWithScissorTest(ScissorRect rect, uint64_t expected) {
+ void TestOcclusionQueryWithScissorTest(ScissorRect rect,
+ OcclusionExpectation::Result expected) {
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
@@ -141,10 +181,9 @@
wgpu::QuerySet querySet = CreateOcclusionQuerySet(kQueryCount);
wgpu::Buffer destination = CreateResolveBuffer(kQueryCount * sizeof(uint64_t));
- uint64_t myData = ~uint64_t(1);
// Set all bits in buffer to check 0 is correctly written if there is no sample passed the
// occlusion testing
- queue.WriteBuffer(destination, 0, &myData, sizeof(myData));
+ queue.WriteBuffer(destination, 0, &kSentinelValue, sizeof(kSentinelValue));
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
renderPass.renderPassInfo.occlusionQuerySet = querySet;
@@ -162,7 +201,7 @@
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
- EXPECT_BUFFER_U64_EQ(expected, destination, 0);
+ EXPECT_BUFFER(destination, 0, sizeof(uint64_t), new OcclusionExpectation(expected));
}
wgpu::ShaderModule vsModule;
@@ -184,39 +223,39 @@
}
// Draw a bottom right triangle with depth/stencil testing enabled and check whether there is
-// sample passed the testing by non-precise occlusion query with the binary results:
-// 0 indicates that no sample passed depth/stencil testing,
-// 1 indicates that at least one sample passed depth/stencil testing.
+// sample passed the testing by non-precise occlusion query with the results:
+// zero indicates that no sample passed depth/stencil testing,
+// non-zero indicates that at least one sample passed depth/stencil testing.
TEST_P(OcclusionQueryTests, QueryWithDepthStencilTest) {
- // TODO(hao.x.li@intel.com): Implement non-precise occlusion on Metal and Vulkan
- DAWN_SKIP_TEST_IF(IsMetal() || IsVulkan());
+ // TODO(hao.x.li@intel.com): Implement non-precise occlusion on Metal
+ DAWN_SKIP_TEST_IF(IsMetal());
// Disable depth/stencil testing, the samples always pass the testing, the expected occlusion
- // result is 1.
- TestOcclusionQueryWithDepthStencilTest(false, false, 1);
+ // result is non-zero.
+ TestOcclusionQueryWithDepthStencilTest(false, false, OcclusionExpectation::Result::NonZero);
// Only enable depth testing and set the samples never pass the testing, the expected occlusion
- // result is 0.
- TestOcclusionQueryWithDepthStencilTest(true, false, 0);
+ // result is zero.
+ TestOcclusionQueryWithDepthStencilTest(true, false, OcclusionExpectation::Result::Zero);
// Only enable stencil testing and set the samples never pass the testing, the expected
- // occlusion result is 0.
- TestOcclusionQueryWithDepthStencilTest(false, true, 0);
+ // occlusion result is zero.
+ TestOcclusionQueryWithDepthStencilTest(false, true, OcclusionExpectation::Result::Zero);
}
// Draw a bottom right triangle with scissor testing enabled and check whether there is
-// sample passed the testing by non-precise occlusion query with the binary results:
-// 0 indicates that no sample passed scissor testing,
-// 1 indicates that at least one sample passed scissor testing.
+// sample passed the testing by non-precise occlusion query with the results:
+// zero indicates that no sample passed scissor testing,
+// non-zero indicates that at least one sample passed scissor testing.
TEST_P(OcclusionQueryTests, QueryWithScissorTest) {
- // TODO(hao.x.li@intel.com): Implement non-precise occlusion on Metal and Vulkan
- DAWN_SKIP_TEST_IF(IsMetal() || IsVulkan());
+ // TODO(hao.x.li@intel.com): Implement non-precise occlusion on Metal
+ DAWN_SKIP_TEST_IF(IsMetal());
- // Test there are samples passed scissor testing, the expected occlusion result is 1.
- TestOcclusionQueryWithScissorTest({2, 1, 2, 1}, 1);
+ // Test there are samples passed scissor testing, the expected occlusion result is non-zero.
+ TestOcclusionQueryWithScissorTest({2, 1, 2, 1}, OcclusionExpectation::Result::NonZero);
- // Test there is no sample passed scissor testing, the expected occlusion result is 0.
- TestOcclusionQueryWithScissorTest({0, 0, 2, 1}, 0);
+ // Test there is no sample passed scissor testing, the expected occlusion result is zero.
+ TestOcclusionQueryWithScissorTest({0, 0, 2, 1}, OcclusionExpectation::Result::Zero);
}
DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend(), MetalBackend(), VulkanBackend());