[native][vulkan] Wrap BindGroupLayout cache with a mutex. - Because we dynamically create BGLs when initializing pipelines, and because pipelines may be created asynchronously, we need to make sure that access to the cache map doesn't mangle the data. Bug: 500609038 Change-Id: I6ffc093773c1c8308bbc95f62da1f202622908db Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/301935 Auto-Submit: Loko Kung <lokokung@google.com> Reviewed-by: Kyle Charbonneau <kylechar@google.com> Commit-Queue: Kyle Charbonneau <kylechar@google.com>
diff --git a/src/dawn/native/vulkan/BindGroupLayoutVk.cpp b/src/dawn/native/vulkan/BindGroupLayoutVk.cpp index cccb3f0..226e369 100644 --- a/src/dawn/native/vulkan/BindGroupLayoutVk.cpp +++ b/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
@@ -251,7 +251,7 @@ DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorSetLayout(device->GetVkDevice(), &createInfo, nullptr, &*mHandle), "CreateDescriptorSetLayout")); - mSpecializations.insert({{}, mHandle}); + mSpecializations->insert({{}, mHandle}); SetLabelImpl(); @@ -260,8 +260,15 @@ ResultOrError<VkDescriptorSetLayout> BindGroupLayout::GetOrCreateSpecializedHandle( const Specialization& specialization) { - if (auto it = mSpecializations.find(specialization); it != mSpecializations.end()) { - return it->second; + if (auto specialized = mSpecializations.ConstUse( + [&](auto specializations) -> std::optional<VkDescriptorSetLayout> { + if (auto it = specializations->find(specialization); it != specializations->end()) { + return it->second; + } + return std::nullopt; + }); + specialized) { + return *specialized; } Device* device = ToBackend(GetDevice()); @@ -282,8 +289,14 @@ nullptr, &*specialized), "CreateDescriptorSetLayout")); - mSpecializations.insert({specialization, specialized}); - return specialized; + return mSpecializations.Use([&](auto specializations) -> ResultOrError<VkDescriptorSetLayout> { + auto [it, inserted] = specializations->insert({specialization, specialized}); + if (!inserted) { + device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), specialized, nullptr); + return it->second; + } + return specialized; + }); } void BindGroupLayout::DestroyImpl(DestroyReason reason) { @@ -293,10 +306,12 @@ // DescriptorSetLayout aren't used by execution on the GPU and can be deleted at any time, // so we can destroy mHandle immediately instead of using the FencedDeleter. - for (auto& [_, handle] : mSpecializations) { - device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), handle, nullptr); - } - mSpecializations.clear(); + mSpecializations.Use([&](auto specializations) { + for (auto& [_, handle] : *specializations) { + device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), handle, nullptr); + } + specializations->clear(); + }); // Handled in the loop above already. mHandle = VK_NULL_HANDLE;
diff --git a/src/dawn/native/vulkan/BindGroupLayoutVk.h b/src/dawn/native/vulkan/BindGroupLayoutVk.h index d61a813..1e164e6 100644 --- a/src/dawn/native/vulkan/BindGroupLayoutVk.h +++ b/src/dawn/native/vulkan/BindGroupLayoutVk.h
@@ -117,7 +117,7 @@ // Caches VkDescriptorSetLayouts for specializations so that the lifetime guarantees are the // same as for mHandle. Note that the noop specialization has mHandle cached directly, but // mHandle is also kept separate for efficiency when creating BindGroups. - absl::flat_hash_map<Specialization, VkDescriptorSetLayout> mSpecializations; + MutexProtected<absl::flat_hash_map<Specialization, VkDescriptorSetLayout>> mSpecializations; // Maps from indices of texture entries that are paired with static samplers // to indices of the entries of their respective samplers.