Vulkan: Support creating render pipeline asynchronously

This patch implements the asynchronous path of creating render
pipeline on Vulkan backend. This patch also makes the access to
the member mCache of Vulkan::RenderPassCache thread-safe as it
can be accessed in different threads simultaneously.

BUG=dawn:529
TEST=dawn_end2end_tests

Change-Id: I74c799935ef46405275585cb5dccfcb552a48aa4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64840
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
index 75de2b3..c9c63f5 100644
--- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
@@ -16,7 +16,6 @@
 
 #include "common/Assert.h"
 #include "common/Log.h"
-#include "dawn_native/AsyncTask.h"
 #include "dawn_native/CreatePipelineAsyncTask.h"
 #include "dawn_native/d3d12/D3D12Error.h"
 #include "dawn_native/d3d12/DeviceD3D12.h"
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 45b98c8..0663d78 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -168,6 +168,12 @@
                                                 void* userdata) {
         ComputePipeline::CreateAsync(this, descriptor, blueprintHash, callback, userdata);
     }
+    void Device::CreateRenderPipelineAsyncImpl(const RenderPipelineDescriptor* descriptor,
+                                               size_t blueprintHash,
+                                               WGPUCreateRenderPipelineAsyncCallback callback,
+                                               void* userdata) {
+        RenderPipeline::CreateAsync(this, descriptor, blueprintHash, callback, userdata);
+    }
 
     MaybeError Device::TickImpl() {
         RecycleCompletedCommands();
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index e053ebf..44d9366 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -141,6 +141,10 @@
                                             size_t blueprintHash,
                                             WGPUCreateComputePipelineAsyncCallback callback,
                                             void* userdata) override;
+        void CreateRenderPipelineAsyncImpl(const RenderPipelineDescriptor* descriptor,
+                                           size_t blueprintHash,
+                                           WGPUCreateRenderPipelineAsyncCallback callback,
+                                           void* userdata) override;
 
         ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice);
         void GatherQueueFromDevice();
diff --git a/src/dawn_native/vulkan/RenderPassCache.cpp b/src/dawn_native/vulkan/RenderPassCache.cpp
index ed2bc42..c9ce6e9 100644
--- a/src/dawn_native/vulkan/RenderPassCache.cpp
+++ b/src/dawn_native/vulkan/RenderPassCache.cpp
@@ -65,13 +65,16 @@
     }
 
     RenderPassCache::~RenderPassCache() {
+        std::lock_guard<std::mutex> lock(mMutex);
         for (auto it : mCache) {
             mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
         }
+
         mCache.clear();
     }
 
     ResultOrError<VkRenderPass> RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
+        std::lock_guard<std::mutex> lock(mMutex);
         auto it = mCache.find(query);
         if (it != mCache.end()) {
             return VkRenderPass(it->second);
diff --git a/src/dawn_native/vulkan/RenderPassCache.h b/src/dawn_native/vulkan/RenderPassCache.h
index 4ee9441..6cfb1df 100644
--- a/src/dawn_native/vulkan/RenderPassCache.h
+++ b/src/dawn_native/vulkan/RenderPassCache.h
@@ -25,6 +25,7 @@
 
 #include <array>
 #include <bitset>
+#include <mutex>
 #include <unordered_map>
 
 namespace dawn_native { namespace vulkan {
@@ -63,6 +64,7 @@
     // render pass. We always arrange the order of attachments in "color-depthstencil-resolve" order
     // when creating render pass and framebuffer so that we can always make sure the order of
     // attachments in the rendering pipeline matches the one of the framebuffer.
+    // All the operations on RenderPassCache are guaranteed to be thread-safe.
     // TODO(cwallez@chromium.org): Make it an LRU cache somehow?
     class RenderPassCache {
       public:
@@ -86,6 +88,8 @@
             std::unordered_map<RenderPassCacheQuery, VkRenderPass, CacheFuncs, CacheFuncs>;
 
         Device* mDevice = nullptr;
+
+        std::mutex mMutex;
         Cache mCache;
     };
 
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.cpp b/src/dawn_native/vulkan/RenderPipelineVk.cpp
index 7276cc4..9fa582d 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn_native/vulkan/RenderPipelineVk.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn_native/vulkan/RenderPipelineVk.h"
 
+#include "dawn_native/CreatePipelineAsyncTask.h"
 #include "dawn_native/vulkan/DeviceVk.h"
 #include "dawn_native/vulkan/FencedDeleter.h"
 #include "dawn_native/vulkan/PipelineLayoutVk.h"
@@ -600,4 +601,16 @@
         return mHandle;
     }
 
+    void RenderPipeline::CreateAsync(Device* device,
+                                     const RenderPipelineDescriptor* descriptor,
+                                     size_t blueprintHash,
+                                     WGPUCreateRenderPipelineAsyncCallback callback,
+                                     void* userdata) {
+        Ref<RenderPipeline> pipeline = AcquireRef(new RenderPipeline(device, descriptor));
+        std::unique_ptr<CreateRenderPipelineAsyncTask> asyncTask =
+            std::make_unique<CreateRenderPipelineAsyncTask>(pipeline, blueprintHash, callback,
+                                                            userdata);
+        CreateRenderPipelineAsyncTask::RunAsync(std::move(asyncTask));
+    }
+
 }}  // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.h b/src/dawn_native/vulkan/RenderPipelineVk.h
index 6a9207f..15f7a9b 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.h
+++ b/src/dawn_native/vulkan/RenderPipelineVk.h
@@ -29,6 +29,11 @@
         static ResultOrError<Ref<RenderPipeline>> Create(
             Device* device,
             const RenderPipelineDescriptor* descriptor);
+        static void CreateAsync(Device* device,
+                                const RenderPipelineDescriptor* descriptor,
+                                size_t blueprintHash,
+                                WGPUCreateRenderPipelineAsyncCallback callback,
+                                void* userdata);
 
         VkPipeline GetHandle() const;