Vulkan: Implement PreferNotUsingMappableOrUniformBufferAsStorage()

`device->PreferNotUsingMappableOrUniformBufferAsStorage()` should be
overloaded on Vulkan as not all Vulkan drivers support creating
mappable storage buffers.

Bug: 348654098, 386255678
Change-Id: I906ea850f1fcf6e3893acc3524fc2858ea3d8657
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/228955
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp
index 935b488..f4a415a 100644
--- a/src/dawn/native/vulkan/DeviceVk.cpp
+++ b/src/dawn/native/vulkan/DeviceVk.cpp
@@ -111,6 +111,8 @@
     VulkanFunctions* functions = GetMutableFunctions();
     *functions = ToBackend(GetPhysicalDevice())->GetVulkanInstance()->GetFunctions();
 
+    mSupportsMappableStorageBuffer = SupportsBufferMapExtendedUsages(mDeviceInfo);
+
     // Two things are crucial if device initialization fails: the function pointers to destroy
     // objects, and the fence deleter that calls these functions. Do not do anything before
     // these two are set up, so that a failed initialization doesn't cause a crash in
@@ -1036,4 +1038,9 @@
     }
 }
 
+bool Device::PreferNotUsingMappableOrUniformBufferAsStorage() const {
+    // Return true when the backend doesn't support mappable storage buffer
+    return !mSupportsMappableStorageBuffer;
+}
+
 }  // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/DeviceVk.h b/src/dawn/native/vulkan/DeviceVk.h
index 5e5698f..00a5bdb 100644
--- a/src/dawn/native/vulkan/DeviceVk.h
+++ b/src/dawn/native/vulkan/DeviceVk.h
@@ -125,6 +125,8 @@
     // Used to associate this device with validation layer messages.
     const char* GetDebugPrefix() { return mDebugPrefix.c_str(); }
 
+    bool PreferNotUsingMappableOrUniformBufferAsStorage() const override;
+
   private:
     Device(AdapterBase* adapter,
            const UnpackedPtr<DeviceDescriptor>& descriptor,
@@ -203,6 +205,8 @@
 
     Ref<PipelineCache> mMonolithicPipelineCache;
 
+    bool mSupportsMappableStorageBuffer = false;
+
     MaybeError ImportExternalImage(const ExternalImageDescriptorVk* descriptor,
                                    ExternalMemoryHandle memoryHandle,
                                    VkImage image,
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
index 0cf9204..d943e4a 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -71,6 +71,21 @@
 
 }  // anonymous namespace
 
+bool SupportsBufferMapExtendedUsages(const VulkanDeviceInfo& deviceInfo) {
+    // On Vulkan the memory type of the mappable buffers with extended usages must have all below
+    // memory property flags.
+    constexpr VkMemoryPropertyFlags kMapExtendedUsageMemoryPropertyFlags =
+        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+    for (const auto& memoryType : deviceInfo.memoryTypes) {
+        if ((memoryType.propertyFlags & kMapExtendedUsageMemoryPropertyFlags) ==
+            kMapExtendedUsageMemoryPropertyFlags) {
+            return true;
+        }
+    }
+    return false;
+}
+
 // SingleTypeAllocator is a combination of a BuddyMemoryAllocator and its client and can
 // service suballocation requests, but for a single Vulkan memory type.
 
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
index 8703dc1..22d4b53 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
@@ -42,6 +42,7 @@
 namespace dawn::native::vulkan {
 
 class Device;
+struct VulkanDeviceInfo;
 
 // Various kinds of memory that influence the result of the allocation. For example, to take
 // into account mappability and Vulkan's bufferImageGranularity.
@@ -53,6 +54,8 @@
     Opaque,
 };
 
+bool SupportsBufferMapExtendedUsages(const VulkanDeviceInfo& deviceInfo);
+
 class ResourceMemoryAllocator {
   public:
     explicit ResourceMemoryAllocator(Device* device);