1 // Copyright 2019 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 "common/Constants.h"
18
19 #include "utils/ComboRenderBundleEncoderDescriptor.h"
20 #include "utils/ComboRenderPipelineDescriptor.h"
21 #include "utils/WGPUHelpers.h"
22
23 namespace {
24
25 class RenderBundleValidationTest : public ValidationTest {
26 protected:
SetUp()27 void SetUp() override {
28 ValidationTest::SetUp();
29
30 vsModule = utils::CreateShaderModule(device, R"(
31 [[block]] struct S {
32 transform : mat2x2<f32>;
33 };
34 [[group(0), binding(0)]] var<uniform> uniforms : S;
35
36 [[stage(vertex)]] fn main([[location(0)]] pos : vec2<f32>) -> [[builtin(position)]] vec4<f32> {
37 return vec4<f32>();
38 })");
39
40 fsModule = utils::CreateShaderModule(device, R"(
41 [[block]] struct Uniforms {
42 color : vec4<f32>;
43 };
44 [[group(1), binding(0)]] var<uniform> uniforms : Uniforms;
45
46 [[block]] struct Storage {
47 dummy : array<f32>;
48 };
49 [[group(1), binding(1)]] var<storage, read_write> ssbo : Storage;
50
51 [[stage(fragment)]] fn main() {
52 })");
53
54 wgpu::BindGroupLayout bgls[] = {
55 utils::MakeBindGroupLayout(
56 device, {{0, wgpu::ShaderStage::Vertex, wgpu::BufferBindingType::Uniform}}),
57 utils::MakeBindGroupLayout(
58 device, {
59 {0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform},
60 {1, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage},
61 })};
62
63 wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = {};
64 pipelineLayoutDesc.bindGroupLayoutCount = 2;
65 pipelineLayoutDesc.bindGroupLayouts = bgls;
66
67 pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc);
68
69 utils::ComboRenderPipelineDescriptor descriptor;
70 InitializeRenderPipelineDescriptor(&descriptor);
71 pipeline = device.CreateRenderPipeline(&descriptor);
72
73 float data[8];
74 wgpu::Buffer buffer = utils::CreateBufferFromData(device, data, 8 * sizeof(float),
75 wgpu::BufferUsage::Uniform);
76
77 constexpr static float kVertices[] = {-1.f, 1.f, 1.f, -1.f, -1.f, 1.f};
78
79 vertexBuffer = utils::CreateBufferFromData(device, kVertices, sizeof(kVertices),
80 wgpu::BufferUsage::Vertex);
81
82 // Dummy storage buffer.
83 wgpu::Buffer storageBuffer = utils::CreateBufferFromData(
84 device, kVertices, sizeof(kVertices), wgpu::BufferUsage::Storage);
85
86 // Vertex buffer with storage usage for testing read+write error usage.
87 vertexStorageBuffer =
88 utils::CreateBufferFromData(device, kVertices, sizeof(kVertices),
89 wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Storage);
90
91 bg0 = utils::MakeBindGroup(device, bgls[0], {{0, buffer, 0, 8 * sizeof(float)}});
92 bg1 = utils::MakeBindGroup(
93 device, bgls[1],
94 {{0, buffer, 0, 4 * sizeof(float)}, {1, storageBuffer, 0, sizeof(kVertices)}});
95
96 bg1Vertex = utils::MakeBindGroup(device, bgls[1],
97 {{0, buffer, 0, 8 * sizeof(float)},
98 {1, vertexStorageBuffer, 0, sizeof(kVertices)}});
99 }
100
InitializeRenderPipelineDescriptor(utils::ComboRenderPipelineDescriptor * descriptor)101 void InitializeRenderPipelineDescriptor(utils::ComboRenderPipelineDescriptor* descriptor) {
102 descriptor->layout = pipelineLayout;
103 descriptor->vertex.module = vsModule;
104 descriptor->cFragment.module = fsModule;
105 descriptor->cTargets[0].writeMask = wgpu::ColorWriteMask::None;
106 descriptor->vertex.bufferCount = 1;
107 descriptor->cBuffers[0].arrayStride = 2 * sizeof(float);
108 descriptor->cBuffers[0].attributeCount = 1;
109 descriptor->cAttributes[0].format = wgpu::VertexFormat::Float32x2;
110 descriptor->cAttributes[0].shaderLocation = 0;
111 }
112
113 wgpu::ShaderModule vsModule;
114 wgpu::ShaderModule fsModule;
115 wgpu::PipelineLayout pipelineLayout;
116 wgpu::RenderPipeline pipeline;
117 wgpu::Buffer vertexBuffer;
118 wgpu::Buffer vertexStorageBuffer;
119 wgpu::BindGroup bg0;
120 wgpu::BindGroup bg1;
121 wgpu::BindGroup bg1Vertex;
122 };
123
124 } // anonymous namespace
125
126 // Test creating and encoding an empty render bundle.
TEST_F(RenderBundleValidationTest,Empty)127 TEST_F(RenderBundleValidationTest, Empty) {
128 DummyRenderPass renderPass(device);
129
130 utils::ComboRenderBundleEncoderDescriptor desc = {};
131 desc.colorFormatsCount = 1;
132 desc.cColorFormats[0] = renderPass.attachmentFormat;
133
134 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
135 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
136
137 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
138 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
139 pass.ExecuteBundles(1, &renderBundle);
140 pass.EndPass();
141 commandEncoder.Finish();
142 }
143
144 // Test that an empty error bundle encoder produces an error bundle.
145 // This is a regression test for error render bundle encoders containing no commands would
146 // produce non-error render bundles.
TEST_F(RenderBundleValidationTest,EmptyErrorEncoderProducesErrorBundle)147 TEST_F(RenderBundleValidationTest, EmptyErrorEncoderProducesErrorBundle) {
148 DummyRenderPass renderPass(device);
149
150 utils::ComboRenderBundleEncoderDescriptor desc = {};
151 // Having 0 attachments is invalid!
152 desc.colorFormatsCount = 0;
153
154 wgpu::RenderBundleEncoder renderBundleEncoder;
155 ASSERT_DEVICE_ERROR(renderBundleEncoder = device.CreateRenderBundleEncoder(&desc));
156 wgpu::RenderBundle renderBundle;
157 ASSERT_DEVICE_ERROR(renderBundle = renderBundleEncoder.Finish());
158
159 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
160 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
161 pass.ExecuteBundles(1, &renderBundle);
162 pass.EndPass();
163 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
164 }
165
166 // Test executing zero render bundles.
TEST_F(RenderBundleValidationTest,ZeroBundles)167 TEST_F(RenderBundleValidationTest, ZeroBundles) {
168 DummyRenderPass renderPass(device);
169
170 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
171 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
172 pass.ExecuteBundles(0, nullptr);
173 pass.EndPass();
174 commandEncoder.Finish();
175 }
176
177 // Test successfully creating and encoding a render bundle into a command buffer.
TEST_F(RenderBundleValidationTest,SimpleSuccess)178 TEST_F(RenderBundleValidationTest, SimpleSuccess) {
179 DummyRenderPass renderPass(device);
180
181 utils::ComboRenderBundleEncoderDescriptor desc = {};
182 desc.colorFormatsCount = 1;
183 desc.cColorFormats[0] = renderPass.attachmentFormat;
184
185 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
186 renderBundleEncoder.SetPipeline(pipeline);
187 renderBundleEncoder.SetBindGroup(0, bg0);
188 renderBundleEncoder.SetBindGroup(1, bg1);
189 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
190 renderBundleEncoder.Draw(3);
191 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
192
193 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
194 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
195 pass.ExecuteBundles(1, &renderBundle);
196 pass.EndPass();
197 commandEncoder.Finish();
198 }
199
200 // Test that render bundle debug groups must be well nested.
TEST_F(RenderBundleValidationTest,DebugGroups)201 TEST_F(RenderBundleValidationTest, DebugGroups) {
202 DummyRenderPass renderPass(device);
203
204 utils::ComboRenderBundleEncoderDescriptor desc = {};
205 desc.colorFormatsCount = 1;
206 desc.cColorFormats[0] = renderPass.attachmentFormat;
207
208 // Test a single debug group works.
209 {
210 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
211 renderBundleEncoder.PushDebugGroup("group");
212 renderBundleEncoder.PopDebugGroup();
213 renderBundleEncoder.Finish();
214 }
215
216 // Test nested debug groups work.
217 {
218 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
219 renderBundleEncoder.PushDebugGroup("group");
220 renderBundleEncoder.PushDebugGroup("group2");
221 renderBundleEncoder.PopDebugGroup();
222 renderBundleEncoder.PopDebugGroup();
223 renderBundleEncoder.Finish();
224 }
225
226 // Test popping when no group is pushed is invalid.
227 {
228 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
229 renderBundleEncoder.PopDebugGroup();
230 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
231 }
232
233 // Test popping too many times is invalid.
234 {
235 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
236 renderBundleEncoder.PushDebugGroup("group");
237 renderBundleEncoder.PopDebugGroup();
238 renderBundleEncoder.PopDebugGroup();
239 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
240 }
241
242 // Test that a single debug group must be popped.
243 {
244 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
245 renderBundleEncoder.PushDebugGroup("group");
246 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
247 }
248
249 // Test that all debug groups must be popped.
250 {
251 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
252 renderBundleEncoder.PushDebugGroup("group");
253 renderBundleEncoder.PushDebugGroup("group2");
254 renderBundleEncoder.PopDebugGroup();
255 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
256 }
257 }
258
259 // Test render bundles do not inherit command buffer state
TEST_F(RenderBundleValidationTest,StateInheritance)260 TEST_F(RenderBundleValidationTest, StateInheritance) {
261 DummyRenderPass renderPass(device);
262
263 utils::ComboRenderBundleEncoderDescriptor desc = {};
264 desc.colorFormatsCount = 1;
265 desc.cColorFormats[0] = renderPass.attachmentFormat;
266
267 // Render bundle does not inherit pipeline so the draw is invalid.
268 {
269 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
270 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
271 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
272
273 pass.SetPipeline(pipeline);
274
275 renderBundleEncoder.SetBindGroup(0, bg0);
276 renderBundleEncoder.SetBindGroup(1, bg1);
277 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
278 renderBundleEncoder.Draw(3);
279 ASSERT_DEVICE_ERROR(wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish());
280
281 pass.ExecuteBundles(1, &renderBundle);
282 pass.EndPass();
283 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
284 }
285
286 // Render bundle does not inherit bind groups so the draw is invalid.
287 {
288 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
289 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
290 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
291
292 pass.SetBindGroup(0, bg0);
293 pass.SetBindGroup(1, bg1);
294
295 renderBundleEncoder.SetPipeline(pipeline);
296 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
297 renderBundleEncoder.Draw(3);
298 ASSERT_DEVICE_ERROR(wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish());
299
300 pass.ExecuteBundles(1, &renderBundle);
301 pass.EndPass();
302 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
303 }
304
305 // Render bundle does not inherit pipeline and bind groups so the draw is invalid.
306 {
307 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
308 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
309 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
310
311 pass.SetPipeline(pipeline);
312 pass.SetBindGroup(0, bg0);
313 pass.SetBindGroup(1, bg1);
314
315 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
316 renderBundleEncoder.Draw(3);
317 ASSERT_DEVICE_ERROR(wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish());
318
319 pass.ExecuteBundles(1, &renderBundle);
320 pass.EndPass();
321 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
322 }
323
324 // Render bundle does not inherit buffers so the draw is invalid.
325 {
326 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
327 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
328 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
329
330 pass.SetVertexBuffer(0, vertexBuffer);
331
332 renderBundleEncoder.SetPipeline(pipeline);
333 renderBundleEncoder.SetBindGroup(0, bg0);
334 renderBundleEncoder.SetBindGroup(1, bg1);
335 renderBundleEncoder.Draw(3);
336 ASSERT_DEVICE_ERROR(wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish());
337
338 pass.ExecuteBundles(1, &renderBundle);
339 pass.EndPass();
340 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
341 }
342 }
343
344 // Test render bundles do not persist command buffer state
TEST_F(RenderBundleValidationTest,StatePersistence)345 TEST_F(RenderBundleValidationTest, StatePersistence) {
346 DummyRenderPass renderPass(device);
347
348 utils::ComboRenderBundleEncoderDescriptor desc = {};
349 desc.colorFormatsCount = 1;
350 desc.cColorFormats[0] = renderPass.attachmentFormat;
351
352 // Render bundle does not persist pipeline so the draw is invalid.
353 {
354 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
355 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
356
357 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
358 renderBundleEncoder.SetPipeline(pipeline);
359 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
360
361 pass.ExecuteBundles(1, &renderBundle);
362 pass.SetBindGroup(0, bg0);
363 pass.SetBindGroup(1, bg1);
364 pass.SetVertexBuffer(0, vertexBuffer);
365 pass.Draw(3);
366 pass.EndPass();
367
368 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
369 }
370
371 // Render bundle does not persist bind groups so the draw is invalid.
372 {
373 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
374 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
375
376 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
377 renderBundleEncoder.SetBindGroup(0, bg0);
378 renderBundleEncoder.SetBindGroup(1, bg1);
379 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
380
381 pass.ExecuteBundles(1, &renderBundle);
382 pass.SetPipeline(pipeline);
383 pass.SetVertexBuffer(0, vertexBuffer);
384 pass.Draw(3);
385 pass.EndPass();
386
387 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
388 }
389
390 // Render bundle does not persist pipeline and bind groups so the draw is invalid.
391 {
392 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
393 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
394
395 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
396 renderBundleEncoder.SetPipeline(pipeline);
397 renderBundleEncoder.SetBindGroup(0, bg0);
398 renderBundleEncoder.SetBindGroup(1, bg1);
399 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
400
401 pass.ExecuteBundles(1, &renderBundle);
402 pass.SetVertexBuffer(0, vertexBuffer);
403 pass.Draw(3);
404 pass.EndPass();
405
406 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
407 }
408
409 // Render bundle does not persist buffers so the draw is invalid.
410 {
411 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
412 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
413
414 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
415 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
416 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
417
418 pass.ExecuteBundles(1, &renderBundle);
419 pass.SetPipeline(pipeline);
420 pass.SetBindGroup(0, bg0);
421 pass.SetBindGroup(1, bg1);
422 pass.Draw(3);
423 pass.EndPass();
424
425 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
426 }
427 }
428
429 // Test executing render bundles clears command buffer state
TEST_F(RenderBundleValidationTest,ClearsState)430 TEST_F(RenderBundleValidationTest, ClearsState) {
431 DummyRenderPass renderPass(device);
432
433 utils::ComboRenderBundleEncoderDescriptor desc = {};
434 desc.colorFormatsCount = 1;
435 desc.cColorFormats[0] = renderPass.attachmentFormat;
436
437 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
438 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
439
440 // Render bundle clears pipeline so the draw is invalid.
441 {
442 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
443 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
444
445 pass.SetPipeline(pipeline);
446 pass.ExecuteBundles(1, &renderBundle);
447 pass.SetBindGroup(0, bg0);
448 pass.SetBindGroup(1, bg1);
449 pass.SetVertexBuffer(0, vertexBuffer);
450 pass.Draw(3);
451 pass.EndPass();
452
453 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
454 }
455
456 // Render bundle clears bind groups so the draw is invalid.
457 {
458 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
459 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
460
461 pass.SetBindGroup(0, bg0);
462 pass.SetBindGroup(1, bg1);
463 pass.ExecuteBundles(1, &renderBundle);
464 pass.SetPipeline(pipeline);
465 pass.SetVertexBuffer(0, vertexBuffer);
466 pass.Draw(3);
467 pass.EndPass();
468
469 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
470 }
471
472 // Render bundle clears pipeline and bind groups so the draw is invalid.
473 {
474 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
475 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
476
477 pass.SetPipeline(pipeline);
478 pass.SetBindGroup(0, bg0);
479 pass.SetBindGroup(1, bg1);
480 pass.ExecuteBundles(1, &renderBundle);
481 pass.SetVertexBuffer(0, vertexBuffer);
482 pass.Draw(3);
483 pass.EndPass();
484
485 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
486 }
487
488 // Render bundle clears buffers so the draw is invalid.
489 {
490 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
491 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
492
493 pass.SetVertexBuffer(0, vertexBuffer);
494 pass.ExecuteBundles(1, &renderBundle);
495 pass.SetPipeline(pipeline);
496 pass.SetBindGroup(0, bg0);
497 pass.SetBindGroup(1, bg1);
498 pass.Draw(3);
499 pass.EndPass();
500
501 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
502 }
503
504 // Test executing 0 bundles still clears command buffer state.
505 {
506 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
507 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
508
509 pass.SetPipeline(pipeline);
510 pass.SetBindGroup(0, bg0);
511 pass.SetBindGroup(1, bg1);
512 pass.SetVertexBuffer(0, vertexBuffer);
513 pass.ExecuteBundles(0, nullptr);
514 pass.Draw(3);
515
516 pass.EndPass();
517 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
518 }
519 }
520
521 // Test creating and encoding multiple render bundles.
TEST_F(RenderBundleValidationTest,MultipleBundles)522 TEST_F(RenderBundleValidationTest, MultipleBundles) {
523 DummyRenderPass renderPass(device);
524
525 utils::ComboRenderBundleEncoderDescriptor desc = {};
526 desc.colorFormatsCount = 1;
527 desc.cColorFormats[0] = renderPass.attachmentFormat;
528
529 wgpu::RenderBundle renderBundles[2] = {};
530
531 wgpu::RenderBundleEncoder renderBundleEncoder0 = device.CreateRenderBundleEncoder(&desc);
532 renderBundleEncoder0.SetPipeline(pipeline);
533 renderBundleEncoder0.SetBindGroup(0, bg0);
534 renderBundleEncoder0.SetBindGroup(1, bg1);
535 renderBundleEncoder0.SetVertexBuffer(0, vertexBuffer);
536 renderBundleEncoder0.Draw(3);
537 renderBundles[0] = renderBundleEncoder0.Finish();
538
539 wgpu::RenderBundleEncoder renderBundleEncoder1 = device.CreateRenderBundleEncoder(&desc);
540 renderBundleEncoder1.SetPipeline(pipeline);
541 renderBundleEncoder1.SetBindGroup(0, bg0);
542 renderBundleEncoder1.SetBindGroup(1, bg1);
543 renderBundleEncoder1.SetVertexBuffer(0, vertexBuffer);
544 renderBundleEncoder1.Draw(3);
545 renderBundles[1] = renderBundleEncoder1.Finish();
546
547 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
548 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
549 pass.ExecuteBundles(2, renderBundles);
550 pass.EndPass();
551 commandEncoder.Finish();
552 }
553
554 // Test that is is valid to execute a render bundle more than once.
TEST_F(RenderBundleValidationTest,ExecuteMultipleTimes)555 TEST_F(RenderBundleValidationTest, ExecuteMultipleTimes) {
556 DummyRenderPass renderPass(device);
557
558 utils::ComboRenderBundleEncoderDescriptor desc = {};
559 desc.colorFormatsCount = 1;
560 desc.cColorFormats[0] = renderPass.attachmentFormat;
561
562 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
563 renderBundleEncoder.SetPipeline(pipeline);
564 renderBundleEncoder.SetBindGroup(0, bg0);
565 renderBundleEncoder.SetBindGroup(1, bg1);
566 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
567 renderBundleEncoder.Draw(3);
568 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
569
570 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
571 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
572 pass.ExecuteBundles(1, &renderBundle);
573 pass.ExecuteBundles(1, &renderBundle);
574 pass.ExecuteBundles(1, &renderBundle);
575 pass.EndPass();
576 commandEncoder.Finish();
577 }
578
579 // Test that it is an error to call Finish() on a render bundle encoder twice.
TEST_F(RenderBundleValidationTest,FinishTwice)580 TEST_F(RenderBundleValidationTest, FinishTwice) {
581 utils::ComboRenderBundleEncoderDescriptor desc = {};
582 desc.colorFormatsCount = 1;
583 desc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Uint;
584
585 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
586 renderBundleEncoder.Finish();
587 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
588 }
589
590 // Test that it is invalid to create a render bundle with no texture formats
TEST_F(RenderBundleValidationTest,RequiresAtLeastOneTextureFormat)591 TEST_F(RenderBundleValidationTest, RequiresAtLeastOneTextureFormat) {
592 // Test failure case.
593 {
594 utils::ComboRenderBundleEncoderDescriptor desc = {};
595 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
596 }
597
598 // Test success with one color format.
599 {
600 utils::ComboRenderBundleEncoderDescriptor desc = {};
601 desc.colorFormatsCount = 1;
602 desc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Uint;
603 device.CreateRenderBundleEncoder(&desc);
604 }
605
606 // Test success with a depth stencil format.
607 {
608 utils::ComboRenderBundleEncoderDescriptor desc = {};
609 desc.depthStencilFormat = wgpu::TextureFormat::Depth24PlusStencil8;
610 device.CreateRenderBundleEncoder(&desc);
611 }
612 }
613
614 // Test that it is invalid to create a render bundle with no texture formats
TEST_F(RenderBundleValidationTest,ColorFormatsCountOutOfBounds)615 TEST_F(RenderBundleValidationTest, ColorFormatsCountOutOfBounds) {
616 std::array<wgpu::TextureFormat, kMaxColorAttachments + 1> colorFormats;
617 for (uint32_t i = 0; i < colorFormats.size(); ++i) {
618 colorFormats[i] = wgpu::TextureFormat::RGBA8Unorm;
619 }
620
621 // colorFormatsCount <= kMaxColorAttachments is valid.
622 {
623 wgpu::RenderBundleEncoderDescriptor desc;
624 desc.colorFormatsCount = kMaxColorAttachments;
625 desc.colorFormats = colorFormats.data();
626 device.CreateRenderBundleEncoder(&desc);
627 }
628
629 // colorFormatsCount > kMaxColorAttachments is invalid.
630 {
631 wgpu::RenderBundleEncoderDescriptor desc;
632 desc.colorFormatsCount = kMaxColorAttachments + 1;
633 desc.colorFormats = colorFormats.data();
634 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
635 }
636 }
637
638 // Test that render bundle color formats cannot be set to undefined.
TEST_F(RenderBundleValidationTest,ColorFormatUndefined)639 TEST_F(RenderBundleValidationTest, ColorFormatUndefined) {
640 utils::ComboRenderBundleEncoderDescriptor desc = {};
641 desc.colorFormatsCount = 1;
642 desc.cColorFormats[0] = wgpu::TextureFormat::Undefined;
643 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
644 }
645
646 // Test that the render bundle depth stencil format cannot be set to undefined.
TEST_F(RenderBundleValidationTest,DepthStencilFormatUndefined)647 TEST_F(RenderBundleValidationTest, DepthStencilFormatUndefined) {
648 utils::ComboRenderBundleEncoderDescriptor desc = {};
649 desc.depthStencilFormat = wgpu::TextureFormat::Undefined;
650 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
651 }
652
653 // Test that depthReadOnly must be equal to stencilReadOnly if depth stencil format contain
654 // both depth and stencil formats.
TEST_F(RenderBundleValidationTest,DepthStencilReadOnly)655 TEST_F(RenderBundleValidationTest, DepthStencilReadOnly) {
656 for (wgpu::TextureFormat format :
657 {wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureFormat::Depth32Float}) {
658 for (bool depthReadOnly : {true, false}) {
659 for (bool stencilReadOnly : {true, false}) {
660 utils::ComboRenderBundleEncoderDescriptor desc = {};
661 desc.depthStencilFormat = format;
662 desc.depthReadOnly = depthReadOnly;
663 desc.stencilReadOnly = stencilReadOnly;
664 if (format == wgpu::TextureFormat::Depth24PlusStencil8 &&
665 depthReadOnly != stencilReadOnly) {
666 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
667 } else {
668 device.CreateRenderBundleEncoder(&desc);
669 }
670 }
671 }
672 }
673 }
674 // Test that resource usages are validated inside render bundles.
TEST_F(RenderBundleValidationTest,UsageTracking)675 TEST_F(RenderBundleValidationTest, UsageTracking) {
676 DummyRenderPass renderPass(device);
677
678 utils::ComboRenderBundleEncoderDescriptor desc = {};
679 desc.colorFormatsCount = 1;
680 desc.cColorFormats[0] = renderPass.attachmentFormat;
681
682 wgpu::RenderBundle renderBundle0;
683 wgpu::RenderBundle renderBundle1;
684
685 // First base case is successful. |bg1Vertex| does not reference |vertexBuffer|.
686 {
687 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
688 renderBundleEncoder.SetPipeline(pipeline);
689 renderBundleEncoder.SetBindGroup(0, bg0);
690 renderBundleEncoder.SetBindGroup(1, bg1Vertex);
691 renderBundleEncoder.SetVertexBuffer(0, vertexBuffer);
692 renderBundleEncoder.Draw(3);
693 renderBundle0 = renderBundleEncoder.Finish();
694 }
695
696 // Second base case is successful. |bg1| does not reference |vertexStorageBuffer|
697 {
698 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
699 renderBundleEncoder.SetPipeline(pipeline);
700 renderBundleEncoder.SetBindGroup(0, bg0);
701 renderBundleEncoder.SetBindGroup(1, bg1);
702 renderBundleEncoder.SetVertexBuffer(0, vertexStorageBuffer);
703 renderBundleEncoder.Draw(3);
704 renderBundle1 = renderBundleEncoder.Finish();
705 }
706
707 // Test that a render bundle which sets a buffer as both vertex and storage is invalid.
708 // |bg1Vertex| references |vertexStorageBuffer|
709 {
710 wgpu::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
711 renderBundleEncoder.SetPipeline(pipeline);
712 renderBundleEncoder.SetBindGroup(0, bg0);
713 renderBundleEncoder.SetBindGroup(1, bg1Vertex);
714 renderBundleEncoder.SetVertexBuffer(0, vertexStorageBuffer);
715 renderBundleEncoder.Draw(3);
716 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
717 }
718
719 // When both render bundles are in the same pass, |vertexStorageBuffer| is used
720 // as both read and write usage. This is invalid.
721 // renderBundle0 uses |vertexStorageBuffer| as a storage buffer.
722 // renderBundle1 uses |vertexStorageBuffer| as a vertex buffer.
723 {
724 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
725 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
726 pass.ExecuteBundles(1, &renderBundle0);
727 pass.ExecuteBundles(1, &renderBundle1);
728 pass.EndPass();
729 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
730 }
731
732 // |vertexStorageBuffer| is used as both read and write usage. This is invalid.
733 // The render pass uses |vertexStorageBuffer| as a storage buffer.
734 // renderBundle1 uses |vertexStorageBuffer| as a vertex buffer.
735 {
736 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
737 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
738
739 pass.SetPipeline(pipeline);
740 pass.SetBindGroup(0, bg0);
741 pass.SetBindGroup(1, bg1Vertex);
742 pass.SetVertexBuffer(0, vertexBuffer);
743 pass.Draw(3);
744
745 pass.ExecuteBundles(1, &renderBundle1);
746 pass.EndPass();
747 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
748 }
749
750 // |vertexStorageBuffer| is used as both read and write usage. This is invalid.
751 // renderBundle0 uses |vertexStorageBuffer| as a storage buffer.
752 // The render pass uses |vertexStorageBuffer| as a vertex buffer.
753 {
754 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
755 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
756
757 pass.ExecuteBundles(1, &renderBundle0);
758
759 pass.SetPipeline(pipeline);
760 pass.SetBindGroup(0, bg0);
761 pass.SetBindGroup(1, bg1);
762 pass.SetVertexBuffer(0, vertexStorageBuffer);
763 pass.Draw(3);
764
765 pass.EndPass();
766 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
767 }
768 }
769
770 // Test that encoding SetPipline with an incompatible color format produces an error.
TEST_F(RenderBundleValidationTest,PipelineColorFormatMismatch)771 TEST_F(RenderBundleValidationTest, PipelineColorFormatMismatch) {
772 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
773 renderBundleDesc.colorFormatsCount = 3;
774 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
775 renderBundleDesc.cColorFormats[1] = wgpu::TextureFormat::RG16Float;
776 renderBundleDesc.cColorFormats[2] = wgpu::TextureFormat::R16Sint;
777
778 auto SetupRenderPipelineDescForTest = [this](utils::ComboRenderPipelineDescriptor* desc) {
779 InitializeRenderPipelineDescriptor(desc);
780 desc->cFragment.targetCount = 3;
781 desc->cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
782 desc->cTargets[1].format = wgpu::TextureFormat::RG16Float;
783 desc->cTargets[2].format = wgpu::TextureFormat::R16Sint;
784 desc->cTargets[0].writeMask = wgpu::ColorWriteMask::None;
785 desc->cTargets[1].writeMask = wgpu::ColorWriteMask::None;
786 desc->cTargets[2].writeMask = wgpu::ColorWriteMask::None;
787 };
788
789 // Test the success case.
790 {
791 utils::ComboRenderPipelineDescriptor desc;
792 SetupRenderPipelineDescForTest(&desc);
793
794 wgpu::RenderBundleEncoder renderBundleEncoder =
795 device.CreateRenderBundleEncoder(&renderBundleDesc);
796 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
797 renderBundleEncoder.SetPipeline(pipeline);
798 renderBundleEncoder.Finish();
799 }
800
801 // Test the failure case for mismatched format types.
802 {
803 utils::ComboRenderPipelineDescriptor desc;
804 SetupRenderPipelineDescForTest(&desc);
805 desc.cTargets[1].format = wgpu::TextureFormat::RGBA8Unorm;
806
807 wgpu::RenderBundleEncoder renderBundleEncoder =
808 device.CreateRenderBundleEncoder(&renderBundleDesc);
809 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
810 renderBundleEncoder.SetPipeline(pipeline);
811 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
812 }
813
814 // Test the failure case for missing format
815 {
816 utils::ComboRenderPipelineDescriptor desc;
817 SetupRenderPipelineDescForTest(&desc);
818 desc.cFragment.targetCount = 2;
819
820 wgpu::RenderBundleEncoder renderBundleEncoder =
821 device.CreateRenderBundleEncoder(&renderBundleDesc);
822 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
823 renderBundleEncoder.SetPipeline(pipeline);
824 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
825 }
826 }
827
828 // Test that encoding SetPipline with an incompatible depth stencil format produces an error.
TEST_F(RenderBundleValidationTest,PipelineDepthStencilFormatMismatch)829 TEST_F(RenderBundleValidationTest, PipelineDepthStencilFormatMismatch) {
830 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
831 renderBundleDesc.colorFormatsCount = 1;
832 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
833 renderBundleDesc.depthStencilFormat = wgpu::TextureFormat::Depth24PlusStencil8;
834
835 auto SetupRenderPipelineDescForTest = [this](utils::ComboRenderPipelineDescriptor* desc) {
836 InitializeRenderPipelineDescriptor(desc);
837 desc->cFragment.targetCount = 1;
838 desc->cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
839 };
840
841 // Test the success case.
842 {
843 utils::ComboRenderPipelineDescriptor desc;
844 SetupRenderPipelineDescForTest(&desc);
845 desc.EnableDepthStencil(wgpu::TextureFormat::Depth24PlusStencil8);
846
847 wgpu::RenderBundleEncoder renderBundleEncoder =
848 device.CreateRenderBundleEncoder(&renderBundleDesc);
849 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
850 renderBundleEncoder.SetPipeline(pipeline);
851 renderBundleEncoder.Finish();
852 }
853
854 // Test the failure case for mismatched format.
855 {
856 utils::ComboRenderPipelineDescriptor desc;
857 SetupRenderPipelineDescForTest(&desc);
858 desc.EnableDepthStencil(wgpu::TextureFormat::Depth24Plus);
859
860 wgpu::RenderBundleEncoder renderBundleEncoder =
861 device.CreateRenderBundleEncoder(&renderBundleDesc);
862 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
863 renderBundleEncoder.SetPipeline(pipeline);
864 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
865 }
866
867 // Test the failure case for missing format.
868 {
869 utils::ComboRenderPipelineDescriptor desc;
870 SetupRenderPipelineDescForTest(&desc);
871 desc.depthStencil = nullptr;
872
873 wgpu::RenderBundleEncoder renderBundleEncoder =
874 device.CreateRenderBundleEncoder(&renderBundleDesc);
875 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
876 renderBundleEncoder.SetPipeline(pipeline);
877 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
878 }
879 }
880
881 // Test that encoding SetPipline with an incompatible sample count produces an error.
TEST_F(RenderBundleValidationTest,PipelineSampleCountMismatch)882 TEST_F(RenderBundleValidationTest, PipelineSampleCountMismatch) {
883 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
884 renderBundleDesc.colorFormatsCount = 1;
885 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
886 renderBundleDesc.sampleCount = 4;
887
888 utils::ComboRenderPipelineDescriptor renderPipelineDesc;
889 InitializeRenderPipelineDescriptor(&renderPipelineDesc);
890 renderPipelineDesc.cFragment.targetCount = 1;
891 renderPipelineDesc.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
892 renderPipelineDesc.multisample.count = 4;
893
894 // Test the success case.
895 {
896 wgpu::RenderBundleEncoder renderBundleEncoder =
897 device.CreateRenderBundleEncoder(&renderBundleDesc);
898 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
899 renderBundleEncoder.SetPipeline(pipeline);
900 renderBundleEncoder.Finish();
901 }
902
903 // Test the failure case.
904 {
905 renderPipelineDesc.multisample.count = 1;
906
907 wgpu::RenderBundleEncoder renderBundleEncoder =
908 device.CreateRenderBundleEncoder(&renderBundleDesc);
909 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
910 renderBundleEncoder.SetPipeline(pipeline);
911 ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
912 }
913 }
914
915 // Test that encoding ExecuteBundles with an incompatible color format produces an error.
TEST_F(RenderBundleValidationTest,RenderPassColorFormatMismatch)916 TEST_F(RenderBundleValidationTest, RenderPassColorFormatMismatch) {
917 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
918 renderBundleDesc.colorFormatsCount = 3;
919 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
920 renderBundleDesc.cColorFormats[1] = wgpu::TextureFormat::RG16Float;
921 renderBundleDesc.cColorFormats[2] = wgpu::TextureFormat::R16Sint;
922
923 wgpu::RenderBundleEncoder renderBundleEncoder =
924 device.CreateRenderBundleEncoder(&renderBundleDesc);
925 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
926
927 wgpu::TextureDescriptor textureDesc = {};
928 textureDesc.usage = wgpu::TextureUsage::RenderAttachment;
929 textureDesc.size = wgpu::Extent3D({400, 400, 1});
930
931 textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
932 wgpu::Texture tex0 = device.CreateTexture(&textureDesc);
933
934 textureDesc.format = wgpu::TextureFormat::RG16Float;
935 wgpu::Texture tex1 = device.CreateTexture(&textureDesc);
936
937 textureDesc.format = wgpu::TextureFormat::R16Sint;
938 wgpu::Texture tex2 = device.CreateTexture(&textureDesc);
939
940 // Test the success case
941 {
942 utils::ComboRenderPassDescriptor renderPass({
943 tex0.CreateView(),
944 tex1.CreateView(),
945 tex2.CreateView(),
946 });
947
948 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
949 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
950 pass.ExecuteBundles(1, &renderBundle);
951 pass.EndPass();
952 commandEncoder.Finish();
953 }
954
955 // Test the failure case for mismatched format
956 {
957 utils::ComboRenderPassDescriptor renderPass({
958 tex0.CreateView(),
959 tex1.CreateView(),
960 tex0.CreateView(),
961 });
962
963 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
964 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
965 pass.ExecuteBundles(1, &renderBundle);
966 pass.EndPass();
967 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
968 }
969
970 // Test the failure case for missing format
971 {
972 utils::ComboRenderPassDescriptor renderPass({
973 tex0.CreateView(),
974 tex1.CreateView(),
975 });
976
977 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
978 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
979 pass.ExecuteBundles(1, &renderBundle);
980 pass.EndPass();
981 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
982 }
983 }
984
985 // Test that encoding ExecuteBundles with an incompatible depth stencil format produces an
986 // error.
TEST_F(RenderBundleValidationTest,RenderPassDepthStencilFormatMismatch)987 TEST_F(RenderBundleValidationTest, RenderPassDepthStencilFormatMismatch) {
988 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
989 renderBundleDesc.colorFormatsCount = 1;
990 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
991 renderBundleDesc.depthStencilFormat = wgpu::TextureFormat::Depth24Plus;
992
993 wgpu::RenderBundleEncoder renderBundleEncoder =
994 device.CreateRenderBundleEncoder(&renderBundleDesc);
995 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
996
997 wgpu::TextureDescriptor textureDesc = {};
998 textureDesc.usage = wgpu::TextureUsage::RenderAttachment;
999 textureDesc.size = wgpu::Extent3D({400, 400, 1});
1000
1001 textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
1002 wgpu::Texture tex0 = device.CreateTexture(&textureDesc);
1003
1004 textureDesc.format = wgpu::TextureFormat::Depth24Plus;
1005 wgpu::Texture tex1 = device.CreateTexture(&textureDesc);
1006
1007 textureDesc.format = wgpu::TextureFormat::Depth32Float;
1008 wgpu::Texture tex2 = device.CreateTexture(&textureDesc);
1009
1010 // Test the success case
1011 {
1012 utils::ComboRenderPassDescriptor renderPass({tex0.CreateView()}, tex1.CreateView());
1013
1014 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1015 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
1016 pass.ExecuteBundles(1, &renderBundle);
1017 pass.EndPass();
1018 commandEncoder.Finish();
1019 }
1020
1021 // Test the failure case for mismatched format
1022 {
1023 utils::ComboRenderPassDescriptor renderPass({tex0.CreateView()}, tex2.CreateView());
1024
1025 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1026 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
1027 pass.ExecuteBundles(1, &renderBundle);
1028 pass.EndPass();
1029 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
1030 }
1031
1032 // Test the failure case for missing format
1033 {
1034 utils::ComboRenderPassDescriptor renderPass({tex0.CreateView()});
1035
1036 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1037 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
1038 pass.ExecuteBundles(1, &renderBundle);
1039 pass.EndPass();
1040 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
1041 }
1042 }
1043
1044 // Test that encoding ExecuteBundles with an incompatible sample count produces an error.
TEST_F(RenderBundleValidationTest,RenderPassSampleCountMismatch)1045 TEST_F(RenderBundleValidationTest, RenderPassSampleCountMismatch) {
1046 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
1047 renderBundleDesc.colorFormatsCount = 1;
1048 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
1049
1050 wgpu::RenderBundleEncoder renderBundleEncoder =
1051 device.CreateRenderBundleEncoder(&renderBundleDesc);
1052 wgpu::RenderBundle renderBundle = renderBundleEncoder.Finish();
1053
1054 wgpu::TextureDescriptor textureDesc = {};
1055 textureDesc.usage = wgpu::TextureUsage::RenderAttachment;
1056 textureDesc.size = wgpu::Extent3D({400, 400, 1});
1057
1058 textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
1059 wgpu::Texture tex0 = device.CreateTexture(&textureDesc);
1060
1061 textureDesc.sampleCount = 4;
1062 wgpu::Texture tex1 = device.CreateTexture(&textureDesc);
1063
1064 // Test the success case
1065 {
1066 utils::ComboRenderPassDescriptor renderPass({tex0.CreateView()});
1067
1068 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1069 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
1070 pass.ExecuteBundles(1, &renderBundle);
1071 pass.EndPass();
1072 commandEncoder.Finish();
1073 }
1074
1075 // Test the failure case
1076 {
1077 utils::ComboRenderPassDescriptor renderPass({tex1.CreateView()});
1078
1079 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1080 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
1081 pass.ExecuteBundles(1, &renderBundle);
1082 pass.EndPass();
1083 ASSERT_DEVICE_ERROR(commandEncoder.Finish());
1084 }
1085 }
1086
1087 // Test that color attachment texture formats must be color renderable and
1088 // depth stencil texture formats must be depth/stencil.
TEST_F(RenderBundleValidationTest,TextureFormats)1089 TEST_F(RenderBundleValidationTest, TextureFormats) {
1090 // Test that color formats are validated as color.
1091 {
1092 utils::ComboRenderBundleEncoderDescriptor desc = {};
1093 desc.colorFormatsCount = 1;
1094 desc.cColorFormats[0] = wgpu::TextureFormat::Depth24PlusStencil8;
1095 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
1096 }
1097
1098 // Test that color formats are validated as renderable.
1099 {
1100 utils::ComboRenderBundleEncoderDescriptor desc = {};
1101 desc.colorFormatsCount = 1;
1102 desc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Snorm;
1103 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
1104 }
1105
1106 // Test that depth/stencil formats are validated as depth/stencil.
1107 {
1108 utils::ComboRenderBundleEncoderDescriptor desc = {};
1109 desc.depthStencilFormat = wgpu::TextureFormat::RGBA8Unorm;
1110 ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&desc));
1111 }
1112
1113 // Don't test non-renerable depth/stencil formats because we don't have any.
1114 }
1115