From 5cfc3b5cc965a64c07e69833f85d44e60d6f3a6e Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Thu, 12 Mar 2020 11:59:04 +0100 Subject: [PATCH] v3dv: handle the case where we fail to allocate a new job gracefully There are a handful of tests that simulate 'out of memory' situations during swapchain image creation, and these can lead to failed job allocations when the driver is running on the prime blit path, as that involves creating a command buffer. The tests expect us to handle this scenario gracefully and return an appropriate OOM error as a result. This make sure we don't try to dereference a job if we failed to allocate it so we don't crash and can return the OOM error gracefully in the process. Fixes: dEQP-VK.wsi.xlib.swapchain.simulate_oom.* Part-of: --- src/broadcom/vulkan/v3dv_cmd_buffer.c | 16 +++++++++++++--- src/broadcom/vulkan/v3dv_meta_copy.c | 15 +++++++++++++++ src/broadcom/vulkan/v3dv_private.h | 3 +++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c index 8c0d68a1e76..5ac8ab2c12f 100644 --- a/src/broadcom/vulkan/v3dv_cmd_buffer.c +++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c @@ -505,7 +505,14 @@ v3dv_cmd_buffer_start_job(struct v3dv_cmd_buffer *cmd_buffer, struct v3dv_job *job = vk_zalloc(&cmd_buffer->device->alloc, sizeof(struct v3dv_job), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - assert(job); + + cmd_buffer->state.job = job; + + if (!job) { + fprintf(stderr, "Error: failed to allocate CPU memory for job\n"); + cmd_buffer->state.oom = true; + return NULL; + } job->cmd_buffer = cmd_buffer; @@ -532,8 +539,6 @@ v3dv_cmd_buffer_start_job(struct v3dv_cmd_buffer *cmd_buffer, if (cmd_buffer->state.pass) job->first_subpass = subpass_idx; - cmd_buffer->state.job = job; - return job; } @@ -1486,6 +1491,8 @@ subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx) * the new job. */ struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, subpass_idx); + if (!job) + return; state->subpass_idx = subpass_idx; @@ -1551,6 +1558,9 @@ v3dv_EndCommandBuffer(VkCommandBuffer commandBuffer) { V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer); + if (cmd_buffer->state.oom) + return VK_ERROR_OUT_OF_HOST_MEMORY; + cmd_buffer->status = V3DV_CMD_BUFFER_STATUS_EXECUTABLE; struct v3dv_job *job = cmd_buffer->state.job; diff --git a/src/broadcom/vulkan/v3dv_meta_copy.c b/src/broadcom/vulkan/v3dv_meta_copy.c index 37988d11e5c..fdc64008aeb 100644 --- a/src/broadcom/vulkan/v3dv_meta_copy.c +++ b/src/broadcom/vulkan/v3dv_meta_copy.c @@ -644,6 +644,8 @@ copy_image_to_buffer_tlb(struct v3dv_cmd_buffer *cmd_buffer, assert(num_layers > 0); struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return; v3dv_cmd_buffer_start_frame(cmd_buffer, region->imageExtent.width, @@ -785,6 +787,8 @@ copy_image_tlb(struct v3dv_cmd_buffer *cmd_buffer, assert(num_layers > 0); struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return; v3dv_cmd_buffer_start_frame(cmd_buffer, region->extent.width, @@ -928,6 +932,8 @@ clear_image_tlb(struct v3dv_cmd_buffer *cmd_buffer, uint32_t height = u_minify(image->extent.height, level); struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return; v3dv_cmd_buffer_start_frame(cmd_buffer, width, height, 1, 1, internal_bpp); @@ -1131,6 +1137,8 @@ copy_buffer(struct v3dv_cmd_buffer *cmd_buffer, uint32_t dst_offset = region->dstOffset; while (num_items > 0) { job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return NULL; uint32_t width, height; framebuffer_size_for_pixel_count(num_items, &width, &height); @@ -1209,6 +1217,8 @@ v3dv_CmdUpdateBuffer(VkCommandBuffer commandBuffer, }; struct v3dv_job *copy_job = copy_buffer(cmd_buffer, dst_buffer->mem->bo, src_bo, ®ion); + if (!copy_job) + return; /* Make sure we add the BO to the list of extra BOs so it is not leaked. * If the copy job was split into multiple jobs, we just bind it to the last @@ -1299,6 +1309,8 @@ fill_buffer(struct v3dv_cmd_buffer *cmd_buffer, while (num_items > 0) { struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return; uint32_t width, height; framebuffer_size_for_pixel_count(num_items, &width, &height); @@ -1487,6 +1499,9 @@ copy_buffer_to_image_tlb(struct v3dv_cmd_buffer *cmd_buffer, assert(num_layers > 0); struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, -1); + if (!job) + return; + v3dv_cmd_buffer_start_frame(cmd_buffer, region->imageExtent.width, region->imageExtent.height, diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 46413a7d079..ec786d70df0 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -612,6 +612,9 @@ struct v3dv_cmd_buffer_state { struct v3dv_vertex_binding vertex_bindings[MAX_VBS]; uint8_t index_size; + + /* Used to flag OOM conditions during command buffer recording */ + bool oom; }; struct v3dv_descriptor {