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