• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "tests/unittests/validation/ValidationTest.h"
16 
17 #include "utils/WGPUHelpers.h"
18 
19 class QuerySetValidationTest : public ValidationTest {
20   protected:
CreateQuerySet(wgpu::Device cDevice,wgpu::QueryType queryType,uint32_t queryCount,std::vector<wgpu::PipelineStatisticName> pipelineStatistics={})21     wgpu::QuerySet CreateQuerySet(
22         wgpu::Device cDevice,
23         wgpu::QueryType queryType,
24         uint32_t queryCount,
25         std::vector<wgpu::PipelineStatisticName> pipelineStatistics = {}) {
26         wgpu::QuerySetDescriptor descriptor;
27         descriptor.type = queryType;
28         descriptor.count = queryCount;
29 
30         if (pipelineStatistics.size() > 0) {
31             descriptor.pipelineStatistics = pipelineStatistics.data();
32             descriptor.pipelineStatisticsCount = pipelineStatistics.size();
33         }
34 
35         return cDevice.CreateQuerySet(&descriptor);
36     }
37 };
38 
39 // Test creating query set without features
TEST_F(QuerySetValidationTest,CreationWithoutFeatures)40 TEST_F(QuerySetValidationTest, CreationWithoutFeatures) {
41     // Creating a query set for occlusion queries succeeds without any features enabled.
42     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
43 
44     // Creating a query set for other types of queries fails without features enabled.
45     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
46                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
47     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1));
48 }
49 
50 // Test creating query set with invalid count
TEST_F(QuerySetValidationTest,InvalidQueryCount)51 TEST_F(QuerySetValidationTest, InvalidQueryCount) {
52     // Success create a query set with the maximum count
53     CreateQuerySet(device, wgpu::QueryType::Occlusion, kMaxQueryCount);
54 
55     // Fail to create a query set with the count which exceeds the maximum
56     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Occlusion, kMaxQueryCount + 1));
57 }
58 
59 // Test creating query set with invalid type
TEST_F(QuerySetValidationTest,InvalidQueryType)60 TEST_F(QuerySetValidationTest, InvalidQueryType) {
61     ASSERT_DEVICE_ERROR(CreateQuerySet(device, static_cast<wgpu::QueryType>(0xFFFFFFFF), 1));
62 }
63 
64 // Test creating query set with unnecessary pipeline statistics for occlusion queries
TEST_F(QuerySetValidationTest,UnnecessaryPipelineStatistics)65 TEST_F(QuerySetValidationTest, UnnecessaryPipelineStatistics) {
66     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Occlusion, 1,
67                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
68 }
69 
70 // Test destroying a destroyed query set
TEST_F(QuerySetValidationTest,DestroyDestroyedQuerySet)71 TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
72     wgpu::QuerySetDescriptor descriptor;
73     descriptor.type = wgpu::QueryType::Occlusion;
74     descriptor.count = 1;
75     wgpu::QuerySet querySet = device.CreateQuerySet(&descriptor);
76     querySet.Destroy();
77     querySet.Destroy();
78 }
79 
80 class OcclusionQueryValidationTest : public QuerySetValidationTest {};
81 
82 // Test the occlusionQuerySet in RenderPassDescriptor
TEST_F(OcclusionQueryValidationTest,InvalidOcclusionQuerySet)83 TEST_F(OcclusionQueryValidationTest, InvalidOcclusionQuerySet) {
84     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
85     DummyRenderPass renderPass(device);
86 
87     // Success
88     {
89         renderPass.occlusionQuerySet = occlusionQuerySet;
90         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
91         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
92         pass.BeginOcclusionQuery(0);
93         pass.EndOcclusionQuery();
94         pass.BeginOcclusionQuery(1);
95         pass.EndOcclusionQuery();
96         pass.EndPass();
97         encoder.Finish();
98     }
99 
100     // Fail to begin occlusion query if the occlusionQuerySet is not set in RenderPassDescriptor
101     {
102         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
103         DummyRenderPass renderPassWithoutOcclusion(device);
104         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassWithoutOcclusion);
105         pass.BeginOcclusionQuery(0);
106         pass.EndOcclusionQuery();
107         pass.EndPass();
108         ASSERT_DEVICE_ERROR(encoder.Finish());
109     }
110 
111     // Fail to begin render pass if the occlusionQuerySet is created from other device
112     {
113         wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
114         wgpu::QuerySet occlusionQuerySetOnOther =
115             CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2);
116         renderPass.occlusionQuerySet = occlusionQuerySetOnOther;
117         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
118         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
119         pass.EndPass();
120         ASSERT_DEVICE_ERROR(encoder.Finish());
121 
122         // Clear this out so we don't hold a reference. The query set
123         // must be destroyed before the device local to this test case.
124         renderPass.occlusionQuerySet = wgpu::QuerySet();
125     }
126 
127     // Fail to submit occlusion query with a destroyed query set
128     {
129         renderPass.occlusionQuerySet = occlusionQuerySet;
130         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
131         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
132         pass.BeginOcclusionQuery(0);
133         pass.EndOcclusionQuery();
134         pass.EndPass();
135         wgpu::CommandBuffer commands = encoder.Finish();
136         wgpu::Queue queue = device.GetQueue();
137         occlusionQuerySet.Destroy();
138         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
139     }
140 }
141 
142 // Test query index of occlusion query
TEST_F(OcclusionQueryValidationTest,InvalidQueryIndex)143 TEST_F(OcclusionQueryValidationTest, InvalidQueryIndex) {
144     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
145     DummyRenderPass renderPass(device);
146     renderPass.occlusionQuerySet = occlusionQuerySet;
147 
148     // Fail to begin occlusion query if the query index exceeds the number of queries in query set
149     {
150         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
151         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
152         pass.BeginOcclusionQuery(2);
153         pass.EndOcclusionQuery();
154         pass.EndPass();
155         ASSERT_DEVICE_ERROR(encoder.Finish());
156     }
157 
158     // Success to begin occlusion query with same query index twice on different render encoder
159     {
160         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
161         wgpu::RenderPassEncoder pass0 = encoder.BeginRenderPass(&renderPass);
162         pass0.BeginOcclusionQuery(0);
163         pass0.EndOcclusionQuery();
164         pass0.EndPass();
165 
166         wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&renderPass);
167         pass1.BeginOcclusionQuery(0);
168         pass1.EndOcclusionQuery();
169         pass1.EndPass();
170         encoder.Finish();
171     }
172 
173     // Fail to begin occlusion query with same query index twice on a same render encoder
174     {
175         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
176         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
177         pass.BeginOcclusionQuery(0);
178         pass.EndOcclusionQuery();
179         pass.BeginOcclusionQuery(0);
180         pass.EndOcclusionQuery();
181         pass.EndPass();
182         ASSERT_DEVICE_ERROR(encoder.Finish());
183     }
184 }
185 
186 // Test the correspondence between BeginOcclusionQuery and EndOcclusionQuery
TEST_F(OcclusionQueryValidationTest,InvalidBeginAndEnd)187 TEST_F(OcclusionQueryValidationTest, InvalidBeginAndEnd) {
188     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
189     DummyRenderPass renderPass(device);
190     renderPass.occlusionQuerySet = occlusionQuerySet;
191 
192     // Fail to begin an occlusion query without corresponding end operation
193     {
194         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
195         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
196         pass.BeginOcclusionQuery(0);
197         pass.BeginOcclusionQuery(1);
198         pass.EndOcclusionQuery();
199         pass.EndPass();
200         ASSERT_DEVICE_ERROR(encoder.Finish());
201     }
202 
203     // Fail to end occlusion query twice in a row even the begin occlusion query twice
204     {
205         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
206         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
207         pass.BeginOcclusionQuery(0);
208         pass.BeginOcclusionQuery(1);
209         pass.EndOcclusionQuery();
210         pass.EndOcclusionQuery();
211         pass.EndPass();
212         ASSERT_DEVICE_ERROR(encoder.Finish());
213     }
214 
215     // Fail to end occlusion query without begin operation
216     {
217         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
218         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
219         pass.EndOcclusionQuery();
220         pass.EndPass();
221         ASSERT_DEVICE_ERROR(encoder.Finish());
222     }
223 }
224 
225 class TimestampQueryValidationTest : public QuerySetValidationTest {
226   protected:
CreateTestDevice()227     WGPUDevice CreateTestDevice() override {
228         dawn_native::DawnDeviceDescriptor descriptor;
229         descriptor.requiredFeatures.push_back("timestamp-query");
230         descriptor.forceDisabledToggles.push_back("disallow_unsafe_apis");
231         return adapter.CreateDevice(&descriptor);
232     }
233 };
234 
235 // Test creating query set with only the timestamp feature enabled.
TEST_F(TimestampQueryValidationTest,Creation)236 TEST_F(TimestampQueryValidationTest, Creation) {
237     // Creating a query set for occlusion queries succeeds.
238     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
239 
240     // Creating a query set for pipeline statistics queries fails.
241     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
242                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
243 
244     // Creating a query set for timestamp queries succeeds.
245     CreateQuerySet(device, wgpu::QueryType::Timestamp, 1);
246 
247     // Fail to create with pipeline statistics for Timestamp query
248     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1,
249                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
250 }
251 
252 // Test creating query set with unnecessary pipeline statistics for timestamp queries
TEST_F(TimestampQueryValidationTest,UnnecessaryPipelineStatistics)253 TEST_F(TimestampQueryValidationTest, UnnecessaryPipelineStatistics) {
254     // Fail to create with pipeline statistics for Occlusion query
255     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1,
256                                        {wgpu::PipelineStatisticName::VertexShaderInvocations}));
257 }
258 
259 // Test query set with type of timestamp is set to the occlusionQuerySet of RenderPassDescriptor.
TEST_F(TimestampQueryValidationTest,BeginRenderPassWithTimestampQuerySet)260 TEST_F(TimestampQueryValidationTest, BeginRenderPassWithTimestampQuerySet) {
261     // Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
262     wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 1);
263     DummyRenderPass renderPass(device);
264     renderPass.occlusionQuerySet = querySet;
265 
266     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
267     encoder.BeginRenderPass(&renderPass);
268     ASSERT_DEVICE_ERROR(encoder.Finish());
269 }
270 
271 // Test write timestamp on command encoder
TEST_F(TimestampQueryValidationTest,WriteTimestampOnCommandEncoder)272 TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
273     wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
274     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
275 
276     // Success on command encoder
277     {
278         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
279         encoder.WriteTimestamp(timestampQuerySet, 0);
280         encoder.Finish();
281     }
282 
283     // Fail to write timestamp to the index which exceeds the number of queries in query set
284     {
285         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
286         encoder.WriteTimestamp(timestampQuerySet, 2);
287         ASSERT_DEVICE_ERROR(encoder.Finish());
288     }
289 
290     // Fail to submit timestamp query with a destroyed query set
291     {
292         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
293         encoder.WriteTimestamp(timestampQuerySet, 0);
294         wgpu::CommandBuffer commands = encoder.Finish();
295 
296         wgpu::Queue queue = device.GetQueue();
297         timestampQuerySet.Destroy();
298         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
299     }
300 }
301 
302 // Test write timestamp on compute pass encoder
TEST_F(TimestampQueryValidationTest,WriteTimestampOnComputePassEncoder)303 TEST_F(TimestampQueryValidationTest, WriteTimestampOnComputePassEncoder) {
304     wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
305     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
306 
307     // Success on compute pass encoder
308     {
309         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
310         wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
311         pass.WriteTimestamp(timestampQuerySet, 0);
312         pass.EndPass();
313         encoder.Finish();
314     }
315 
316     // Not allow to write timestamp to the query set with other query type
317     {
318         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
319         wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
320         pass.WriteTimestamp(occlusionQuerySet, 0);
321         pass.EndPass();
322         ASSERT_DEVICE_ERROR(encoder.Finish());
323     }
324 
325     // Fail to write timestamp to the index which exceeds the number of queries in query set
326     {
327         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
328         wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
329         pass.WriteTimestamp(timestampQuerySet, 2);
330         pass.EndPass();
331         ASSERT_DEVICE_ERROR(encoder.Finish());
332     }
333 
334     // Fail to submit timestamp query with a destroyed query set
335     {
336         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
337         wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
338         pass.WriteTimestamp(timestampQuerySet, 0);
339         pass.EndPass();
340         wgpu::CommandBuffer commands = encoder.Finish();
341 
342         wgpu::Queue queue = device.GetQueue();
343         timestampQuerySet.Destroy();
344         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
345     }
346 }
347 
348 // Test write timestamp on render pass encoder
TEST_F(TimestampQueryValidationTest,WriteTimestampOnRenderPassEncoder)349 TEST_F(TimestampQueryValidationTest, WriteTimestampOnRenderPassEncoder) {
350     DummyRenderPass renderPass(device);
351 
352     wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
353     wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
354 
355     // Success on render pass encoder
356     {
357         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
358         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
359         pass.WriteTimestamp(timestampQuerySet, 0);
360         pass.EndPass();
361         encoder.Finish();
362     }
363 
364     // Not allow to write timestamp to the query set with other query type
365     {
366         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
367         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
368         pass.WriteTimestamp(occlusionQuerySet, 0);
369         pass.EndPass();
370         ASSERT_DEVICE_ERROR(encoder.Finish());
371     }
372 
373     // Fail to write timestamp to the index which exceeds the number of queries in query set
374     {
375         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
376         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
377         pass.WriteTimestamp(timestampQuerySet, 2);
378         pass.EndPass();
379         ASSERT_DEVICE_ERROR(encoder.Finish());
380     }
381 
382     // Success to write timestamp to the same query index twice on command encoder and render
383     // encoder
384     {
385         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
386         encoder.WriteTimestamp(timestampQuerySet, 0);
387         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
388         pass.WriteTimestamp(timestampQuerySet, 0);
389         pass.EndPass();
390         encoder.Finish();
391     }
392 
393     // Success to write timestamp to the same query index twice on different render encoder
394     {
395         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
396         wgpu::RenderPassEncoder pass0 = encoder.BeginRenderPass(&renderPass);
397         pass0.WriteTimestamp(timestampQuerySet, 0);
398         pass0.EndPass();
399         wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&renderPass);
400         pass1.WriteTimestamp(timestampQuerySet, 0);
401         pass1.EndPass();
402         encoder.Finish();
403     }
404 
405     // Fail to write timestamp to the same query index twice on same render encoder
406     {
407         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
408         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
409         pass.WriteTimestamp(timestampQuerySet, 0);
410         pass.WriteTimestamp(timestampQuerySet, 0);
411         pass.EndPass();
412         ASSERT_DEVICE_ERROR(encoder.Finish());
413     }
414 
415     // Fail to submit timestamp query with a destroyed query set
416     {
417         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
418         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
419         pass.WriteTimestamp(timestampQuerySet, 0);
420         pass.EndPass();
421         wgpu::CommandBuffer commands = encoder.Finish();
422 
423         wgpu::Queue queue = device.GetQueue();
424         timestampQuerySet.Destroy();
425         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
426     }
427 }
428 
429 class PipelineStatisticsQueryValidationTest : public QuerySetValidationTest {
430   protected:
CreateTestDevice()431     WGPUDevice CreateTestDevice() override {
432         dawn_native::DawnDeviceDescriptor descriptor;
433         descriptor.requiredFeatures.push_back("pipeline-statistics-query");
434         // TODO(crbug.com/1177506): Pipeline statistic query is an unsafe API, disable disallowing
435         // unsafe APIs to test it.
436         descriptor.forceDisabledToggles.push_back("disallow_unsafe_apis");
437         return adapter.CreateDevice(&descriptor);
438     }
439 };
440 
441 // Test creating query set with only the pipeline statistics feature enabled.
TEST_F(PipelineStatisticsQueryValidationTest,Creation)442 TEST_F(PipelineStatisticsQueryValidationTest, Creation) {
443     // Creating a query set for occlusion queries succeeds.
444     CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
445 
446     // Creating a query set for timestamp queries fails.
447     ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1));
448 
449     // Creating a query set for pipeline statistics queries succeeds.
450     CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
451                    {wgpu::PipelineStatisticName::VertexShaderInvocations});
452 }
453 
454 // Test creating query set with invalid pipeline statistics
TEST_F(PipelineStatisticsQueryValidationTest,InvalidPipelineStatistics)455 TEST_F(PipelineStatisticsQueryValidationTest, InvalidPipelineStatistics) {
456     // Success to create with all pipeline statistics names which are not in the same order as
457     // defined in webgpu header file
458     {
459         CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
460                        {wgpu::PipelineStatisticName::ClipperInvocations,
461                         wgpu::PipelineStatisticName::ClipperPrimitivesOut,
462                         wgpu::PipelineStatisticName::ComputeShaderInvocations,
463                         wgpu::PipelineStatisticName::FragmentShaderInvocations,
464                         wgpu::PipelineStatisticName::VertexShaderInvocations});
465     }
466 
467     // Fail to create with empty pipeline statistics
468     { ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1, {})); }
469 
470     // Fail to create with invalid pipeline statistics
471     {
472         ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
473                                            {static_cast<wgpu::PipelineStatisticName>(0xFFFFFFFF)}));
474     }
475 
476     // Fail to create with duplicate pipeline statistics
477     {
478         ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
479                                            {wgpu::PipelineStatisticName::VertexShaderInvocations,
480                                             wgpu::PipelineStatisticName::VertexShaderInvocations}));
481     }
482 }
483 
484 // Test query set with type of pipeline statistics is set to the occlusionQuerySet of
485 // RenderPassDescriptor.
TEST_F(PipelineStatisticsQueryValidationTest,BeginRenderPassWithPipelineStatisticsQuerySet)486 TEST_F(PipelineStatisticsQueryValidationTest, BeginRenderPassWithPipelineStatisticsQuerySet) {
487     // Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
488     wgpu::QuerySet querySet =
489         CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
490                        {wgpu::PipelineStatisticName::VertexShaderInvocations});
491     DummyRenderPass renderPass(device);
492     renderPass.occlusionQuerySet = querySet;
493 
494     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
495     encoder.BeginRenderPass(&renderPass);
496     ASSERT_DEVICE_ERROR(encoder.Finish());
497 }
498 
499 class ResolveQuerySetValidationTest : public QuerySetValidationTest {
500   protected:
CreateBuffer(wgpu::Device cDevice,uint64_t size,wgpu::BufferUsage usage)501     wgpu::Buffer CreateBuffer(wgpu::Device cDevice, uint64_t size, wgpu::BufferUsage usage) {
502         wgpu::BufferDescriptor descriptor;
503         descriptor.size = size;
504         descriptor.usage = usage;
505 
506         return cDevice.CreateBuffer(&descriptor);
507     }
508 };
509 
510 // Test resolve query set with invalid query set, first query and query count
TEST_F(ResolveQuerySetValidationTest,ResolveInvalidQuerySetAndIndexCount)511 TEST_F(ResolveQuerySetValidationTest, ResolveInvalidQuerySetAndIndexCount) {
512     constexpr uint32_t kQueryCount = 4;
513 
514     wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, kQueryCount);
515     wgpu::Buffer destination =
516         CreateBuffer(device, kQueryCount * sizeof(uint64_t), wgpu::BufferUsage::QueryResolve);
517 
518     // Success
519     {
520         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
521         encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
522         wgpu::CommandBuffer commands = encoder.Finish();
523 
524         wgpu::Queue queue = device.GetQueue();
525         queue.Submit(1, &commands);
526     }
527 
528     //  Fail to resolve query set if first query out of range
529     {
530         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
531         encoder.ResolveQuerySet(querySet, kQueryCount, 0, destination, 0);
532         ASSERT_DEVICE_ERROR(encoder.Finish());
533     }
534 
535     //  Fail to resolve query set if the sum of first query and query count is larger than queries
536     //  number in the query set
537     {
538         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
539         encoder.ResolveQuerySet(querySet, 1, kQueryCount, destination, 0);
540         ASSERT_DEVICE_ERROR(encoder.Finish());
541     }
542 
543     // Fail to resolve a destroyed query set
544     {
545         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
546         encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
547         wgpu::CommandBuffer commands = encoder.Finish();
548 
549         wgpu::Queue queue = device.GetQueue();
550         querySet.Destroy();
551         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
552     }
553 }
554 
555 // Test resolve query set with invalid query set, first query and query count
TEST_F(ResolveQuerySetValidationTest,ResolveToInvalidBufferAndOffset)556 TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) {
557     constexpr uint32_t kQueryCount = 4;
558     constexpr uint64_t kBufferSize =
559         (kQueryCount - 1) * sizeof(uint64_t) + 256 /*destinationOffset*/;
560 
561     wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, kQueryCount);
562     wgpu::Buffer destination = CreateBuffer(device, kBufferSize, wgpu::BufferUsage::QueryResolve);
563 
564     // Success
565     {
566         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
567         encoder.ResolveQuerySet(querySet, 1, kQueryCount - 1, destination, 256);
568         wgpu::CommandBuffer commands = encoder.Finish();
569 
570         wgpu::Queue queue = device.GetQueue();
571         queue.Submit(1, &commands);
572     }
573 
574     // Fail to resolve query set to a buffer created from another device
575     {
576         wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
577         wgpu::Buffer bufferOnOther =
578             CreateBuffer(otherDevice, kBufferSize, wgpu::BufferUsage::QueryResolve);
579         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
580         encoder.ResolveQuerySet(querySet, 0, kQueryCount, bufferOnOther, 0);
581         ASSERT_DEVICE_ERROR(encoder.Finish());
582     }
583 
584     //  Fail to resolve query set to a buffer if offset is not a multiple of 256 bytes
585     {
586         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
587         encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 128);
588         ASSERT_DEVICE_ERROR(encoder.Finish());
589     }
590 
591     //  Fail to resolve query set to a buffer if the data size overflow the buffer
592     {
593         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
594         encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 256);
595         ASSERT_DEVICE_ERROR(encoder.Finish());
596     }
597 
598     //  Fail to resolve query set to a buffer if the offset is past the end of the buffer
599     {
600         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
601         encoder.ResolveQuerySet(querySet, 0, 1, destination, kBufferSize);
602         ASSERT_DEVICE_ERROR(encoder.Finish());
603     }
604 
605     //  Fail to resolve query set to a buffer does not have the usage of QueryResolve
606     {
607         wgpu::Buffer dstBuffer = CreateBuffer(device, kBufferSize, wgpu::BufferUsage::CopyDst);
608         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
609         encoder.ResolveQuerySet(querySet, 0, kQueryCount, dstBuffer, 0);
610         ASSERT_DEVICE_ERROR(encoder.Finish());
611     }
612 
613     // Fail to resolve query set to a destroyed buffer.
614     {
615         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
616         encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
617         wgpu::CommandBuffer commands = encoder.Finish();
618 
619         wgpu::Queue queue = device.GetQueue();
620         destination.Destroy();
621         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
622     }
623 }
624