• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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