Vulkan: attempt sub-allocation before direct allocation.

Falling-back to direct allocation ensures allocation failure returns OOM.
If no OOM, the resource could be left then used while in an invalid state.

BUG=chromium:1045811,chromium:1047220,chromium:1047048

Change-Id: I927962b1dc6a7422a7d6eac114d82f28a42794a2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15600
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
index 3d8ded5..3c2ae56 100644
--- a/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -112,31 +112,35 @@
 
         VkDeviceSize size = requirements.size;
 
-        // If the resource is too big, allocate memory just for it.
-        // Also allocate mappable resources separately because at the moment the mapped pointer
+        // Sub-allocate non-mappable resources because at the moment the mapped pointer
         // is part of the resource and not the heap, which doesn't match the Vulkan model.
         // TODO(cwallez@chromium.org): allow sub-allocating mappable resources, maybe.
-        if (requirements.size >= kMaxSizeForSubAllocation || mappable) {
-            std::unique_ptr<ResourceHeapBase> resourceHeap;
-            DAWN_TRY_ASSIGN(resourceHeap,
-                            mAllocatorsPerType[memoryType]->AllocateResourceHeap(size));
-
-            void* mappedPointer = nullptr;
-            if (mappable) {
-                DAWN_TRY(
-                    CheckVkSuccess(mDevice->fn.MapMemory(mDevice->GetVkDevice(),
-                                                         ToBackend(resourceHeap.get())->GetMemory(),
-                                                         0, size, 0, &mappedPointer),
-                                   "vkMapMemory"));
+        if (requirements.size < kMaxSizeForSubAllocation && !mappable) {
+            ResourceMemoryAllocation subAllocation;
+            DAWN_TRY_ASSIGN(subAllocation,
+                            mAllocatorsPerType[memoryType]->AllocateMemory(requirements));
+            if (subAllocation.GetInfo().mMethod != AllocationMethod::kInvalid) {
+                return subAllocation;
             }
-
-            AllocationInfo info;
-            info.mMethod = AllocationMethod::kDirect;
-            return ResourceMemoryAllocation(info, /*offset*/ 0, resourceHeap.release(),
-                                            static_cast<uint8_t*>(mappedPointer));
-        } else {
-            return mAllocatorsPerType[memoryType]->AllocateMemory(requirements);
         }
+
+        // If sub-allocation failed, allocate memory just for it.
+        std::unique_ptr<ResourceHeapBase> resourceHeap;
+        DAWN_TRY_ASSIGN(resourceHeap, mAllocatorsPerType[memoryType]->AllocateResourceHeap(size));
+
+        void* mappedPointer = nullptr;
+        if (mappable) {
+            DAWN_TRY(
+                CheckVkSuccess(mDevice->fn.MapMemory(mDevice->GetVkDevice(),
+                                                     ToBackend(resourceHeap.get())->GetMemory(), 0,
+                                                     size, 0, &mappedPointer),
+                               "vkMapMemory"));
+        }
+
+        AllocationInfo info;
+        info.mMethod = AllocationMethod::kDirect;
+        return ResourceMemoryAllocation(info, /*offset*/ 0, resourceHeap.release(),
+                                        static_cast<uint8_t*>(mappedPointer));
     }
 
     void ResourceMemoryAllocator::Deallocate(ResourceMemoryAllocation* allocation) {