From 0b51040b5ee85242921b87208ef5c452e47eb192 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Thu, 17 Jun 2021 14:46:50 +0200 Subject: [PATCH] radv: reject binding buffer/image when the device memory is too small From the Vulkan spec 1.2.181: "The difference of the size of memory and memoryOffset must be greater than or equal to the size member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with the same image" This is invalid usage but adding a check in the driver is safe and might avoid spurious failures. This is a workaround for the inventory GPU hang with Cyberpunk 2077 which is actually a game bug. Luckily the game handles this error gracefully. Since the addrlib change from March, addrlib now selects a better swizzle mode (4KB instead of 64KB) which reduces image size. Though, the game assumes that an image with 2 mips is always smaller than the same image but with 6 mips. This is not always true if the swizzle mode is different. Then, it creates a D312 heap that is too small for the 2 mips image and the GPU hang with a memory violation, ugh... Note that next vkd3d-proton release should also reject this but fixing both sides is fine. Cc: 21.1 mesa-stable Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/4823 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/4593 Signed-off-by: Samuel Pitoiset Reviewed-by: Bas Nieuwenhuizen Part-of: (cherry picked from commit 50233d0daa3ca444a1f1caf6e9eab1144d28530d) --- .pick_status.json | 2 +- src/amd/vulkan/radv_device.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 6cc3e19accb..30d7a818b11 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -130,7 +130,7 @@ "description": "radv: reject binding buffer/image when the device memory is too small", "nominated": true, "nomination_type": 0, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null }, diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c index 975536acc6e..52551ba4a5a 100644 --- a/src/amd/vulkan/radv_device.c +++ b/src/amd/vulkan/radv_device.c @@ -5427,14 +5427,27 @@ radv_GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, } VkResult -radv_BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, +radv_BindBufferMemory2(VkDevice _device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos) { + RADV_FROM_HANDLE(radv_device, device, _device); + for (uint32_t i = 0; i < bindInfoCount; ++i) { RADV_FROM_HANDLE(radv_device_memory, mem, pBindInfos[i].memory); RADV_FROM_HANDLE(radv_buffer, buffer, pBindInfos[i].buffer); if (mem) { + if (mem->alloc_size) { + VkMemoryRequirements req; + + radv_GetBufferMemoryRequirements(_device, pBindInfos[i].buffer, &req); + + if (pBindInfos[i].memoryOffset + req.size > mem->alloc_size) { + return vk_errorf(device->instance, VK_ERROR_UNKNOWN, + "Device memory object too small for the buffer.\n"); + } + } + buffer->bo = mem->bo; buffer->offset = pBindInfos[i].memoryOffset; } else { @@ -5457,14 +5470,27 @@ radv_BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, } VkResult -radv_BindImageMemory2(VkDevice device, uint32_t bindInfoCount, +radv_BindImageMemory2(VkDevice _device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos) { + RADV_FROM_HANDLE(radv_device, device, _device); + for (uint32_t i = 0; i < bindInfoCount; ++i) { RADV_FROM_HANDLE(radv_device_memory, mem, pBindInfos[i].memory); RADV_FROM_HANDLE(radv_image, image, pBindInfos[i].image); if (mem) { + if (mem->alloc_size) { + VkMemoryRequirements req; + + radv_GetImageMemoryRequirements(_device, pBindInfos[i].image, &req); + + if (pBindInfos[i].memoryOffset + req.size > mem->alloc_size) { + return vk_errorf(device->instance, VK_ERROR_UNKNOWN, + "Device memory object too small for the image.\n"); + } + } + image->bo = mem->bo; image->offset = pBindInfos[i].memoryOffset; } else {