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>
This commit is contained in:
Hao Li 2021-02-02 02:38:59 +00:00 committed by Commit Bot service account
parent 71b811b4c9
commit 387a597154
2 changed files with 77 additions and 30 deletions

View File

@ -1188,11 +1188,19 @@ namespace dawn_native { namespace vulkan {
}
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: {

View File

@ -33,6 +33,46 @@ class QueryTests : public DawnTest {
}
};
// 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 @@ class OcclusionQueryTests : public QueryTests {
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 @@ class OcclusionQueryTests : public QueryTests {
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 @@ class OcclusionQueryTests : public QueryTests {
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 @@ class OcclusionQueryTests : public QueryTests {
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 @@ class OcclusionQueryTests : public QueryTests {
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 @@ TEST_P(OcclusionQueryTests, QuerySetDestroy) {
}
// 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());