diff --git a/src/dawn_native/BindGroup.cpp b/src/dawn_native/BindGroup.cpp index b5dfd79057..f447142258 100644 --- a/src/dawn_native/BindGroup.cpp +++ b/src/dawn_native/BindGroup.cpp @@ -182,6 +182,10 @@ namespace dawn_native { "Dimension (%s) of %s doesn't match the expected dimension (%s).", entry.textureView->GetDimension(), entry.textureView, bindingInfo.storageTexture.viewDimension); + + DAWN_INVALID_IF(entry.textureView->GetLevelCount() != 1, + "mipLevelCount (%u) of %s expected to be 1.", + entry.textureView->GetLevelCount(), entry.textureView); break; } default: diff --git a/src/tests/unittests/validation/BindGroupValidationTests.cpp b/src/tests/unittests/validation/BindGroupValidationTests.cpp index c2af0a8f39..7c00ff8196 100644 --- a/src/tests/unittests/validation/BindGroupValidationTests.cpp +++ b/src/tests/unittests/validation/BindGroupValidationTests.cpp @@ -218,7 +218,7 @@ TEST_F(BindGroupValidationTest, TextureBindingType) { // Setting the sampler as well is an error binding.sampler = mSampler; ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor)); - binding.textureView = nullptr; + binding.sampler = nullptr; // Setting the buffer as well is an error binding.buffer = mUBO; @@ -552,6 +552,71 @@ TEST_F(BindGroupValidationTest, TextureDimension) { ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, arrayTextureView}})); } +// Check that a storage texture binding must have a texture view with a mipLevelCount of 1 +TEST_F(BindGroupValidationTest, StorageTextureViewLayerCount) { + wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout( + device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, + wgpu::TextureFormat::RGBA8Uint}}); + + wgpu::TextureDescriptor descriptor; + descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.size = {16, 16, 1}; + descriptor.sampleCount = 1; + descriptor.mipLevelCount = 1; + descriptor.usage = wgpu::TextureUsage::StorageBinding; + descriptor.format = wgpu::TextureFormat::RGBA8Uint; + + wgpu::Texture textureNoMip = device.CreateTexture(&descriptor); + + descriptor.mipLevelCount = 3; + wgpu::Texture textureMip = device.CreateTexture(&descriptor); + + // Control case: setting a storage texture view on a texture with only one mip level works + { + wgpu::TextureView view = textureNoMip.CreateView(); + utils::MakeBindGroup(device, layout, {{0, view}}); + } + + // Setting a storage texture view with mipLevelCount=1 on a texture of multiple mip levels is + // valid + { + wgpu::TextureViewDescriptor viewDesc = {}; + viewDesc.aspect = wgpu::TextureAspect::All; + viewDesc.dimension = wgpu::TextureViewDimension::e2D; + viewDesc.format = wgpu::TextureFormat::RGBA8Uint; + viewDesc.baseMipLevel = 0; + viewDesc.mipLevelCount = 1; + + // Setting texture view with lod 0 is valid + wgpu::TextureView view = textureMip.CreateView(&viewDesc); + utils::MakeBindGroup(device, layout, {{0, view}}); + + // Setting texture view with other lod is also valid + viewDesc.baseMipLevel = 2; + view = textureMip.CreateView(&viewDesc); + utils::MakeBindGroup(device, layout, {{0, view}}); + } + + // Texture view with mipLevelCount > 1 is invalid + { + wgpu::TextureViewDescriptor viewDesc = {}; + viewDesc.aspect = wgpu::TextureAspect::All; + viewDesc.dimension = wgpu::TextureViewDimension::e2D; + viewDesc.format = wgpu::TextureFormat::RGBA8Uint; + viewDesc.baseMipLevel = 0; + viewDesc.mipLevelCount = 2; + + // Setting texture view with lod 0 and 1 is invalid + wgpu::TextureView view = textureMip.CreateView(&viewDesc); + ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, view}})); + + // Setting texture view with lod 1 and 2 is invalid + viewDesc.baseMipLevel = 1; + view = textureMip.CreateView(&viewDesc); + ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, view}})); + } +} + // Check that a UBO must have the correct usage TEST_F(BindGroupValidationTest, BufferUsageUBO) { wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(