D3D12: Fix 3D UAV desc WSize being 0 in some cases.

This could happen when selecting small mip levels where depth >> mip
ends up being zero. Instead the computation should be
max(1, depth >> mip). Also adds a regression test.

Bug: dawn:2072
Change-Id: I1312d684cba77cf7314acda3e80b0be07cccaa97
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/151860
Reviewed-by: Peng Huang <penghuang@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index df920d3..b0c5032 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -1339,7 +1339,7 @@
         case wgpu::TextureViewDimension::e3D:
             uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
             uavDesc.Texture3D.FirstWSlice = 0;
-            uavDesc.Texture3D.WSize = GetTexture()->GetDepth() >> GetBaseMipLevel();
+            uavDesc.Texture3D.WSize = std::max(1u, GetTexture()->GetDepth() >> GetBaseMipLevel());
             uavDesc.Texture3D.MipSlice = GetBaseMipLevel();
             break;
         // Cube and Cubemap can't be used as storage texture. So there is no need to create UAV
diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp
index bbc83ee..5c19073 100644
--- a/src/dawn/native/d3d12/TextureD3D12.cpp
+++ b/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -1116,7 +1116,7 @@
         case wgpu::TextureViewDimension::e3D:
             uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
             uavDesc.Texture3D.FirstWSlice = 0;
-            uavDesc.Texture3D.WSize = GetTexture()->GetDepth() >> GetBaseMipLevel();
+            uavDesc.Texture3D.WSize = std::max(1u, GetTexture()->GetDepth() >> GetBaseMipLevel());
             uavDesc.Texture3D.MipSlice = GetBaseMipLevel();
             break;
         // Cube and Cubemap can't be used as storage texture. So there is no need to create UAV
diff --git a/src/dawn/tests/end2end/Texture3DTests.cpp b/src/dawn/tests/end2end/Texture3DTests.cpp
index df6fd0e..1483f7b 100644
--- a/src/dawn/tests/end2end/Texture3DTests.cpp
+++ b/src/dawn/tests/end2end/Texture3DTests.cpp
@@ -120,6 +120,45 @@
     }
 }
 
+// Regression test for crbug.com/dawn/2072 where the WSize of D3D UAV descriptor ends up being 0.
+// (which is invalid as noted by the debug layers)
+TEST_P(Texture3DTests, LatestMipClampsDepthSizeForStorageTextures) {
+    wgpu::TextureDescriptor tDesc;
+    tDesc.dimension = wgpu::TextureDimension::e3D;
+    tDesc.size = {2, 2, 1};
+    tDesc.mipLevelCount = 2;
+    tDesc.usage = wgpu::TextureUsage::StorageBinding;
+    tDesc.format = wgpu::TextureFormat::R32Uint;
+    wgpu::Texture t = device.CreateTexture(&tDesc);
+
+    wgpu::TextureViewDescriptor vDesc;
+    vDesc.baseMipLevel = 1;
+    vDesc.mipLevelCount = 1;
+    wgpu::TextureView v = t.CreateView(&vDesc);
+
+    wgpu::ComputePipelineDescriptor pDesc;
+    pDesc.compute.module = utils::CreateShaderModule(device, R"(
+        @group(0) @binding(0) var t : texture_storage_3d<r32uint, write>;
+        @compute @workgroup_size(1) fn main() {
+            _ = t;
+        }
+    )");
+    pDesc.compute.entryPoint = "main";
+    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pDesc);
+
+    wgpu::BindGroup bg = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, v}});
+
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+    pass.SetBindGroup(0, bg);
+    pass.SetPipeline(pipeline);
+    pass.DispatchWorkgroups(1);
+    pass.End();
+
+    wgpu::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+}
+
 DAWN_INSTANTIATE_TEST(Texture3DTests,
                       D3D11Backend(),
                       D3D12Backend(),