Add basic supports of storage textures on Vulkan

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

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: I6831b96202a97182763ecd28bc41ab03df904a7c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20560
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/BindGroupAndStorageBarrierTracker.h b/src/dawn_native/BindGroupAndStorageBarrierTracker.h
index 94a2be8..8227d84 100644
--- a/src/dawn_native/BindGroupAndStorageBarrierTracker.h
+++ b/src/dawn_native/BindGroupAndStorageBarrierTracker.h
@@ -17,6 +17,8 @@
 
 #include "dawn_native/BindGroup.h"
 #include "dawn_native/BindGroupTracker.h"
+#include "dawn_native/Buffer.h"
+#include "dawn_native/Texture.h"
 
 namespace dawn_native {
 
@@ -34,8 +36,8 @@
                             uint32_t dynamicOffsetCount,
                             uint32_t* dynamicOffsets) {
             if (this->mBindGroups[index] != bindGroup) {
-                mBuffers[index] = {};
-                mBuffersNeedingBarrier[index] = {};
+                mBindings[index] = {};
+                mBindingsNeedingBarrier[index] = {};
 
                 const BindGroupLayoutBase* layout = bindGroup->GetLayout();
 
@@ -58,16 +60,23 @@
                             break;
 
                         case wgpu::BindingType::StorageBuffer:
-                            mBuffersNeedingBarrier[index].set(bindingIndex);
-                            mBuffers[index][bindingIndex] =
-                                bindGroup->GetBindingAsBufferBinding(bindingIndex).buffer;
+                            mBindingsNeedingBarrier[index].set(bindingIndex);
+                            mBindings[index][bindingIndex] = static_cast<ObjectBase*>(
+                                bindGroup->GetBindingAsBufferBinding(bindingIndex).buffer);
+                            break;
+
+                        // Read-only and write-only storage textures must use general layout
+                        // because load and store operations on storage images can only be done on
+                        // the images in VK_IMAGE_LAYOUT_GENERAL layout.
+                        case wgpu::BindingType::ReadonlyStorageTexture:
+                        case wgpu::BindingType::WriteonlyStorageTexture:
+                            mBindingsNeedingBarrier[index].set(bindingIndex);
+                            mBindings[index][bindingIndex] = static_cast<ObjectBase*>(
+                                bindGroup->GetBindingAsTextureView(bindingIndex));
                             break;
 
                         case wgpu::BindingType::StorageTexture:
-                        case wgpu::BindingType::ReadonlyStorageTexture:
-                        case wgpu::BindingType::WriteonlyStorageTexture:
                             // Not implemented.
-
                         default:
                             UNREACHABLE();
                             break;
@@ -79,10 +88,10 @@
         }
 
       protected:
-        std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBuffersNeedingBarrier = {};
+        std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBindingsNeedingBarrier = {};
         std::array<std::array<wgpu::BindingType, kMaxBindingsPerGroup>, kMaxBindGroups>
             mBindingTypes = {};
-        std::array<std::array<BufferBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBuffers = {};
+        std::array<std::array<ObjectBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBindings = {};
     };
 
 }  // namespace dawn_native
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index cea9516..9a5b663 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -148,11 +148,11 @@
 
             if (mInCompute) {
                 for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) {
-                    for (uint32_t binding : IterateBitSet(mBuffersNeedingBarrier[index])) {
+                    for (uint32_t binding : IterateBitSet(mBindingsNeedingBarrier[index])) {
                         wgpu::BindingType bindingType = mBindingTypes[index][binding];
                         switch (bindingType) {
                             case wgpu::BindingType::StorageBuffer:
-                                ToBackend(mBuffers[index][binding])
+                                static_cast<Buffer*>(mBindings[index][binding])
                                     ->TrackUsageAndTransitionNow(commandContext,
                                                                  wgpu::BufferUsage::Storage);
                                 break;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 5ab1b8f..53f2602 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -140,17 +140,24 @@
                                     mDynamicOffsetCounts, mDynamicOffsets);
 
                 for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) {
-                    for (uint32_t bindingIndex : IterateBitSet(mBuffersNeedingBarrier[index])) {
+                    for (uint32_t bindingIndex : IterateBitSet(mBindingsNeedingBarrier[index])) {
                         switch (mBindingTypes[index][bindingIndex]) {
                             case wgpu::BindingType::StorageBuffer:
-                                ToBackend(mBuffers[index][bindingIndex])
+                                static_cast<Buffer*>(mBindings[index][bindingIndex])
                                     ->TransitionUsageNow(recordingContext,
                                                          wgpu::BufferUsage::Storage);
                                 break;
 
-                            case wgpu::BindingType::StorageTexture:
                             case wgpu::BindingType::ReadonlyStorageTexture:
                             case wgpu::BindingType::WriteonlyStorageTexture:
+                                ToBackend(
+                                    static_cast<TextureViewBase*>(mBindings[index][bindingIndex])
+                                        ->GetTexture())
+                                    ->TransitionUsageNow(recordingContext,
+                                                         wgpu::TextureUsage::Storage);
+                                break;
+
+                            case wgpu::BindingType::StorageTexture:
                                 // Not implemented.
 
                             case wgpu::BindingType::UniformBuffer:
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 35ade8b..681e0cf 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -120,9 +120,11 @@
                 // combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we
                 // make CopySrc use GENERAL.
                 case wgpu::TextureUsage::CopySrc:
-                // Writable storage textures must use general. If we could know the texture is read
-                // only we could use SHADER_READ_ONLY_OPTIMAL
+                // Read-only and write-only storage textures must use general layout because load
+                // and store operations on storage images can only be done on the images in
+                // VK_IMAGE_LAYOUT_GENERAL layout.
                 case wgpu::TextureUsage::Storage:
+                case kReadonlyStorageTexture:
                     return VK_IMAGE_LAYOUT_GENERAL;
                 case wgpu::TextureUsage::OutputAttachment:
                     if (format.HasDepthOrStencil()) {
@@ -149,11 +151,15 @@
             if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) {
                 flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
             }
-            if (usage & (wgpu::TextureUsage::Sampled | wgpu::TextureUsage::Storage)) {
+            if (usage & (wgpu::TextureUsage::Sampled | kReadonlyStorageTexture)) {
                 flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
                          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
                          VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
             }
+            if (usage & wgpu::TextureUsage::Storage) {
+                flags |=
+                    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+            }
             if (usage & wgpu::TextureUsage::OutputAttachment) {
                 if (format.HasDepthOrStencil()) {
                     flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp
index da9d983..9e6764c 100644
--- a/src/tests/end2end/StorageTextureTests.cpp
+++ b/src/tests/end2end/StorageTextureTests.cpp
@@ -176,6 +176,7 @@
         #version 450
         void main() {
             gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
+            gl_PointSize = 1.0f;
         })";
 
     const char* kCommonReadOnlyTestCode_uimage2D = R"(
@@ -236,8 +237,8 @@
 
 // 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, Vulkan and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
 
     // Prepare the read-only storage texture and fill it with the expected data.
     // TODO(jiawei.shao@intel.com): test more texture formats.
@@ -291,8 +292,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, Vulkan and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+    DAWN_SKIP_TEST_IF(IsD3D12() || 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.
@@ -321,6 +322,7 @@
                 } else {
                     o_color = vec4(1.f, 0.f, 0.f, 1.f);
                 }
+                gl_PointSize = 1.0f;
             })";
     const char* kFragmentShader = R"(
             #version 450
@@ -334,8 +336,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, Vulkan and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+    DAWN_SKIP_TEST_IF(IsD3D12() || 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.
@@ -370,8 +372,8 @@
 
 // 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, Vulkan and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
 
     // Prepare the write-only storage texture.
     // TODO(jiawei.shao@intel.com): test more texture formats.
@@ -400,8 +402,8 @@
 
 // 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, Vulkan and OpenGL.
-    DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+    // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+    DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
 
     // Prepare the write-only storage texture.
     // TODO(jiawei.shao@intel.com): test more texture formats.