Vulkan: Enable feature `BufferMapExtendedUsages` on specific memory types

This patch enables feature `BufferMapExtendedUsages` on the devices that
support below memory types, which means such devices support the memory
type that is CPU visible and can be efficiently accessed by GPU:
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT

Bug: 386255678
Test: dawn_end2end_tests
Change-Id: I03224cd7f4a0f6f28d5892dd26e04f06d34b7579
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/220518
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/dawn/native/vulkan/BufferVk.cpp b/src/dawn/native/vulkan/BufferVk.cpp
index fd27ea7..e5b2a03 100644
--- a/src/dawn/native/vulkan/BufferVk.cpp
+++ b/src/dawn/native/vulkan/BufferVk.cpp
@@ -174,6 +174,11 @@
         kReadOnlyStorageBuffer | kIndirectBufferForBackendResourceTracking;
     if (bufferUsage & kDeviceLocalBufferUsages) {
         requestKind |= MemoryKind::DeviceLocal;
+        // All mappable buffers with extended buffer usages should be allocated on the memory type
+        // with `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`.
+        if (bufferUsage & (wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite)) {
+            requestKind |= MemoryKind::HostCached;
+        }
     }
 
     return requestKind;
@@ -734,9 +739,6 @@
     size_t originalBufferCount = buffers.size();
     for (const Ref<Buffer>& buffer : buffers) {
         wgpu::BufferUsage mapUsage = buffer->GetInternalUsage() & kMappableBufferUsages;
-        DAWN_ASSERT(mapUsage == wgpu::BufferUsage::MapRead ||
-                    mapUsage == wgpu::BufferUsage::MapWrite);
-
         buffer->TrackUsageAndGetResourceBarrier(recordingContext, mapUsage,
                                                 wgpu::ShaderStage::None);
     }
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 798c15c..307d10e 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -40,6 +40,7 @@
 #include "dawn/native/Limits.h"
 #include "dawn/native/vulkan/BackendVk.h"
 #include "dawn/native/vulkan/DeviceVk.h"
+#include "dawn/native/vulkan/ResourceMemoryAllocatorVk.h"
 #include "dawn/native/vulkan/SwapChainVk.h"
 #include "dawn/native/vulkan/TextureVk.h"
 #include "dawn/native/vulkan/UtilsVulkan.h"
@@ -470,6 +471,10 @@
         EnableFeature(Feature::SharedTextureMemoryOpaqueFD);
     }
 
+    if (SupportsBufferMapExtendedUsages(mDeviceInfo)) {
+        EnableFeature(Feature::BufferMapExtendedUsages);
+    }
+
 #if DAWN_PLATFORM_IS(ANDROID)
     if (mDeviceInfo.HasExt(DeviceExt::ExternalMemoryAndroidHardwareBuffer)) {
         if (GetOrLoadAHBFunctions()->IsValid()) {
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
index ccf383b..c7d4617 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -57,6 +57,28 @@
     return memoryKind & (MemoryKind::ReadMappable | MemoryKind::WriteMappable);
 }
 
+VkMemoryPropertyFlags GetRequiredMemoryPropertyFlags(MemoryKind memoryKind, bool mappable) {
+    VkMemoryPropertyFlags vkFlags = 0;
+
+    // Mappable resource must be host visible and host coherent.
+    if (mappable) {
+        vkFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+        vkFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+    }
+
+    // DEVICE_LOCAL_BIT must be set when MemoryKind::DeviceLocal is required.
+    if (memoryKind & MemoryKind::DeviceLocal) {
+        vkFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+    }
+
+    // HOST_CACHED_BIT must be set when MemoryKind::HostCached is required.
+    if (memoryKind & MemoryKind::HostCached) {
+        vkFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+    }
+
+    return vkFlags;
+}
+
 }  // anonymous namespace
 
 bool SupportsBufferMapExtendedUsages(const VulkanDeviceInfo& deviceInfo) {
@@ -274,6 +296,7 @@
 int ResourceMemoryAllocator::FindBestTypeIndex(VkMemoryRequirements requirements, MemoryKind kind) {
     const VulkanDeviceInfo& info = mDevice->GetDeviceInfo();
     bool mappable = IsMemoryKindMappable(kind);
+    VkMemoryPropertyFlags vkRequiredFlags = GetRequiredMemoryPropertyFlags(kind, mappable);
 
     // Find a suitable memory type for this allocation
     int bestType = -1;
@@ -283,21 +306,8 @@
             continue;
         }
 
-        // Mappable resource must be host visible
-        if (mappable &&
-            (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
-            continue;
-        }
-
-        // Mappable must also be host coherent.
-        if (mappable &&
-            (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) {
-            continue;
-        }
-
-        // DEVICE_LOCAL_BIT must be set when MemoryKind::DeviceLocal is required.
-        if ((kind & MemoryKind::DeviceLocal) &&
-            (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
+        // Memory type must have all the required memory properties.
+        if ((info.memoryTypes[i].propertyFlags & vkRequiredFlags) != vkRequiredFlags) {
             continue;
         }
 
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
index 0d9ac68..d166fd1 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
@@ -52,6 +52,7 @@
     DeviceLocal = 4,
     ReadMappable = 8,
     WriteMappable = 16,
+    HostCached = 32,
 };
 
 bool SupportsBufferMapExtendedUsages(const VulkanDeviceInfo& deviceInfo);