Vulkan: prevent degenerate buffer sizes from reaching the driver

Allocating buffers with sizes close to UINT64_MAX caused issues in all
Vulkan drivers. See https://gitlab.khronos.org/vulkan/vulkan/issues/1904
for more context. Do early validation to prevent such cases from
reaching the driver.

Bug: dawn:241
Fixed: dawn:241

Change-Id: I7edbb25999b4c11767047518b69edc1fa624cd3b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14641
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/vulkan/BufferVk.cpp b/src/dawn_native/vulkan/BufferVk.cpp
index 15571c7..8f8b3aa 100644
--- a/src/dawn_native/vulkan/BufferVk.cpp
+++ b/src/dawn_native/vulkan/BufferVk.cpp
@@ -123,6 +123,16 @@
     }
 
     MaybeError Buffer::Initialize() {
+        // Avoid passing ludicrously large sizes to drivers because it causes issues: drivers add
+        // some constants to the size passed and align it, but for values close to the maximum
+        // VkDeviceSize this can cause overflows and makes drivers crash or return bad sizes in the
+        // VkmemoryRequirements. See https://gitlab.khronos.org/vulkan/vulkan/issues/1904
+        // Any size with one of two top bits of VkDeviceSize set is a HUGE allocation and we can
+        // safely return an OOM error.
+        if (GetSize() & (uint64_t(3) << uint64_t(62))) {
+            return DAWN_OUT_OF_MEMORY_ERROR("Buffer size is HUGE and could cause overflows");
+        }
+
         VkBufferCreateInfo createInfo;
         createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
         createInfo.pNext = nullptr;
diff --git a/src/tests/end2end/BufferTests.cpp b/src/tests/end2end/BufferTests.cpp
index 09640fa..93fe804 100644
--- a/src/tests/end2end/BufferTests.cpp
+++ b/src/tests/end2end/BufferTests.cpp
@@ -733,11 +733,6 @@
     // TODO(http://crbug.com/dawn/27): Missing support.
     DAWN_SKIP_TEST_IF(IsMetal() || IsOpenGL());
 
-    // TODO(http://crbug.com/dawn/241): Fails on NVIDIA cards when Vulkan validation layers are
-    // enabled becuase the maximum size of a single allocation cannot be larger than or equal to
-    // 4G on some platforms.
-    DAWN_SKIP_TEST_IF(IsVulkan() && IsNvidia() && IsBackendValidationEnabled());
-
     wgpu::BufferDescriptor descriptor;
     descriptor.size = std::numeric_limits<uint64_t>::max();
     descriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;