Query API: Non Precise Occlusion Query

- Add BeginOcclusionQuery and EndOcclusionQuery in frontend
- Set occlusion query as unsafe APIs
- Add validation tests

Bug: dawn:434
Change-Id: I3d1cefed780812dd62fb082287ff71530b76ebee
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31321
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Hao Li
2020-11-18 09:47:52 +00:00
committed by Commit Bot service account
parent 55f251dffe
commit 01e4450729
13 changed files with 373 additions and 4 deletions

View File

@@ -68,6 +68,146 @@ TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
querySet.Destroy();
}
class OcclusionQueryValidationTest : public QuerySetValidationTest {};
// Test the occlusionQuerySet in RenderPassDescriptor
TEST_F(OcclusionQueryValidationTest, InvalidOcclusionQuerySet) {
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
DummyRenderPass renderPass(device);
// Success
{
renderPass.occlusionQuerySet = occlusionQuerySet;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(0);
pass.EndOcclusionQuery();
pass.BeginOcclusionQuery(1);
pass.EndOcclusionQuery();
pass.EndPass();
encoder.Finish();
}
// Fail to begin occlusion query if the occlusionQuerySet is not set in RenderPassDescriptor
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass renderPassWithoutOcclusion(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassWithoutOcclusion);
pass.BeginOcclusionQuery(0);
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to begin render pass if the occlusionQuerySet is created from other device
{
wgpu::Device otherDevice = adapter.CreateDevice();
wgpu::QuerySet occlusionQuerySetOnOther =
CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2);
renderPass.occlusionQuerySet = occlusionQuerySetOnOther;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.BeginRenderPass(&renderPass);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit occlusion query with a destroyed query set
{
renderPass.occlusionQuerySet = occlusionQuerySet;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(0);
pass.EndOcclusionQuery();
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = device.GetDefaultQueue();
occlusionQuerySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test query index of occlusion query
TEST_F(OcclusionQueryValidationTest, InvalidQueryIndex) {
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
DummyRenderPass renderPass(device);
renderPass.occlusionQuerySet = occlusionQuerySet;
// Fail to begin occlusion query if the query index exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(2);
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Success to begin occlusion query with same query index twice on different render encoder
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass0 = encoder.BeginRenderPass(&renderPass);
pass0.BeginOcclusionQuery(0);
pass0.EndOcclusionQuery();
pass0.EndPass();
wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&renderPass);
pass1.BeginOcclusionQuery(0);
pass1.EndOcclusionQuery();
pass1.EndPass();
encoder.Finish();
}
// Fail to begin occlusion query with same query index twice on a same render encoder
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(0);
pass.EndOcclusionQuery();
pass.BeginOcclusionQuery(0);
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
}
// Test the correspondence between BeginOcclusionQuery and EndOcclusionQuery
TEST_F(OcclusionQueryValidationTest, InvalidBeginAndEnd) {
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
DummyRenderPass renderPass(device);
renderPass.occlusionQuerySet = occlusionQuerySet;
// Fail to begin an occlusion query without corresponding end operation
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(0);
pass.BeginOcclusionQuery(1);
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to end occlusion query twice in a row even the begin occlusion query twice
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.BeginOcclusionQuery(0);
pass.BeginOcclusionQuery(1);
pass.EndOcclusionQuery();
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to end occlusion query without begin operation
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.EndOcclusionQuery();
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
}
class TimestampQueryValidationTest : public QuerySetValidationTest {
protected:
wgpu::Device CreateTestDevice() override {
@@ -101,6 +241,18 @@ TEST_F(TimestampQueryValidationTest, UnnecessaryPipelineStatistics) {
{wgpu::PipelineStatisticName::VertexShaderInvocations}));
}
// Test query set with type of timestamp is set to the occlusionQuerySet of RenderPassDescriptor.
TEST_F(TimestampQueryValidationTest, BeginRenderPassWithTimestampQuerySet) {
// Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 1);
DummyRenderPass renderPass(device);
renderPass.occlusionQuerySet = querySet;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.BeginRenderPass(&renderPass);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test write timestamp on command encoder
TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
@@ -311,6 +463,21 @@ TEST_F(PipelineStatisticsQueryValidationTest, InvalidPipelineStatistics) {
}
}
// Test query set with type of pipeline statistics is set to the occlusionQuerySet of
// RenderPassDescriptor.
TEST_F(PipelineStatisticsQueryValidationTest, BeginRenderPassWithPipelineStatisticsQuerySet) {
// Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
wgpu::QuerySet querySet =
CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
{wgpu::PipelineStatisticName::VertexShaderInvocations});
DummyRenderPass renderPass(device);
renderPass.occlusionQuerySet = querySet;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.BeginRenderPass(&renderPass);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
class ResolveQuerySetValidationTest : public QuerySetValidationTest {
protected:
wgpu::Buffer CreateBuffer(wgpu::Device cDevice, uint64_t size, wgpu::BufferUsage usage) {

View File

@@ -167,3 +167,32 @@ TEST_F(UnsafeAPIValidationTest, DynamicStorageBuffer) {
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&desc));
}
}
// Check that occlusion query is disallowed as part of unsafe APIs.
TEST_F(UnsafeAPIValidationTest, OcclusionQueryDisallowed) {
DummyRenderPass renderPass(device);
// Control case: BeginRenderPass without occlusionQuerySet is allowed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.EndPass();
encoder.Finish();
}
// Error case: BeginRenderPass with occlusionQuerySet is disallowed.
{
wgpu::QuerySetDescriptor descriptor;
descriptor.type = wgpu::QueryType::Occlusion;
descriptor.count = 1;
wgpu::QuerySet querySet = device.CreateQuerySet(&descriptor);
renderPass.occlusionQuerySet = querySet;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
}