Reland "Vulkan: Allow setting multiple `MemoryKind` bits"

This is a reland of commit a8f733807cbf72ebab8baecbda359ca4413d00c7

This patch no longer requires the support of DEVICE_LOCAL_BIT for
the buffer memory created from a host mapped pointer.

Original change's description:
> Vulkan: Allow setting multiple `MemoryKind` bits
>
> This patch allows setting multiple MemoryKind bits in one MemoryKind
> value and replaces MemoryKind::Opaque with MemoryKind::DeviceLocal as
> a preparation of the implementation of BufferMapExtendedUsage on
> Vulkan.
>
> Bug: 386255678
> Change-Id: I68f77de15d8267ae985d49f73497410fb08fbd49
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/227697
> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>

Bug: 386255678
Change-Id: I8acd518e05966b38db48879aacb9a7c029470016
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/229340
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/vulkan/BufferVk.cpp b/src/dawn/native/vulkan/BufferVk.cpp
index c789fd3..fd27ea7 100644
--- a/src/dawn/native/vulkan/BufferVk.cpp
+++ b/src/dawn/native/vulkan/BufferVk.cpp
@@ -157,6 +157,28 @@
     return flags;
 }
 
+MemoryKind GetMemoryKindFor(wgpu::BufferUsage bufferUsage) {
+    MemoryKind requestKind = MemoryKind::Linear;
+    if (bufferUsage & wgpu::BufferUsage::MapRead) {
+        requestKind |= MemoryKind::ReadMappable;
+    }
+    if (bufferUsage & wgpu::BufferUsage::MapWrite) {
+        requestKind |= MemoryKind::WriteMappable;
+    }
+
+    // `kDeviceLocalBufferUsages` covers all the buffer usages that prefer the memory type
+    // `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`.
+    constexpr wgpu::BufferUsage kDeviceLocalBufferUsages =
+        wgpu::BufferUsage::Index | wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::Storage |
+        wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Vertex | kInternalStorageBuffer |
+        kReadOnlyStorageBuffer | kIndirectBufferForBackendResourceTracking;
+    if (bufferUsage & kDeviceLocalBufferUsages) {
+        requestKind |= MemoryKind::DeviceLocal;
+    }
+
+    return requestKind;
+}
+
 }  // namespace
 
 // static
@@ -233,12 +255,7 @@
     VkMemoryRequirements requirements;
     device->fn.GetBufferMemoryRequirements(device->GetVkDevice(), mHandle, &requirements);
 
-    MemoryKind requestKind = MemoryKind::Linear;
-    if (GetInternalUsage() & wgpu::BufferUsage::MapRead) {
-        requestKind = MemoryKind::LinearReadMappable;
-    } else if (GetInternalUsage() & wgpu::BufferUsage::MapWrite) {
-        requestKind = MemoryKind::LinearWriteMappable;
-    }
+    MemoryKind requestKind = GetMemoryKindFor(GetInternalUsage());
     DAWN_TRY_ASSIGN(mMemoryAllocation,
                     device->GetResourceMemoryAllocator()->Allocate(requirements, requestKind));
 
@@ -330,15 +347,11 @@
         requirements.memoryTypeBits &= hostPointerProperties.memoryTypeBits;
     }
 
-    MemoryKind requestKind;
-    if (GetInternalUsage() & wgpu::BufferUsage::MapRead) {
-        requestKind = MemoryKind::LinearReadMappable;
-    } else if (GetInternalUsage() & wgpu::BufferUsage::MapWrite) {
-        requestKind = MemoryKind::LinearWriteMappable;
-    } else {
-        requestKind = MemoryKind::Linear;
-    }
-
+    // We can choose memory type with `requirements.memoryTypeBits` only because host-mapped memory
+    // - is CPU-visible
+    // - is device-local on UMA
+    // - cannot be non-device-local on non-UMA
+    MemoryKind requestKind = MemoryKind::Linear;
     int memoryTypeIndex =
         device->GetResourceMemoryAllocator()->FindBestTypeIndex(requirements, requestKind);
     DAWN_INVALID_IF(memoryTypeIndex < 0, "Failed to find suitable memory type.");
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
index d943e4a..ccf383b 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -54,19 +54,7 @@
 constexpr uint64_t kBuddyHeapsSize = 2 * kMaxSizeForSubAllocation;
 
 bool IsMemoryKindMappable(MemoryKind memoryKind) {
-    switch (memoryKind) {
-        case MemoryKind::LinearReadMappable:
-        case MemoryKind::LinearWriteMappable:
-            return true;
-
-        case MemoryKind::LazilyAllocated:
-        case MemoryKind::Linear:
-        case MemoryKind::Opaque:
-            return false;
-
-        default:
-            DAWN_UNREACHABLE();
-    }
+    return memoryKind & (MemoryKind::ReadMappable | MemoryKind::WriteMappable);
 }
 
 }  // anonymous namespace
@@ -307,6 +295,12 @@
             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) {
+            continue;
+        }
+
         // Found the first candidate memory type
         if (bestType == -1) {
             bestType = static_cast<int>(i);
@@ -347,7 +341,7 @@
             info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
         bool bestHostCached =
             info.memoryTypes[bestType].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
-        if (kind == MemoryKind::LinearReadMappable && currentHostCached != bestHostCached) {
+        if ((kind & MemoryKind::ReadMappable) && currentHostCached != bestHostCached) {
             if (currentHostCached) {
                 bestType = static_cast<int>(i);
             }
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
index 22d4b53..0d9ac68 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.h
@@ -44,14 +44,14 @@
 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.
-enum class MemoryKind {
-    LazilyAllocated,
-    Linear,
-    LinearReadMappable,
-    LinearWriteMappable,
-    Opaque,
+// Each bit of MemoryKind represents a kind of memory that influence the result of the allocation.
+// For example, to take into account mappability and Vulkan's bufferImageGranularity.
+enum class MemoryKind : uint8_t {
+    LazilyAllocated = 1,
+    Linear = 2,
+    DeviceLocal = 4,
+    ReadMappable = 8,
+    WriteMappable = 16,
 };
 
 bool SupportsBufferMapExtendedUsages(const VulkanDeviceInfo& deviceInfo);
@@ -83,4 +83,12 @@
 
 }  // namespace dawn::native::vulkan
 
+namespace wgpu {
+template <>
+struct IsWGPUBitmask<dawn::native::vulkan::MemoryKind> {
+    static constexpr bool enable = true;
+};
+
+}  // namespace wgpu
+
 #endif  // SRC_DAWN_NATIVE_VULKAN_RESOURCEMEMORYALLOCATORVK_H_
diff --git a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
index 4bf68bd..67e2887 100644
--- a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
+++ b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
@@ -439,7 +439,7 @@
     // import's constraint.
     memoryRequirements.memoryTypeBits &= fdProperties.memoryTypeBits;
     int memoryTypeIndex = device->GetResourceMemoryAllocator()->FindBestTypeIndex(
-        memoryRequirements, MemoryKind::Opaque);
+        memoryRequirements, MemoryKind::DeviceLocal);
     DAWN_INVALID_IF(memoryTypeIndex == -1, "Unable to find an appropriate memory type for import.");
 
     SystemHandle memoryFD;
@@ -669,7 +669,7 @@
         VkMemoryRequirements memoryRequirements;
         memoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits;
         int memoryTypeIndex = device->GetResourceMemoryAllocator()->FindBestTypeIndex(
-            memoryRequirements, MemoryKind::Opaque);
+            memoryRequirements, MemoryKind::DeviceLocal);
         DAWN_INVALID_IF(memoryTypeIndex == -1,
                         "Unable to find an appropriate memory type for import.");
 
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index 2cabce5..9861608 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -1382,7 +1382,7 @@
         (GetInternalUsage() & (wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment));
     auto memoryKind = (GetInternalUsage() & wgpu::TextureUsage::TransientAttachment)
                           ? MemoryKind::LazilyAllocated
-                          : MemoryKind::Opaque;
+                          : MemoryKind::DeviceLocal;
     DAWN_TRY_ASSIGN(mMemoryAllocation, device->GetResourceMemoryAllocator()->Allocate(
                                            requirements, memoryKind, forceDisableSubAllocation));
 
diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
index 9178027..d02ebe3 100644
--- a/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
+++ b/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
@@ -264,7 +264,7 @@
         // import's constraint.
         memoryRequirements.memoryTypeBits &= fdProperties.memoryTypeBits;
         int memoryTypeIndex = mDevice->GetResourceMemoryAllocator()->FindBestTypeIndex(
-            memoryRequirements, MemoryKind::Opaque);
+            memoryRequirements, MemoryKind::DeviceLocal);
         DAWN_INVALID_IF(memoryTypeIndex == -1,
                         "Unable to find an appropriate memory type for import.");
 
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests_opaquefd.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests_opaquefd.cpp
index 407057c..71d313a 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests_opaquefd.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests_opaquefd.cpp
@@ -84,7 +84,7 @@
     deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), vkImage, &requirements);
 
     int bestType = deviceVk->GetResourceMemoryAllocator()->FindBestTypeIndex(
-        requirements, native::vulkan::MemoryKind::Opaque);
+        requirements, native::vulkan::MemoryKind::DeviceLocal);
     EXPECT_GE(bestType, 0);
 
     VkMemoryDedicatedAllocateInfo dedicatedInfo;
diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
index cd16976..97042cc 100644
--- a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
+++ b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
@@ -230,7 +230,7 @@
         deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle, &requirements);
 
         int bestType = deviceVk->GetResourceMemoryAllocator()->FindBestTypeIndex(
-            requirements, MemoryKind::Opaque);
+            requirements, MemoryKind::DeviceLocal);
 
         VkMemoryAllocateInfo allocateInfo;
         allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;