• 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 "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19 
20 class GetBindGroupLayoutTests : public ValidationTest {
21   protected:
RenderPipelineFromFragmentShader(const char * shader)22     wgpu::RenderPipeline RenderPipelineFromFragmentShader(const char* shader) {
23         wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
24                 [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
25                     return vec4<f32>();
26                 })");
27 
28         wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, shader);
29 
30         utils::ComboRenderPipelineDescriptor descriptor;
31         descriptor.layout = nullptr;
32         descriptor.vertex.module = vsModule;
33         descriptor.cFragment.module = fsModule;
34         descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
35 
36         return device.CreateRenderPipeline(&descriptor);
37     }
38 };
39 
40 // Test that GetBindGroupLayout returns the same object for the same index
41 // and for matching layouts.
TEST_F(GetBindGroupLayoutTests,SameObject)42 TEST_F(GetBindGroupLayoutTests, SameObject) {
43     // This test works assuming Dawn Native's object deduplication.
44     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
45     // Native.
46     DAWN_SKIP_TEST_IF(UsesWire());
47 
48     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
49         [[block]] struct S {
50             pos : vec4<f32>;
51         };
52         [[group(0), binding(0)]] var<uniform> uniform0 : S;
53         [[group(1), binding(0)]] var<uniform> uniform1 : S;
54 
55         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
56             var pos : vec4<f32> = uniform0.pos;
57             pos = uniform1.pos;
58             return vec4<f32>();
59         })");
60 
61     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
62         [[block]] struct S2 {
63             pos : vec4<f32>;
64         };
65         [[group(2), binding(0)]] var<uniform> uniform2 : S2;
66 
67         [[block]] struct S3 {
68             pos : mat4x4<f32>;
69         };
70         [[group(3), binding(0)]] var<storage, read_write> storage3 : S3;
71 
72         [[stage(fragment)]] fn main() {
73             var pos_u : vec4<f32> = uniform2.pos;
74             var pos_s : mat4x4<f32> = storage3.pos;
75         })");
76 
77     utils::ComboRenderPipelineDescriptor descriptor;
78     descriptor.layout = nullptr;
79     descriptor.vertex.module = vsModule;
80     descriptor.cFragment.module = fsModule;
81     descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
82 
83     wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
84 
85     // The same value is returned for the same index.
86     EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(0).Get());
87 
88     // Matching bind group layouts at different indices are the same object.
89     EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(1).Get());
90 
91     // BGLs with different bindings types are different objects.
92     EXPECT_NE(pipeline.GetBindGroupLayout(2).Get(), pipeline.GetBindGroupLayout(3).Get());
93 
94     // BGLs with different visibilities are different objects.
95     EXPECT_NE(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(2).Get());
96 }
97 
98 // Test that default BindGroupLayouts cannot be used in the creation of a new PipelineLayout
TEST_F(GetBindGroupLayoutTests,DefaultBindGroupLayoutPipelineCompatibility)99 TEST_F(GetBindGroupLayoutTests, DefaultBindGroupLayoutPipelineCompatibility) {
100     wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
101         [[block]] struct S {
102             pos : vec4<f32>;
103         };
104         [[group(0), binding(0)]] var<uniform> uniforms : S;
105 
106         [[stage(fragment)]] fn main() {
107             var pos : vec4<f32> = uniforms.pos;
108         })");
109 
110     ASSERT_DEVICE_ERROR(utils::MakePipelineLayout(device, {pipeline.GetBindGroupLayout(0)}));
111 }
112 
113 // Test that getBindGroupLayout defaults are correct
114 // - shader stage visibility is the stage that adds the binding.
115 // - dynamic offsets is false
TEST_F(GetBindGroupLayoutTests,DefaultShaderStageAndDynamicOffsets)116 TEST_F(GetBindGroupLayoutTests, DefaultShaderStageAndDynamicOffsets) {
117     // This test works assuming Dawn Native's object deduplication.
118     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
119     // Native.
120     DAWN_SKIP_TEST_IF(UsesWire());
121 
122     wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
123         [[block]] struct S {
124             pos : vec4<f32>;
125         };
126         [[group(0), binding(0)]] var<uniform> uniforms : S;
127 
128         [[stage(fragment)]] fn main() {
129             var pos : vec4<f32> = uniforms.pos;
130         })");
131 
132     wgpu::BindGroupLayoutEntry binding = {};
133     binding.binding = 0;
134     binding.buffer.type = wgpu::BufferBindingType::Uniform;
135     binding.buffer.minBindingSize = 4 * sizeof(float);
136 
137     wgpu::BindGroupLayoutDescriptor desc = {};
138     desc.entryCount = 1;
139     desc.entries = &binding;
140 
141     // Check that an otherwise compatible bind group layout doesn't match one created as part of a
142     // default pipeline layout.
143     binding.buffer.hasDynamicOffset = false;
144     binding.visibility = wgpu::ShaderStage::Fragment;
145     EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get());
146 
147     // Check that any change in visibility doesn't match.
148     binding.visibility = wgpu::ShaderStage::Vertex;
149     EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get());
150 
151     binding.visibility = wgpu::ShaderStage::Compute;
152     EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get());
153 
154     // Check that any change in hasDynamicOffsets doesn't match.
155     binding.buffer.hasDynamicOffset = true;
156     binding.visibility = wgpu::ShaderStage::Fragment;
157     EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get());
158 }
159 
TEST_F(GetBindGroupLayoutTests,DefaultTextureSampleType)160 TEST_F(GetBindGroupLayoutTests, DefaultTextureSampleType) {
161     // This test works assuming Dawn Native's object deduplication.
162     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
163     // Native.
164     DAWN_SKIP_TEST_IF(UsesWire());
165 
166     wgpu::BindGroupLayout filteringBGL = utils::MakeBindGroupLayout(
167         device, {{0, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
168                   wgpu::TextureSampleType::Float},
169                  {1, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
170                   wgpu::SamplerBindingType::Filtering}});
171 
172     wgpu::BindGroupLayout nonFilteringBGL = utils::MakeBindGroupLayout(
173         device, {{0, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
174                   wgpu::TextureSampleType::UnfilterableFloat},
175                  {1, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
176                   wgpu::SamplerBindingType::Filtering}});
177 
178     wgpu::ShaderModule emptyVertexModule = utils::CreateShaderModule(device, R"(
179         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
180         [[group(0), binding(1)]] var mySampler : sampler;
181         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
182             _ = myTexture;
183             _ = mySampler;
184             return vec4<f32>();
185         })");
186 
187     wgpu::ShaderModule textureLoadVertexModule = utils::CreateShaderModule(device, R"(
188         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
189         [[group(0), binding(1)]] var mySampler : sampler;
190         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
191             textureLoad(myTexture, vec2<i32>(), 0);
192             _ = mySampler;
193             return vec4<f32>();
194         })");
195 
196     wgpu::ShaderModule textureSampleVertexModule = utils::CreateShaderModule(device, R"(
197         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
198         [[group(0), binding(1)]] var mySampler : sampler;
199         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
200             textureSampleLevel(myTexture, mySampler, vec2<f32>(), 0.0);
201             return vec4<f32>();
202         })");
203 
204     wgpu::ShaderModule unusedTextureFragmentModule = utils::CreateShaderModule(device, R"(
205         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
206         [[group(0), binding(1)]] var mySampler : sampler;
207         [[stage(fragment)]] fn main() {
208             _ = myTexture;
209             _ = mySampler;
210         })");
211 
212     wgpu::ShaderModule textureLoadFragmentModule = utils::CreateShaderModule(device, R"(
213         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
214         [[group(0), binding(1)]] var mySampler : sampler;
215         [[stage(fragment)]] fn main() {
216             textureLoad(myTexture, vec2<i32>(), 0);
217             _ = mySampler;
218         })");
219 
220     wgpu::ShaderModule textureSampleFragmentModule = utils::CreateShaderModule(device, R"(
221         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
222         [[group(0), binding(1)]] var mySampler : sampler;
223         [[stage(fragment)]] fn main() {
224             textureSample(myTexture, mySampler, vec2<f32>());
225         })");
226 
227     auto BGLFromModules = [this](wgpu::ShaderModule vertexModule,
228                                  wgpu::ShaderModule fragmentModule) {
229         utils::ComboRenderPipelineDescriptor descriptor;
230         descriptor.vertex.module = vertexModule;
231         descriptor.cFragment.module = fragmentModule;
232         descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
233         return device.CreateRenderPipeline(&descriptor).GetBindGroupLayout(0);
234     };
235 
236     // Textures not used default to non-filtering
237     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
238         BGLFromModules(emptyVertexModule, unusedTextureFragmentModule).Get(),
239         nonFilteringBGL.Get()));
240     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
241         BGLFromModules(emptyVertexModule, unusedTextureFragmentModule).Get(), filteringBGL.Get()));
242 
243     // Textures used with textureLoad default to non-filtering
244     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
245         BGLFromModules(emptyVertexModule, textureLoadFragmentModule).Get(), nonFilteringBGL.Get()));
246     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
247         BGLFromModules(emptyVertexModule, textureLoadFragmentModule).Get(), filteringBGL.Get()));
248 
249     // Textures used with textureLoad on both stages default to non-filtering
250     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
251         BGLFromModules(textureLoadVertexModule, textureLoadFragmentModule).Get(),
252         nonFilteringBGL.Get()));
253     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
254         BGLFromModules(textureLoadVertexModule, textureLoadFragmentModule).Get(),
255         filteringBGL.Get()));
256 
257     // Textures used with textureSample default to filtering
258     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
259         BGLFromModules(emptyVertexModule, textureSampleFragmentModule).Get(),
260         nonFilteringBGL.Get()));
261     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
262         BGLFromModules(emptyVertexModule, textureSampleFragmentModule).Get(), filteringBGL.Get()));
263     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
264         BGLFromModules(textureSampleVertexModule, unusedTextureFragmentModule).Get(),
265         nonFilteringBGL.Get()));
266     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
267         BGLFromModules(textureSampleVertexModule, unusedTextureFragmentModule).Get(),
268         filteringBGL.Get()));
269 
270     // Textures used with both textureLoad and textureSample default to filtering
271     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
272         BGLFromModules(textureLoadVertexModule, textureSampleFragmentModule).Get(),
273         nonFilteringBGL.Get()));
274     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
275         BGLFromModules(textureLoadVertexModule, textureSampleFragmentModule).Get(),
276         filteringBGL.Get()));
277     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
278         BGLFromModules(textureSampleVertexModule, textureLoadFragmentModule).Get(),
279         nonFilteringBGL.Get()));
280     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
281         BGLFromModules(textureSampleVertexModule, textureLoadFragmentModule).Get(),
282         filteringBGL.Get()));
283 }
284 
285 // Test GetBindGroupLayout works with a compute pipeline
TEST_F(GetBindGroupLayoutTests,ComputePipeline)286 TEST_F(GetBindGroupLayoutTests, ComputePipeline) {
287     // This test works assuming Dawn Native's object deduplication.
288     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
289     // Native.
290     DAWN_SKIP_TEST_IF(UsesWire());
291 
292     wgpu::ShaderModule csModule = utils::CreateShaderModule(device, R"(
293         [[block]] struct S {
294             pos : vec4<f32>;
295         };
296         [[group(0), binding(0)]] var<uniform> uniforms : S;
297 
298         [[stage(compute), workgroup_size(1)]] fn main() {
299             var pos : vec4<f32> = uniforms.pos;
300         })");
301 
302     wgpu::ComputePipelineDescriptor descriptor;
303     descriptor.layout = nullptr;
304     descriptor.compute.module = csModule;
305     descriptor.compute.entryPoint = "main";
306 
307     wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
308 
309     wgpu::BindGroupLayoutEntry binding = {};
310     binding.binding = 0;
311     binding.buffer.type = wgpu::BufferBindingType::Uniform;
312     binding.visibility = wgpu::ShaderStage::Compute;
313     binding.buffer.hasDynamicOffset = false;
314     binding.buffer.minBindingSize = 4 * sizeof(float);
315 
316     wgpu::BindGroupLayoutDescriptor desc = {};
317     desc.entryCount = 1;
318     desc.entries = &binding;
319 
320     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
321         device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
322 }
323 
324 // Test that the binding type matches the shader.
TEST_F(GetBindGroupLayoutTests,BindingType)325 TEST_F(GetBindGroupLayoutTests, BindingType) {
326     // This test works assuming Dawn Native's object deduplication.
327     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
328     // Native.
329     DAWN_SKIP_TEST_IF(UsesWire());
330 
331     wgpu::BindGroupLayoutEntry binding = {};
332     binding.binding = 0;
333     binding.buffer.hasDynamicOffset = false;
334     binding.buffer.minBindingSize = 4 * sizeof(float);
335     binding.visibility = wgpu::ShaderStage::Fragment;
336 
337     wgpu::BindGroupLayoutDescriptor desc = {};
338     desc.entryCount = 1;
339     desc.entries = &binding;
340 
341     {
342         // Storage buffer binding is not supported in vertex shader.
343         binding.visibility = wgpu::ShaderStage::Fragment;
344         binding.buffer.type = wgpu::BufferBindingType::Storage;
345         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
346             [[block]] struct S {
347                 pos : vec4<f32>;
348             };
349             [[group(0), binding(0)]] var<storage, read_write> ssbo : S;
350 
351             [[stage(fragment)]] fn main() {
352                 var pos : vec4<f32> = ssbo.pos;
353             })");
354         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
355             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
356     }
357     {
358         binding.buffer.type = wgpu::BufferBindingType::Uniform;
359         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
360             [[block]] struct S {
361                 pos : vec4<f32>;
362             };
363             [[group(0), binding(0)]] var<uniform> uniforms : S;
364 
365             [[stage(fragment)]] fn main() {
366                 var pos : vec4<f32> = uniforms.pos;
367             })");
368         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
369             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
370     }
371 
372     {
373         binding.buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
374         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
375             [[block]] struct S {
376                 pos : vec4<f32>;
377             };
378             [[group(0), binding(0)]] var<storage, read> ssbo : S;
379 
380             [[stage(fragment)]] fn main() {
381                 var pos : vec4<f32> = ssbo.pos;
382             })");
383         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
384             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
385     }
386 
387     binding.buffer.type = wgpu::BufferBindingType::Undefined;
388     binding.buffer.minBindingSize = 0;
389     {
390         binding.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
391         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
392             [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
393 
394             [[stage(fragment)]] fn main() {
395                 textureDimensions(myTexture);
396             })");
397         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
398             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
399     }
400 
401     {
402         binding.texture.multisampled = true;
403         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
404             [[group(0), binding(0)]] var myTexture : texture_multisampled_2d<f32>;
405 
406             [[stage(fragment)]] fn main() {
407                 textureDimensions(myTexture);
408             })");
409         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
410             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
411     }
412 
413     binding.texture.sampleType = wgpu::TextureSampleType::Undefined;
414     {
415         binding.sampler.type = wgpu::SamplerBindingType::Filtering;
416         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
417             [[group(0), binding(0)]] var mySampler: sampler;
418 
419             [[stage(fragment)]] fn main() {
420                 _ = mySampler;
421             })");
422         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
423             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
424     }
425 }
426 
427 // Tests that the external texture binding type matches with a texture_external declared in the
428 // shader.
TEST_F(GetBindGroupLayoutTests,ExternalTextureBindingType)429 TEST_F(GetBindGroupLayoutTests, ExternalTextureBindingType) {
430     // This test works assuming Dawn Native's object deduplication.
431     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
432     // Native.
433     DAWN_SKIP_TEST_IF(UsesWire());
434 
435     wgpu::BindGroupLayoutEntry binding = {};
436     binding.binding = 0;
437     binding.visibility = wgpu::ShaderStage::Fragment;
438 
439     wgpu::BindGroupLayoutDescriptor desc = {};
440     desc.entryCount = 1;
441     desc.entries = &binding;
442 
443     binding.nextInChain = &utils::kExternalTextureBindingLayout;
444     wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
445             [[group(0), binding(0)]] var myExternalTexture: texture_external;
446 
447             [[stage(fragment)]] fn main() {
448                _ = myExternalTexture;
449             })");
450     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
451         device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
452 }
453 
454 // Test that texture view dimension matches the shader.
TEST_F(GetBindGroupLayoutTests,ViewDimension)455 TEST_F(GetBindGroupLayoutTests, ViewDimension) {
456     // This test works assuming Dawn Native's object deduplication.
457     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
458     // Native.
459     DAWN_SKIP_TEST_IF(UsesWire());
460 
461     wgpu::BindGroupLayoutEntry binding = {};
462     binding.binding = 0;
463     binding.visibility = wgpu::ShaderStage::Fragment;
464     binding.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
465 
466     wgpu::BindGroupLayoutDescriptor desc = {};
467     desc.entryCount = 1;
468     desc.entries = &binding;
469 
470     {
471         binding.texture.viewDimension = wgpu::TextureViewDimension::e1D;
472         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
473             [[group(0), binding(0)]] var myTexture : texture_1d<f32>;
474 
475             [[stage(fragment)]] fn main() {
476                 textureDimensions(myTexture);
477             })");
478         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
479             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
480     }
481 
482     {
483         binding.texture.viewDimension = wgpu::TextureViewDimension::e2D;
484         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
485             [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
486 
487             [[stage(fragment)]] fn main() {
488                 textureDimensions(myTexture);
489             })");
490         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
491             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
492     }
493 
494     {
495         binding.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
496         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
497             [[group(0), binding(0)]] var myTexture : texture_2d_array<f32>;
498 
499             [[stage(fragment)]] fn main() {
500                 textureDimensions(myTexture);
501             })");
502         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
503             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
504     }
505 
506     {
507         binding.texture.viewDimension = wgpu::TextureViewDimension::e3D;
508         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
509             [[group(0), binding(0)]] var myTexture : texture_3d<f32>;
510 
511             [[stage(fragment)]] fn main() {
512                 textureDimensions(myTexture);
513             })");
514         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
515             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
516     }
517 
518     {
519         binding.texture.viewDimension = wgpu::TextureViewDimension::Cube;
520         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
521             [[group(0), binding(0)]] var myTexture : texture_cube<f32>;
522 
523             [[stage(fragment)]] fn main() {
524                 textureDimensions(myTexture);
525             })");
526         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
527             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
528     }
529 
530     {
531         binding.texture.viewDimension = wgpu::TextureViewDimension::CubeArray;
532         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
533             [[group(0), binding(0)]] var myTexture : texture_cube_array<f32>;
534 
535             [[stage(fragment)]] fn main() {
536                 textureDimensions(myTexture);
537             })");
538         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
539             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
540     }
541 }
542 
543 // Test that texture component type matches the shader.
TEST_F(GetBindGroupLayoutTests,TextureComponentType)544 TEST_F(GetBindGroupLayoutTests, TextureComponentType) {
545     // This test works assuming Dawn Native's object deduplication.
546     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
547     // Native.
548     DAWN_SKIP_TEST_IF(UsesWire());
549 
550     wgpu::BindGroupLayoutEntry binding = {};
551     binding.binding = 0;
552     binding.visibility = wgpu::ShaderStage::Fragment;
553 
554     wgpu::BindGroupLayoutDescriptor desc = {};
555     desc.entryCount = 1;
556     desc.entries = &binding;
557 
558     {
559         binding.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
560         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
561             [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
562 
563             [[stage(fragment)]] fn main() {
564                 textureDimensions(myTexture);
565             })");
566         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
567             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
568     }
569 
570     {
571         binding.texture.sampleType = wgpu::TextureSampleType::Sint;
572         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
573             [[group(0), binding(0)]] var myTexture : texture_2d<i32>;
574 
575             [[stage(fragment)]] fn main() {
576                 textureDimensions(myTexture);
577             })");
578         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
579             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
580     }
581 
582     {
583         binding.texture.sampleType = wgpu::TextureSampleType::Uint;
584         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
585             [[group(0), binding(0)]] var myTexture : texture_2d<u32>;
586 
587             [[stage(fragment)]] fn main() {
588                 textureDimensions(myTexture);
589             })");
590         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
591             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
592     }
593 }
594 
595 // Test that binding= indices match.
TEST_F(GetBindGroupLayoutTests,BindingIndices)596 TEST_F(GetBindGroupLayoutTests, BindingIndices) {
597     // This test works assuming Dawn Native's object deduplication.
598     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
599     // Native.
600     DAWN_SKIP_TEST_IF(UsesWire());
601 
602     wgpu::BindGroupLayoutEntry binding = {};
603     binding.visibility = wgpu::ShaderStage::Fragment;
604     binding.buffer.type = wgpu::BufferBindingType::Uniform;
605     binding.buffer.hasDynamicOffset = false;
606     binding.buffer.minBindingSize = 4 * sizeof(float);
607 
608     wgpu::BindGroupLayoutDescriptor desc = {};
609     desc.entryCount = 1;
610     desc.entries = &binding;
611 
612     {
613         binding.binding = 0;
614         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
615             [[block]] struct S {
616                 pos : vec4<f32>;
617             };
618             [[group(0), binding(0)]] var<uniform> uniforms : S;
619 
620             [[stage(fragment)]] fn main() {
621                 var pos : vec4<f32> = uniforms.pos;
622             })");
623         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
624             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
625     }
626 
627     {
628         binding.binding = 1;
629         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
630             [[block]] struct S {
631                 pos : vec4<f32>;
632             };
633             [[group(0), binding(1)]] var<uniform> uniforms : S;
634 
635             [[stage(fragment)]] fn main() {
636                 var pos : vec4<f32> = uniforms.pos;
637             })");
638         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
639             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
640     }
641 
642     {
643         binding.binding = 2;
644         wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
645             [[block]] struct S {
646                 pos : vec4<f32>;
647             };
648             [[group(0), binding(1)]] var<uniform> uniforms : S;
649 
650             [[stage(fragment)]] fn main() {
651                 var pos : vec4<f32> = uniforms.pos;
652             })");
653         EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
654             device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()));
655     }
656 }
657 
658 // Test it is valid to have duplicate bindings in the shaders.
TEST_F(GetBindGroupLayoutTests,DuplicateBinding)659 TEST_F(GetBindGroupLayoutTests, DuplicateBinding) {
660     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
661         [[block]] struct S {
662             pos : vec4<f32>;
663         };
664         [[group(0), binding(0)]] var<uniform> uniform0 : S;
665         [[group(1), binding(0)]] var<uniform> uniform1 : S;
666 
667         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
668             var pos : vec4<f32> = uniform0.pos;
669             pos = uniform1.pos;
670             return vec4<f32>();
671         })");
672 
673     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
674         [[block]] struct S {
675             pos : vec4<f32>;
676         };
677         [[group(1), binding(0)]] var<uniform> uniforms : S;
678 
679         [[stage(fragment)]] fn main() {
680             var pos : vec4<f32> = uniforms.pos;
681         })");
682 
683     utils::ComboRenderPipelineDescriptor descriptor;
684     descriptor.layout = nullptr;
685     descriptor.vertex.module = vsModule;
686     descriptor.cFragment.module = fsModule;
687     descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
688 
689     device.CreateRenderPipeline(&descriptor);
690 }
691 
692 // Test that minBufferSize is set on the BGL and that the max of the min buffer sizes is used.
TEST_F(GetBindGroupLayoutTests,MinBufferSize)693 TEST_F(GetBindGroupLayoutTests, MinBufferSize) {
694     // This test works assuming Dawn Native's object deduplication.
695     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
696     // Native.
697     DAWN_SKIP_TEST_IF(UsesWire());
698 
699     wgpu::ShaderModule vsModule4 = utils::CreateShaderModule(device, R"(
700         [[block]] struct S {
701             pos : f32;
702         };
703         [[group(0), binding(0)]] var<uniform> uniforms : S;
704 
705         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
706             var pos : f32 = uniforms.pos;
707             return vec4<f32>();
708         })");
709 
710     wgpu::ShaderModule vsModule64 = utils::CreateShaderModule(device, R"(
711         [[block]] struct S {
712             pos : mat4x4<f32>;
713         };
714         [[group(0), binding(0)]] var<uniform> uniforms : S;
715 
716         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
717             var pos : mat4x4<f32> = uniforms.pos;
718             return vec4<f32>();
719         })");
720 
721     wgpu::ShaderModule fsModule4 = utils::CreateShaderModule(device, R"(
722         [[block]] struct S {
723             pos : f32;
724         };
725         [[group(0), binding(0)]] var<uniform> uniforms : S;
726 
727         [[stage(fragment)]] fn main() {
728             var pos : f32 = uniforms.pos;
729         })");
730 
731     wgpu::ShaderModule fsModule64 = utils::CreateShaderModule(device, R"(
732         [[block]] struct S {
733             pos : mat4x4<f32>;
734         };
735         [[group(0), binding(0)]] var<uniform> uniforms : S;
736 
737         [[stage(fragment)]] fn main() {
738             var pos : mat4x4<f32> = uniforms.pos;
739         })");
740 
741     // Create BGLs with minBufferBindingSize 4 and 64.
742     wgpu::BindGroupLayoutEntry binding = {};
743     binding.binding = 0;
744     binding.buffer.type = wgpu::BufferBindingType::Uniform;
745     binding.visibility = wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Vertex;
746 
747     wgpu::BindGroupLayoutDescriptor desc = {};
748     desc.entryCount = 1;
749     desc.entries = &binding;
750 
751     binding.buffer.minBindingSize = 4;
752     wgpu::BindGroupLayout bgl4 = device.CreateBindGroupLayout(&desc);
753     binding.buffer.minBindingSize = 64;
754     wgpu::BindGroupLayout bgl64 = device.CreateBindGroupLayout(&desc);
755 
756     utils::ComboRenderPipelineDescriptor descriptor;
757     descriptor.layout = nullptr;
758     descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
759 
760     // Check with both stages using 4 bytes.
761     {
762         descriptor.vertex.module = vsModule4;
763         descriptor.cFragment.module = fsModule4;
764         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
765         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
766             pipeline.GetBindGroupLayout(0).Get(), bgl4.Get()));
767     }
768 
769     // Check that the max is taken between 4 and 64.
770     {
771         descriptor.vertex.module = vsModule64;
772         descriptor.cFragment.module = fsModule4;
773         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
774         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
775             pipeline.GetBindGroupLayout(0).Get(), bgl64.Get()));
776     }
777 
778     // Check that the order doesn't change that the max is taken.
779     {
780         descriptor.vertex.module = vsModule4;
781         descriptor.cFragment.module = fsModule64;
782         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
783         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
784             pipeline.GetBindGroupLayout(0).Get(), bgl64.Get()));
785     }
786 }
787 
788 // Test that the visibility is correctly aggregated if two stages have the exact same binding.
TEST_F(GetBindGroupLayoutTests,StageAggregation)789 TEST_F(GetBindGroupLayoutTests, StageAggregation) {
790     // This test works assuming Dawn Native's object deduplication.
791     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
792     // Native.
793     DAWN_SKIP_TEST_IF(UsesWire());
794 
795     wgpu::ShaderModule vsModuleNoSampler = utils::CreateShaderModule(device, R"(
796         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
797             return vec4<f32>();
798         })");
799 
800     wgpu::ShaderModule vsModuleSampler = utils::CreateShaderModule(device, R"(
801         [[group(0), binding(0)]] var mySampler: sampler;
802         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
803             _ = mySampler;
804             return vec4<f32>();
805         })");
806 
807     wgpu::ShaderModule fsModuleNoSampler = utils::CreateShaderModule(device, R"(
808         [[stage(fragment)]] fn main() {
809         })");
810 
811     wgpu::ShaderModule fsModuleSampler = utils::CreateShaderModule(device, R"(
812         [[group(0), binding(0)]] var mySampler: sampler;
813         [[stage(fragment)]] fn main() {
814             _ = mySampler;
815         })");
816 
817     // Create BGLs with minBufferBindingSize 4 and 64.
818     wgpu::BindGroupLayoutEntry binding = {};
819     binding.binding = 0;
820     binding.sampler.type = wgpu::SamplerBindingType::Filtering;
821 
822     wgpu::BindGroupLayoutDescriptor desc = {};
823     desc.entryCount = 1;
824     desc.entries = &binding;
825 
826     utils::ComboRenderPipelineDescriptor descriptor;
827     descriptor.layout = nullptr;
828     descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
829 
830     // Check with only the vertex shader using the sampler
831     {
832         descriptor.vertex.module = vsModuleSampler;
833         descriptor.cFragment.module = fsModuleNoSampler;
834         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
835 
836         binding.visibility = wgpu::ShaderStage::Vertex;
837         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
838             pipeline.GetBindGroupLayout(0).Get(), device.CreateBindGroupLayout(&desc).Get()));
839     }
840 
841     // Check with only the fragment shader using the sampler
842     {
843         descriptor.vertex.module = vsModuleNoSampler;
844         descriptor.cFragment.module = fsModuleSampler;
845         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
846 
847         binding.visibility = wgpu::ShaderStage::Fragment;
848         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
849             pipeline.GetBindGroupLayout(0).Get(), device.CreateBindGroupLayout(&desc).Get()));
850     }
851 
852     // Check with both shaders using the sampler
853     {
854         descriptor.vertex.module = vsModuleSampler;
855         descriptor.cFragment.module = fsModuleSampler;
856         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
857 
858         binding.visibility = wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Vertex;
859         EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
860             pipeline.GetBindGroupLayout(0).Get(), device.CreateBindGroupLayout(&desc).Get()));
861     }
862 }
863 
864 // Test it is invalid to have conflicting binding types in the shaders.
TEST_F(GetBindGroupLayoutTests,ConflictingBindingType)865 TEST_F(GetBindGroupLayoutTests, ConflictingBindingType) {
866     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
867         [[block]] struct S {
868             pos : vec4<f32>;
869         };
870         [[group(0), binding(0)]] var<uniform> ubo : S;
871 
872         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
873             var pos : vec4<f32> = ubo.pos;
874             return vec4<f32>();
875         })");
876 
877     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
878         [[block]] struct S {
879             pos : vec4<f32>;
880         };
881         [[group(0), binding(0)]] var<storage, read_write> ssbo : S;
882 
883         [[stage(fragment)]] fn main() {
884             var pos : vec4<f32> = ssbo.pos;
885         })");
886 
887     utils::ComboRenderPipelineDescriptor descriptor;
888     descriptor.layout = nullptr;
889     descriptor.vertex.module = vsModule;
890     descriptor.cFragment.module = fsModule;
891 
892     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
893 }
894 
895 // Test it is invalid to have conflicting binding texture multisampling in the shaders.
TEST_F(GetBindGroupLayoutTests,ConflictingBindingTextureMultisampling)896 TEST_F(GetBindGroupLayoutTests, ConflictingBindingTextureMultisampling) {
897     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
898         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
899 
900         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
901             textureDimensions(myTexture);
902             return vec4<f32>();
903         })");
904 
905     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
906         [[group(0), binding(0)]] var myTexture : texture_multisampled_2d<f32>;
907 
908         [[stage(fragment)]] fn main() {
909             textureDimensions(myTexture);
910         })");
911 
912     utils::ComboRenderPipelineDescriptor descriptor;
913     descriptor.layout = nullptr;
914     descriptor.vertex.module = vsModule;
915     descriptor.cFragment.module = fsModule;
916 
917     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
918 }
919 
920 // Test it is invalid to have conflicting binding texture dimension in the shaders.
TEST_F(GetBindGroupLayoutTests,ConflictingBindingViewDimension)921 TEST_F(GetBindGroupLayoutTests, ConflictingBindingViewDimension) {
922     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
923         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
924 
925         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
926             textureDimensions(myTexture);
927             return vec4<f32>();
928         })");
929 
930     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
931         [[group(0), binding(0)]] var myTexture : texture_3d<f32>;
932 
933         [[stage(fragment)]] fn main() {
934             textureDimensions(myTexture);
935         })");
936 
937     utils::ComboRenderPipelineDescriptor descriptor;
938     descriptor.layout = nullptr;
939     descriptor.vertex.module = vsModule;
940     descriptor.cFragment.module = fsModule;
941 
942     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
943 }
944 
945 // Test it is invalid to have conflicting binding texture component type in the shaders.
TEST_F(GetBindGroupLayoutTests,ConflictingBindingTextureComponentType)946 TEST_F(GetBindGroupLayoutTests, ConflictingBindingTextureComponentType) {
947     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
948         [[group(0), binding(0)]] var myTexture : texture_2d<f32>;
949 
950         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
951             textureDimensions(myTexture);
952             return vec4<f32>();
953         })");
954 
955     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
956         [[group(0), binding(0)]] var myTexture : texture_2d<i32>;
957 
958         [[stage(fragment)]] fn main() {
959             textureDimensions(myTexture);
960         })");
961 
962     utils::ComboRenderPipelineDescriptor descriptor;
963     descriptor.layout = nullptr;
964     descriptor.vertex.module = vsModule;
965     descriptor.cFragment.module = fsModule;
966 
967     ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
968 }
969 
970 // Test it is an error to query an out of range bind group layout.
TEST_F(GetBindGroupLayoutTests,OutOfRangeIndex)971 TEST_F(GetBindGroupLayoutTests, OutOfRangeIndex) {
972     ASSERT_DEVICE_ERROR(RenderPipelineFromFragmentShader(R"(
973         [[stage(fragment)]] fn main() {
974         })")
975                             .GetBindGroupLayout(kMaxBindGroups));
976 
977     ASSERT_DEVICE_ERROR(RenderPipelineFromFragmentShader(R"(
978         [[stage(fragment)]] fn main() {
979         })")
980                             .GetBindGroupLayout(kMaxBindGroups + 1));
981 }
982 
983 // Test that unused indices return the empty bind group layout.
TEST_F(GetBindGroupLayoutTests,UnusedIndex)984 TEST_F(GetBindGroupLayoutTests, UnusedIndex) {
985     // This test works assuming Dawn Native's object deduplication.
986     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
987     // Native.
988     DAWN_SKIP_TEST_IF(UsesWire());
989 
990     wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
991         [[block]] struct S {
992             pos : vec4<f32>;
993         };
994         [[group(0), binding(0)]] var<uniform> uniforms0 : S;
995         [[group(2), binding(0)]] var<uniform> uniforms2 : S;
996 
997         [[stage(fragment)]] fn main() {
998             var pos : vec4<f32> = uniforms0.pos;
999             pos = uniforms2.pos;
1000         })");
1001 
1002     wgpu::BindGroupLayoutDescriptor desc = {};
1003     desc.entryCount = 0;
1004     desc.entries = nullptr;
1005 
1006     wgpu::BindGroupLayout emptyBindGroupLayout = device.CreateBindGroupLayout(&desc);
1007 
1008     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
1009         pipeline.GetBindGroupLayout(0).Get(), emptyBindGroupLayout.Get()));  // Used
1010     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
1011         pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get()));  // Not Used.
1012     EXPECT_FALSE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
1013         pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get()));  // Used.
1014     EXPECT_TRUE(dawn_native::BindGroupLayoutBindingsEqualForTesting(
1015         pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get()));  // Not used
1016 }
1017 
1018 // Test that after explicitly creating a pipeline with a pipeline layout, calling
1019 // GetBindGroupLayout reflects the same bind group layouts.
TEST_F(GetBindGroupLayoutTests,Reflection)1020 TEST_F(GetBindGroupLayoutTests, Reflection) {
1021     // This test works assuming Dawn Native's object deduplication.
1022     // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
1023     // Native.
1024     DAWN_SKIP_TEST_IF(UsesWire());
1025 
1026     wgpu::BindGroupLayoutEntry binding = {};
1027     binding.binding = 0;
1028     binding.buffer.type = wgpu::BufferBindingType::Uniform;
1029     binding.visibility = wgpu::ShaderStage::Vertex;
1030 
1031     wgpu::BindGroupLayoutDescriptor bglDesc = {};
1032     bglDesc.entryCount = 1;
1033     bglDesc.entries = &binding;
1034 
1035     wgpu::BindGroupLayout bindGroupLayout = device.CreateBindGroupLayout(&bglDesc);
1036 
1037     wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = {};
1038     pipelineLayoutDesc.bindGroupLayoutCount = 1;
1039     pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
1040 
1041     wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc);
1042 
1043     wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
1044         [[block]] struct S {
1045             pos : vec4<f32>;
1046         };
1047         [[group(0), binding(0)]] var<uniform> uniforms : S;
1048 
1049         [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
1050             var pos : vec4<f32> = uniforms.pos;
1051             return vec4<f32>();
1052         })");
1053 
1054     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
1055         [[stage(fragment)]] fn main() {
1056         })");
1057 
1058     utils::ComboRenderPipelineDescriptor pipelineDesc;
1059     pipelineDesc.layout = pipelineLayout;
1060     pipelineDesc.vertex.module = vsModule;
1061     pipelineDesc.cFragment.module = fsModule;
1062     pipelineDesc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
1063 
1064     wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
1065 
1066     EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), bindGroupLayout.Get());
1067 
1068     {
1069         wgpu::BindGroupLayoutDescriptor emptyDesc = {};
1070         emptyDesc.entryCount = 0;
1071         emptyDesc.entries = nullptr;
1072 
1073         wgpu::BindGroupLayout emptyBindGroupLayout = device.CreateBindGroupLayout(&emptyDesc);
1074 
1075         // Check that the rest of the bind group layouts reflect the empty one.
1076         EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get());
1077         EXPECT_EQ(pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get());
1078         EXPECT_EQ(pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get());
1079     }
1080 }
1081 
1082 // Test that fragment output validation is for the correct entryPoint
TEST_F(GetBindGroupLayoutTests,FromCorrectEntryPoint)1083 TEST_F(GetBindGroupLayoutTests, FromCorrectEntryPoint) {
1084     wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
1085         [[block]] struct Data {
1086             data : f32;
1087         };
1088         [[group(0), binding(0)]] var<storage, read_write> data0 : Data;
1089         [[group(0), binding(1)]] var<storage, read_write> data1 : Data;
1090 
1091         [[stage(compute), workgroup_size(1)]] fn compute0() {
1092             data0.data = 0.0;
1093         }
1094 
1095         [[stage(compute), workgroup_size(1)]] fn compute1() {
1096             data1.data = 0.0;
1097         }
1098     )");
1099 
1100     wgpu::ComputePipelineDescriptor pipelineDesc;
1101     pipelineDesc.compute.module = module;
1102 
1103     // Get each entryPoint's BGL.
1104     pipelineDesc.compute.entryPoint = "compute0";
1105     wgpu::ComputePipeline pipeline0 = device.CreateComputePipeline(&pipelineDesc);
1106     wgpu::BindGroupLayout bgl0 = pipeline0.GetBindGroupLayout(0);
1107 
1108     pipelineDesc.compute.entryPoint = "compute1";
1109     wgpu::ComputePipeline pipeline1 = device.CreateComputePipeline(&pipelineDesc);
1110     wgpu::BindGroupLayout bgl1 = pipeline1.GetBindGroupLayout(0);
1111 
1112     // Create the buffer used in the bindgroups.
1113     wgpu::BufferDescriptor bufferDesc;
1114     bufferDesc.size = 4;
1115     bufferDesc.usage = wgpu::BufferUsage::Storage;
1116     wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
1117 
1118     // Success case, the BGL matches the descriptor for the bindgroup.
1119     utils::MakeBindGroup(device, bgl0, {{0, buffer}});
1120     utils::MakeBindGroup(device, bgl1, {{1, buffer}});
1121 
1122     // Error case, the BGL doesn't match the descriptor for the bindgroup.
1123     ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl0, {{1, buffer}}));
1124     ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl1, {{0, buffer}}));
1125 }
1126