Fix #137909: Vulkan: Recover from allocation errors

When buffers/images are allocated that use larger limits than supported
by the GPU blender would crash. This PR adds some safety mechanism to
allow Blender to recover from allocation errors.

This has been tested on NVIDIA drivers.

Pull Request: https://projects.blender.org/blender/blender/pulls/139876
This commit is contained in:
Jeroen Bakker
2025-06-05 14:11:37 +02:00
parent aca960500e
commit 3a16f3b45f
5 changed files with 41 additions and 18 deletions

View File

@@ -63,7 +63,11 @@ class VKDrawIndexedIndirectNode
const CreateInfo &create_info) override
{
create_info.resources.build_links(resources, node_links);
vk_index_buffer_binding_build_links(resources, node_links, create_info.node_data.index_buffer);
if (create_info.node_data.index_buffer.buffer != VK_NULL_HANDLE) {
vk_index_buffer_binding_build_links(
resources, node_links, create_info.node_data.index_buffer);
}
vk_vertex_buffer_bindings_build_links(
resources, node_links, create_info.node_data.vertex_buffers);
ResourceWithStamp buffer_resource = resources.get_buffer(

View File

@@ -30,6 +30,9 @@ bool VKBuffer::create(size_t size_in_bytes,
BLI_assert(!is_allocated());
BLI_assert(vk_buffer_ == VK_NULL_HANDLE);
BLI_assert(mapped_memory_ == nullptr);
if (allocation_failed_) {
return false;
}
size_in_bytes_ = size_in_bytes;
/*
@@ -77,6 +80,9 @@ bool VKBuffer::create(size_t size_in_bytes,
VkResult result = vmaCreateBuffer(
allocator, &create_info, &vma_create_info, &vk_buffer_, &allocation_, nullptr);
if (result != VK_SUCCESS) {
allocation_failed_ = true;
size_in_bytes_ = 0;
alloc_size_in_bytes_ = 0;
return false;
}

View File

@@ -27,6 +27,8 @@ class VKBuffer : public NonCopyable {
VmaAllocation allocation_ = VK_NULL_HANDLE;
VkMemoryPropertyFlags vk_memory_property_flags_;
TimelineValue async_timeline_ = 0;
/** Has a previous allocation failed. Will skip reallocations. */
bool allocation_failed_ = false;
/* Pointer to the virtually mapped memory. */
void *mapped_memory_ = nullptr;

View File

@@ -113,7 +113,7 @@ void VKDebuggingTools::deinit(VkInstance vk_instance)
void object_label(VkObjectType vk_object_type, uint64_t object_handle, const char *name)
{
const VKDevice &device = VKBackend::get().device;
if (G.debug & G_DEBUG_GPU && device.functions.vkSetDebugUtilsObjectName) {
if (G.debug & G_DEBUG_GPU && device.functions.vkSetDebugUtilsObjectName && object_handle != 0) {
VkDebugUtilsObjectNameInfoEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
info.objectType = vk_object_type;

View File

@@ -163,11 +163,14 @@ void VKDescriptorSetTracker::bind_input_attachment_resource(
.vk_handle(),
VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
resource_binding.location);
access_info.images.append({texture->vk_image_handle(),
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({texture->vk_image_handle(),
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
}
else {
bool supports_dynamic_rendering = device.extensions_get().dynamic_rendering;
@@ -183,11 +186,14 @@ void VKDescriptorSetTracker::bind_input_attachment_resource(
texture->image_view_get(resource_binding.arrayed, VKImageViewFlags::DEFAULT).vk_handle(),
VK_IMAGE_LAYOUT_GENERAL,
resource_binding.location);
access_info.images.append({texture->vk_image_handle(),
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({vk_image,
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
}
else {
/* Fall back to render-passes / sub-passes. */
@@ -197,11 +203,14 @@ void VKDescriptorSetTracker::bind_input_attachment_resource(
.vk_handle(),
VK_IMAGE_LAYOUT_GENERAL,
resource_binding.location);
access_info.images.append({texture->vk_image_handle(),
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
VkImage vk_image = texture->vk_image_handle();
if (vk_image != VK_NULL_HANDLE) {
access_info.images.append({vk_image,
resource_binding.access_mask,
to_vk_image_aspect_flag_bits(texture->device_format_get()),
0,
VK_REMAINING_ARRAY_LAYERS});
}
}
}
}
@@ -260,7 +269,9 @@ void VKDescriptorSetTracker::bind_storage_buffer_resource(
elem.offset,
vk_device_size - elem.offset,
resource_binding.location);
access_info.buffers.append({vk_buffer, resource_binding.access_mask});
if (vk_buffer != VK_NULL_HANDLE) {
access_info.buffers.append({vk_buffer, resource_binding.access_mask});
}
}
void VKDescriptorSetTracker::bind_uniform_buffer_resource(