| // Copyright 2019 The Dawn Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "tests/unittests/validation/ValidationTest.h" |
| |
| #include "utils/ComboRenderPipelineDescriptor.h" |
| #include "utils/WGPUHelpers.h" |
| |
| class GetBindGroupLayoutTests : public ValidationTest { |
| protected: |
| static constexpr wgpu::ShaderStage kVisibilityAll = |
| wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Vertex; |
| |
| wgpu::RenderPipeline RenderPipelineFromFragmentShader(const char* shader) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| void main() { |
| })"); |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, shader); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| return device.CreateRenderPipeline(&descriptor); |
| } |
| }; |
| |
| // Test that GetBindGroupLayout returns the same object for the same index |
| // and for matching layouts. |
| TEST_F(GetBindGroupLayoutTests, SameObject) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UniformBuffer1 { |
| vec4 pos1; |
| }; |
| |
| layout(set = 1, binding = 0) uniform UniformBuffer2 { |
| vec4 pos2; |
| }; |
| |
| void main() { |
| })"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 2, binding = 0) uniform UniformBuffer3 { |
| vec4 pos3; |
| }; |
| |
| layout(set = 3, binding = 0) buffer StorageBuffer { |
| mat4 pos4; |
| }; |
| |
| void main() { |
| })"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor); |
| |
| EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| |
| EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), pipeline.GetBindGroupLayout(1).Get()); |
| |
| EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(1).Get()); |
| |
| EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(2).Get()); |
| |
| EXPECT_NE(pipeline.GetBindGroupLayout(0).Get(), pipeline.GetBindGroupLayout(3).Get()); |
| } |
| |
| // Test that getBindGroupLayout defaults are correct |
| // - shader stage visibility is All |
| // - dynamic offsets is false |
| TEST_F(GetBindGroupLayoutTests, DefaultShaderStageAndDynamicOffsets) { |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UniformBuffer { |
| vec4 pos; |
| }; |
| |
| void main() { |
| })"); |
| |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::UniformBuffer; |
| binding.multisampled = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| // Check that visibility and dynamic offsets match |
| binding.hasDynamicOffset = false; |
| binding.visibility = kVisibilityAll; |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| |
| // Check that any change in visibility doesn't match. |
| binding.visibility = wgpu::ShaderStage::Vertex; |
| EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| |
| binding.visibility = wgpu::ShaderStage::Fragment; |
| EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| |
| binding.visibility = wgpu::ShaderStage::Compute; |
| EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| |
| // Check that any change in hasDynamicOffsets doesn't match. |
| binding.hasDynamicOffset = true; |
| binding.visibility = kVisibilityAll; |
| EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| // Test GetBindGroupLayout works with a compute pipeline |
| TEST_F(GetBindGroupLayoutTests, ComputePipeline) { |
| wgpu::ShaderModule csModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UniformBuffer { |
| vec4 pos; |
| }; |
| void main() { |
| })"); |
| |
| wgpu::ComputePipelineDescriptor descriptor; |
| descriptor.layout = nullptr; |
| descriptor.computeStage.module = csModule; |
| descriptor.computeStage.entryPoint = "main"; |
| |
| wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor); |
| |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::UniformBuffer; |
| binding.visibility = kVisibilityAll; |
| binding.hasDynamicOffset = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| // Test that the binding type matches the shader. |
| TEST_F(GetBindGroupLayoutTests, BindingType) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.hasDynamicOffset = false; |
| binding.multisampled = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| { |
| // Storage buffer binding is not supported in vertex shader. |
| binding.visibility = wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment; |
| binding.type = wgpu::BindingType::StorageBuffer; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) buffer Storage { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| binding.visibility = kVisibilityAll; |
| { |
| binding.type = wgpu::BindingType::UniformBuffer; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.type = wgpu::BindingType::ReadonlyStorageBuffer; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) readonly buffer Storage { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.type = wgpu::BindingType::SampledTexture; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.type = wgpu::BindingType::Sampler; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler samp; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| } |
| |
| // Test that multisampling matches the shader. |
| TEST_F(GetBindGroupLayoutTests, Multisampled) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::SampledTexture; |
| binding.visibility = kVisibilityAll; |
| binding.hasDynamicOffset = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| { |
| binding.multisampled = false; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| // TODO: Support multisampling |
| GTEST_SKIP() << "Multisampling unimplemented"; |
| { |
| binding.multisampled = true; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2DMS tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| } |
| |
| // Test that texture view dimension matches the shader. |
| TEST_F(GetBindGroupLayoutTests, TextureDimension) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::SampledTexture; |
| binding.visibility = kVisibilityAll; |
| binding.hasDynamicOffset = false; |
| binding.multisampled = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::e1D; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture1D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::e2D; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::e2DArray; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2DArray tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::e3D; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture3D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::Cube; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform textureCube tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureDimension = wgpu::TextureViewDimension::CubeArray; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform textureCubeArray tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| } |
| |
| // Test that texture component type matches the shader. |
| TEST_F(GetBindGroupLayoutTests, TextureComponentType) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::SampledTexture; |
| binding.visibility = kVisibilityAll; |
| binding.hasDynamicOffset = false; |
| binding.multisampled = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| { |
| binding.textureComponentType = wgpu::TextureComponentType::Float; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureComponentType = wgpu::TextureComponentType::Sint; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform itexture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.textureComponentType = wgpu::TextureComponentType::Uint; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform utexture2D tex; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| } |
| |
| // Test that binding= indices match. |
| TEST_F(GetBindGroupLayoutTests, BindingIndices) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.type = wgpu::BindingType::UniformBuffer; |
| binding.visibility = kVisibilityAll; |
| binding.hasDynamicOffset = false; |
| binding.multisampled = false; |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 1; |
| desc.bindings = &binding; |
| |
| { |
| binding.binding = 0; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.binding = 1; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 1) uniform Buffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| |
| { |
| binding.binding = 2; |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 1) uniform Buffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| EXPECT_NE(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get()); |
| } |
| } |
| |
| // Test it is valid to have duplicate bindings in the shaders. |
| TEST_F(GetBindGroupLayoutTests, DuplicateBinding) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UniformBuffer1 { |
| vec4 pos1; |
| }; |
| |
| layout(set = 1, binding = 0) uniform UniformBuffer2 { |
| vec4 pos2; |
| }; |
| |
| void main() {})"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 1, binding = 0) uniform UniformBuffer3 { |
| vec4 pos3; |
| }; |
| |
| void main() {})"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| device.CreateRenderPipeline(&descriptor); |
| } |
| |
| // Test it is invalid to have conflicting binding types in the shaders. |
| TEST_F(GetBindGroupLayoutTests, ConflictingBindingType) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform UniformBuffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 0, binding = 0) buffer StorageBuffer { |
| vec4 pos; |
| }; |
| |
| void main() {})"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); |
| } |
| |
| // Test it is invalid to have conflicting binding texture multisampling in the shaders. |
| TEST_F(GetBindGroupLayoutTests, ConflictingBindingTextureMultisampling) { |
| // TODO: Support multisampling |
| GTEST_SKIP() << "Multisampling unimplemented"; |
| |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2DMS tex; |
| |
| void main() {})"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); |
| } |
| |
| // Test it is invalid to have conflicting binding texture dimension in the shaders. |
| TEST_F(GetBindGroupLayoutTests, ConflictingBindingTextureDimension) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture3D tex; |
| |
| void main() {})"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); |
| } |
| |
| // Test it is invalid to have conflicting binding texture component type in the shaders. |
| TEST_F(GetBindGroupLayoutTests, ConflictingBindingTextureComponentType) { |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform texture2D tex; |
| |
| void main() {})"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform utexture2D tex; |
| |
| void main() {})"); |
| |
| utils::ComboRenderPipelineDescriptor descriptor(device); |
| descriptor.layout = nullptr; |
| descriptor.vertexStage.module = vsModule; |
| descriptor.cFragmentStage.module = fsModule; |
| |
| ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); |
| } |
| |
| // Test it is an error to query an out of range bind group layout. |
| TEST_F(GetBindGroupLayoutTests, OutOfRangeIndex) { |
| ASSERT_DEVICE_ERROR(RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer1 { |
| vec4 pos1; |
| }; |
| void main() {})") |
| .GetBindGroupLayout(kMaxBindGroups)); |
| |
| ASSERT_DEVICE_ERROR(RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer1 { |
| vec4 pos1; |
| }; |
| void main() {})") |
| .GetBindGroupLayout(kMaxBindGroups + 1)); |
| } |
| |
| // Test that unused indices return the empty bind group layout. |
| TEST_F(GetBindGroupLayoutTests, UnusedIndex) { |
| wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer1 { |
| vec4 pos1; |
| }; |
| |
| layout(set = 2, binding = 0) uniform Buffer2 { |
| vec4 pos2; |
| }; |
| |
| void main() {})"); |
| |
| wgpu::BindGroupLayoutDescriptor desc = {}; |
| desc.bindingCount = 0; |
| desc.bindings = nullptr; |
| |
| wgpu::BindGroupLayout emptyBindGroupLayout = device.CreateBindGroupLayout(&desc); |
| |
| EXPECT_NE(pipeline.GetBindGroupLayout(0).Get(), emptyBindGroupLayout.Get()); // Used |
| EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get()); // Not Used. |
| EXPECT_NE(pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get()); // Used. |
| EXPECT_EQ(pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get()); // Not used |
| } |
| |
| // Test that after explicitly creating a pipeline with a pipeline layout, calling |
| // GetBindGroupLayout reflects the same bind group layouts. |
| TEST_F(GetBindGroupLayoutTests, Reflection) { |
| wgpu::BindGroupLayoutBinding binding = {}; |
| binding.binding = 0; |
| binding.type = wgpu::BindingType::UniformBuffer; |
| binding.visibility = wgpu::ShaderStage::Vertex; |
| |
| wgpu::BindGroupLayoutDescriptor bglDesc = {}; |
| bglDesc.bindingCount = 1; |
| bglDesc.bindings = &binding; |
| |
| wgpu::BindGroupLayout bindGroupLayout = device.CreateBindGroupLayout(&bglDesc); |
| |
| wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = {}; |
| pipelineLayoutDesc.bindGroupLayoutCount = 1; |
| pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout; |
| |
| wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc); |
| |
| wgpu::ShaderModule vsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( |
| #version 450 |
| layout(set = 0, binding = 0) uniform Buffer1 { |
| vec4 pos1; |
| }; |
| |
| void main() { |
| })"); |
| |
| wgpu::ShaderModule fsModule = |
| utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( |
| #version 450 |
| void main() { |
| })"); |
| |
| utils::ComboRenderPipelineDescriptor pipelineDesc(device); |
| pipelineDesc.layout = pipelineLayout; |
| pipelineDesc.vertexStage.module = vsModule; |
| pipelineDesc.cFragmentStage.module = fsModule; |
| |
| wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc); |
| |
| EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), bindGroupLayout.Get()); |
| |
| { |
| wgpu::BindGroupLayoutDescriptor emptyDesc = {}; |
| emptyDesc.bindingCount = 0; |
| emptyDesc.bindings = nullptr; |
| |
| wgpu::BindGroupLayout emptyBindGroupLayout = device.CreateBindGroupLayout(&emptyDesc); |
| |
| // Check that the rest of the bind group layouts reflect the empty one. |
| EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get()); |
| EXPECT_EQ(pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get()); |
| EXPECT_EQ(pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get()); |
| } |
| } |