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:
parent
71b811b4c9
commit
387a597154
|
@ -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: {
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue