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>
This commit is contained in:
Jiawei Shao 2021-09-24 00:40:57 +00:00 committed by Dawn LUCI CQ
parent ba66295033
commit 525039ddc6
7 changed files with 35 additions and 1 deletions

View File

@ -16,7 +16,6 @@
#include "common/Assert.h" #include "common/Assert.h"
#include "common/Log.h" #include "common/Log.h"
#include "dawn_native/AsyncTask.h"
#include "dawn_native/CreatePipelineAsyncTask.h" #include "dawn_native/CreatePipelineAsyncTask.h"
#include "dawn_native/d3d12/D3D12Error.h" #include "dawn_native/d3d12/D3D12Error.h"
#include "dawn_native/d3d12/DeviceD3D12.h" #include "dawn_native/d3d12/DeviceD3D12.h"

View File

@ -168,6 +168,12 @@ namespace dawn_native { namespace vulkan {
void* userdata) { void* userdata) {
ComputePipeline::CreateAsync(this, descriptor, blueprintHash, callback, 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() { MaybeError Device::TickImpl() {
RecycleCompletedCommands(); RecycleCompletedCommands();

View File

@ -141,6 +141,10 @@ namespace dawn_native { namespace vulkan {
size_t blueprintHash, size_t blueprintHash,
WGPUCreateComputePipelineAsyncCallback callback, WGPUCreateComputePipelineAsyncCallback callback,
void* userdata) override; void* userdata) override;
void CreateRenderPipelineAsyncImpl(const RenderPipelineDescriptor* descriptor,
size_t blueprintHash,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) override;
ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice); ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice);
void GatherQueueFromDevice(); void GatherQueueFromDevice();

View File

@ -65,13 +65,16 @@ namespace dawn_native { namespace vulkan {
} }
RenderPassCache::~RenderPassCache() { RenderPassCache::~RenderPassCache() {
std::lock_guard<std::mutex> lock(mMutex);
for (auto it : mCache) { for (auto it : mCache) {
mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr); mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
} }
mCache.clear(); mCache.clear();
} }
ResultOrError<VkRenderPass> RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) { ResultOrError<VkRenderPass> RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
std::lock_guard<std::mutex> lock(mMutex);
auto it = mCache.find(query); auto it = mCache.find(query);
if (it != mCache.end()) { if (it != mCache.end()) {
return VkRenderPass(it->second); return VkRenderPass(it->second);

View File

@ -25,6 +25,7 @@
#include <array> #include <array>
#include <bitset> #include <bitset>
#include <mutex>
#include <unordered_map> #include <unordered_map>
namespace dawn_native { namespace vulkan { namespace dawn_native { namespace vulkan {
@ -63,6 +64,7 @@ namespace dawn_native { namespace vulkan {
// render pass. We always arrange the order of attachments in "color-depthstencil-resolve" order // 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 // 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. // 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? // TODO(cwallez@chromium.org): Make it an LRU cache somehow?
class RenderPassCache { class RenderPassCache {
public: public:
@ -86,6 +88,8 @@ namespace dawn_native { namespace vulkan {
std::unordered_map<RenderPassCacheQuery, VkRenderPass, CacheFuncs, CacheFuncs>; std::unordered_map<RenderPassCacheQuery, VkRenderPass, CacheFuncs, CacheFuncs>;
Device* mDevice = nullptr; Device* mDevice = nullptr;
std::mutex mMutex;
Cache mCache; Cache mCache;
}; };

View File

@ -14,6 +14,7 @@
#include "dawn_native/vulkan/RenderPipelineVk.h" #include "dawn_native/vulkan/RenderPipelineVk.h"
#include "dawn_native/CreatePipelineAsyncTask.h"
#include "dawn_native/vulkan/DeviceVk.h" #include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/FencedDeleter.h" #include "dawn_native/vulkan/FencedDeleter.h"
#include "dawn_native/vulkan/PipelineLayoutVk.h" #include "dawn_native/vulkan/PipelineLayoutVk.h"
@ -600,4 +601,16 @@ namespace dawn_native { namespace vulkan {
return mHandle; 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 }} // namespace dawn_native::vulkan

View File

@ -29,6 +29,11 @@ namespace dawn_native { namespace vulkan {
static ResultOrError<Ref<RenderPipeline>> Create( static ResultOrError<Ref<RenderPipeline>> Create(
Device* device, Device* device,
const RenderPipelineDescriptor* descriptor); const RenderPipelineDescriptor* descriptor);
static void CreateAsync(Device* device,
const RenderPipelineDescriptor* descriptor,
size_t blueprintHash,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata);
VkPipeline GetHandle() const; VkPipeline GetHandle() const;