Add basic supports of storage textures on D3D12

This patch adds the basic supports of read-only and write-only storage
textures on D3D12.

The subresource tracking and barriers on the subresources used as
read-only and write-only storage textures are not included in this
patch.

BUG=dawn:267
TEST=dawn_end2end_tests

Change-Id: Ie29a3a9962cd1a79217bc87815ed0bd27623e3a8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/21140
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/d3d12/BindGroupD3D12.cpp b/src/dawn_native/d3d12/BindGroupD3D12.cpp
index 4e32874..5aeaf56 100644
--- a/src/dawn_native/d3d12/BindGroupD3D12.cpp
+++ b/src/dawn_native/d3d12/BindGroupD3D12.cpp
@@ -115,7 +115,11 @@
                         viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex]));
                     break;
                 }
-                case wgpu::BindingType::SampledTexture: {
+
+                // Readonly storage is implemented as SRV so it can be used at the same time as a
+                // sampled texture.
+                case wgpu::BindingType::SampledTexture:
+                case wgpu::BindingType::ReadonlyStorageTexture: {
                     auto* view = ToBackend(GetBindingAsTextureView(bindingIndex));
                     auto& srv = view->GetSRVDescriptor();
                     d3d12Device->CreateShaderResourceView(
@@ -133,9 +137,16 @@
                     break;
                 }
 
+                case wgpu::BindingType::WriteonlyStorageTexture: {
+                    TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
+                    D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor();
+                    d3d12Device->CreateUnorderedAccessView(
+                        ToBackend(view->GetTexture())->GetD3D12Resource(), nullptr, &uav,
+                        viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex]));
+                    break;
+                }
+
                 case wgpu::BindingType::StorageTexture:
-                case wgpu::BindingType::ReadonlyStorageTexture:
-                case wgpu::BindingType::WriteonlyStorageTexture:
                     UNREACHABLE();
                     break;
 
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 6f96262..72377f7 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -166,9 +166,21 @@
                                                                  wgpu::BufferUsage::Storage);
                                 break;
 
-                            case wgpu::BindingType::StorageTexture:
                             case wgpu::BindingType::ReadonlyStorageTexture:
+                                ToBackend(static_cast<TextureView*>(mBindings[index][binding])
+                                              ->GetTexture())
+                                    ->TrackUsageAndTransitionNow(commandContext,
+                                                                 kReadonlyStorageTexture);
+                                break;
+
                             case wgpu::BindingType::WriteonlyStorageTexture:
+                                ToBackend(static_cast<TextureView*>(mBindings[index][binding])
+                                              ->GetTexture())
+                                    ->TrackUsageAndTransitionNow(commandContext,
+                                                                 wgpu::TextureUsage::Storage);
+                                break;
+
+                            case wgpu::BindingType::StorageTexture:
                                 // Not implemented.
 
                             case wgpu::BindingType::UniformBuffer:
diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
index e006d6f..d6410aa 100644
--- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
@@ -51,6 +51,7 @@
             // See https://github.com/gpuweb/gpuweb/issues/332
             options.SetHLSLPointCoordCompat(true);
             options.SetHLSLPointSizeCompat(true);
+            options.SetHLSLNonWritableUAVTextureAsSRV(true);
 
             DAWN_TRY(CheckSpvcSuccess(
                 mSpvcContext.InitializeForHlsl(spirv.data(), spirv.size(), options),
@@ -90,6 +91,7 @@
             // See https://github.com/gpuweb/gpuweb/issues/332
             options_hlsl.point_coord_compat = true;
             options_hlsl.point_size_compat = true;
+            options_hlsl.nonwritable_uav_texture_as_srv = true;
 
             compilerImpl = std::make_unique<spirv_cross::CompilerHLSL>(spirv);
             compiler = compilerImpl.get();
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 865bc2b..bcd4d26 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -48,7 +48,7 @@
             if (usage & wgpu::TextureUsage::CopyDst) {
                 resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
             }
-            if (usage & wgpu::TextureUsage::Sampled) {
+            if (usage & (wgpu::TextureUsage::Sampled | kReadonlyStorageTexture)) {
                 resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
                                   D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
             }
@@ -830,4 +830,17 @@
             ->GetDSVDescriptor(mipLevel, GetBaseArrayLayer(), GetLayerCount());
     }
 
+    D3D12_UNORDERED_ACCESS_VIEW_DESC TextureView::GetUAVDescriptor() const {
+        D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
+        uavDesc.Format = GetD3D12Format();
+
+        ASSERT(!GetTexture()->IsMultisampledTexture());
+        uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
+        uavDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer();
+        uavDesc.Texture2DArray.ArraySize = GetLayerCount();
+        uavDesc.Texture2DArray.MipSlice = GetBaseMipLevel();
+        uavDesc.Texture2DArray.PlaneSlice = 0;
+        return uavDesc;
+    }
+
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h
index 88a24f4..45443c1 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -116,6 +116,7 @@
         const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const;
         D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor() const;
         D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor() const;
+        D3D12_UNORDERED_ACCESS_VIEW_DESC GetUAVDescriptor() const;
 
       private:
         D3D12_SHADER_RESOURCE_VIEW_DESC mSrvDesc;
diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp
index 9e6764c..047351a 100644
--- a/src/tests/end2end/StorageTextureTests.cpp
+++ b/src/tests/end2end/StorageTextureTests.cpp
@@ -237,8 +237,14 @@
 
 // Test that read-only storage textures are supported in compute shader.
 TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) {
-    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on OpenGL.
+    DAWN_SKIP_TEST_IF(IsOpenGL());
+
+    // When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
+    // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
+    // TODO(jiawei.shao@intel.com): enable this test when we specify "--use-spvc-parser" after the
+    // bug in spvc parser is fixed.
+    DAWN_SKIP_TEST_IF(IsD3D12() && IsSpvcParserBeingUsed());
 
     // Prepare the read-only storage texture and fill it with the expected data.
     // TODO(jiawei.shao@intel.com): test more texture formats.
@@ -292,8 +298,8 @@
 
 // Test that read-only storage textures are supported in vertex shader.
 TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
-    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on OpenGL.
+    DAWN_SKIP_TEST_IF(IsOpenGL());
 
     // When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
     // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@@ -336,8 +342,8 @@
 
 // Test that read-only storage textures are supported in fragment shader.
 TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) {
-    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on OpenGL.
+    DAWN_SKIP_TEST_IF(IsOpenGL());
 
     // When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
     // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@@ -373,7 +379,13 @@
 // Test that write-only storage textures are supported in compute shader.
 TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
     // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
+    DAWN_SKIP_TEST_IF(IsOpenGL());
+
+    // When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
+    // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
+    // TODO(jiawei.shao@intel.com): enable this test when we specify "--use-spvc-parser" after the
+    // bug in spvc parser is fixed.
+    DAWN_SKIP_TEST_IF(IsD3D12() && IsSpvcParserBeingUsed());
 
     // Prepare the write-only storage texture.
     // TODO(jiawei.shao@intel.com): test more texture formats.
@@ -403,7 +415,13 @@
 // Test that write-only storage textures are supported in fragment shader.
 TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
     // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
+    DAWN_SKIP_TEST_IF(IsOpenGL());
+
+    // When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
+    // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
+    // TODO(jiawei.shao@intel.com): enable this test when we specify "--use-spvc-parser" after the
+    // bug in spvc parser is fixed.
+    DAWN_SKIP_TEST_IF(IsD3D12() && IsSpvcParserBeingUsed());
 
     // Prepare the write-only storage texture.
     // TODO(jiawei.shao@intel.com): test more texture formats.