diff --git a/src/broadcom/vulkan/v3dv_bo.c b/src/broadcom/vulkan/v3dv_bo.c index 847a19f1749..a63e61bbbea 100644 --- a/src/broadcom/vulkan/v3dv_bo.c +++ b/src/broadcom/vulkan/v3dv_bo.c @@ -34,8 +34,10 @@ v3dv_bo_alloc(struct v3dv_device *device, uint32_t size, const char *name) { struct v3dv_bo *bo = vk_alloc(&device->alloc, sizeof(struct v3dv_bo), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); - if (!bo) + if (!bo) { + fprintf(stderr, "Failed to allocate host memory for BO\n"); return NULL; + } const uint32_t page_align = 4096; /* Always allocate full pages */ size = align(size, page_align); @@ -45,6 +47,7 @@ v3dv_bo_alloc(struct v3dv_device *device, uint32_t size, const char *name) int ret = v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_CREATE_BO, &create); if (ret != 0) { + fprintf(stderr, "Failed to allocate device memory for BO\n"); return NULL; } @@ -64,7 +67,8 @@ v3dv_bo_alloc(struct v3dv_device *device, uint32_t size, const char *name) bool v3dv_bo_free(struct v3dv_device *device, struct v3dv_bo *bo) { - assert(bo); + if (!bo) + return true; if (bo->map) v3dv_bo_unmap(device, bo); diff --git a/src/broadcom/vulkan/v3dv_cl.c b/src/broadcom/vulkan/v3dv_cl.c index df5b47fbf00..9aab7b8cabd 100644 --- a/src/broadcom/vulkan/v3dv_cl.c +++ b/src/broadcom/vulkan/v3dv_cl.c @@ -73,16 +73,18 @@ v3dv_cl_ensure_space(struct v3dv_cl *cl, uint32_t space, uint32_t alignment) struct v3dv_bo *bo = v3dv_bo_alloc(cl->job->device, space, "CL"); if (!bo) { - fprintf(stderr, "failed to allocate memory for command list"); - abort(); + fprintf(stderr, "failed to allocate memory for command list\n"); + v3dv_flag_oom(NULL, cl->job); + return 0; } v3dv_job_add_bo(cl->job, bo); bool ok = v3dv_bo_map(cl->job->device, bo, bo->size); if (!ok) { - fprintf(stderr, "failed to map command list buffer"); - abort(); + fprintf(stderr, "failed to map command list buffer\n"); + v3dv_flag_oom(NULL, cl->job); + return 0; } cl->bo = bo; @@ -93,7 +95,6 @@ v3dv_cl_ensure_space(struct v3dv_cl *cl, uint32_t space, uint32_t alignment) return 0; } - void v3dv_cl_ensure_space_with_branch(struct v3dv_cl *cl, uint32_t space) { @@ -102,8 +103,9 @@ v3dv_cl_ensure_space_with_branch(struct v3dv_cl *cl, uint32_t space) struct v3dv_bo *bo = v3dv_bo_alloc(cl->job->device, space, "CL"); if (!bo) { - fprintf(stderr, "failed to allocate memory for command list"); - abort(); + fprintf(stderr, "failed to allocate memory for command list\n"); + v3dv_flag_oom(NULL, cl->job); + return; } /* Chain to the new BO from the old one if needed */ @@ -117,8 +119,9 @@ v3dv_cl_ensure_space_with_branch(struct v3dv_cl *cl, uint32_t space) bool ok = v3dv_bo_map(cl->job->device, bo, bo->size); if (!ok) { - fprintf(stderr, "failed to map command list buffer"); - abort(); + fprintf(stderr, "failed to map command list buffer\n"); + v3dv_flag_oom(NULL, cl->job); + return; } cl->bo = bo; diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c index 100fd71b532..73c19e2ad33 100644 --- a/src/broadcom/vulkan/v3dv_cmd_buffer.c +++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c @@ -206,7 +206,7 @@ v3dv_cmd_buffer_add_private_obj(struct v3dv_cmd_buffer *cmd_buffer, vk_alloc(&cmd_buffer->device->alloc, sizeof(*pobj), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!pobj) { - cmd_buffer->state.oom = true; + v3dv_flag_oom(cmd_buffer, NULL); return; } @@ -275,7 +275,10 @@ void v3dv_job_emit_binning_flush(struct v3dv_job *job) { assert(job); + v3dv_cl_ensure_space_with_branch(&job->bcl, cl_packet_length(FLUSH)); + v3dv_return_if_oom(NULL, job); + cl_emit(&job->bcl, FLUSH, flush); } @@ -448,6 +451,7 @@ v3dv_job_start_frame(struct v3dv_job *job, render_target_count, max_internal_bpp); v3dv_cl_ensure_space_with_branch(&job->bcl, 256); + v3dv_return_if_oom(NULL, job); /* The PTB will request the tile alloc initial size per tile at start * of tile binning. @@ -473,6 +477,11 @@ v3dv_job_start_frame(struct v3dv_job *job, job->tile_alloc = v3dv_bo_alloc(job->device, tile_alloc_size, "tile_alloc"); + if (!job->tile_alloc) { + v3dv_flag_oom(NULL, job); + return; + } + v3dv_job_add_bo(job, job->tile_alloc); const uint32_t tsda_per_tile_size = 256; @@ -481,6 +490,11 @@ v3dv_job_start_frame(struct v3dv_job *job, tiling->draw_tiles_y * tsda_per_tile_size; job->tile_state = v3dv_bo_alloc(job->device, tile_state_size, "TSDA"); + if (!job->tile_state) { + v3dv_flag_oom(NULL, job); + return; + } + v3dv_job_add_bo(job, job->tile_state); /* This must go before the binning mode configuration. It is @@ -568,6 +582,12 @@ v3dv_cmd_buffer_finish_job(struct v3dv_cmd_buffer *cmd_buffer) if (!job) return; + if (cmd_buffer->state.oom) { + v3dv_job_destroy(job); + cmd_buffer->state.job = NULL; + return; + } + assert(v3dv_cl_offset(&job->bcl) != 0); /* When we merge multiple subpasses into the same job we must only emit one @@ -602,6 +622,8 @@ v3dv_job_init(struct v3dv_job *job, job->device = device; job->cmd_buffer = cmd_buffer; + list_inithead(&job->list_link); + if (type == V3DV_JOB_TYPE_GPU_CL) { job->bos = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); @@ -668,7 +690,7 @@ v3dv_cmd_buffer_start_job(struct v3dv_cmd_buffer *cmd_buffer, if (!job) { fprintf(stderr, "Error: failed to allocate CPU memory for job\n"); - cmd_buffer->state.oom = true; + v3dv_flag_oom(cmd_buffer, NULL); return NULL; } @@ -1405,6 +1427,8 @@ cmd_buffer_render_pass_emit_per_tile_rcl(struct v3dv_cmd_buffer *cmd_buffer, */ struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(cmd_buffer, NULL); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -1568,6 +1592,7 @@ cmd_buffer_emit_render_pass_rcl(struct v3dv_cmd_buffer *cmd_buffer) v3dv_cl_ensure_space_with_branch(&job->rcl, 200 + MAX2(fb_layers, 1) * 256 * cl_packet_length(SUPERTILE_COORDINATES)); + v3dv_return_if_oom(cmd_buffer, NULL); assert(state->subpass_idx < state->pass->subpass_count); const struct v3dv_subpass *subpass = @@ -2576,6 +2601,7 @@ emit_depth_bias(struct v3dv_cmd_buffer *cmd_buffer) assert(job); v3dv_cl_ensure_space_with_branch(&job->bcl, cl_packet_length(DEPTH_OFFSET)); + v3dv_return_if_oom(cmd_buffer, NULL); struct v3dv_dynamic_state *dynamic = &cmd_buffer->state.dynamic; cl_emit(&job->bcl, DEPTH_OFFSET, bias) { @@ -2595,6 +2621,8 @@ emit_line_width(struct v3dv_cmd_buffer *cmd_buffer) assert(job); v3dv_cl_ensure_space_with_branch(&job->bcl, cl_packet_length(LINE_WIDTH)); + v3dv_return_if_oom(cmd_buffer, NULL); + cl_emit(&job->bcl, LINE_WIDTH, line) { line.line_width = cmd_buffer->state.dynamic.line_width; } @@ -2618,6 +2646,7 @@ emit_blend(struct v3dv_cmd_buffer *cmd_buffer) cl_packet_length(COLOR_WRITE_MASKS); v3dv_cl_ensure_space_with_branch(&job->bcl, blend_packets_size); + v3dv_return_if_oom(cmd_buffer, NULL); if (cmd_buffer->state.dirty & V3DV_CMD_DIRTY_PIPELINE) { if (pipeline->blend.enables) { @@ -2810,6 +2839,7 @@ emit_gl_shader_state(struct v3dv_cmd_buffer *cmd_buffer) num_elements_to_emit * cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD), 32); + v3dv_return_if_oom(cmd_buffer, NULL); cl_emit_with_prepacked(&job->indirect, GL_SHADER_STATE_RECORD, pipeline->shader_state_record, shader) { diff --git a/src/broadcom/vulkan/v3dv_meta_clear.c b/src/broadcom/vulkan/v3dv_meta_clear.c index cb6fe25793f..6dc8b034b4d 100644 --- a/src/broadcom/vulkan/v3dv_meta_clear.c +++ b/src/broadcom/vulkan/v3dv_meta_clear.c @@ -768,6 +768,8 @@ emit_tlb_clear_per_tile_rcl(struct v3dv_cmd_buffer *cmd_buffer, struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(cmd_buffer, NULL); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -909,6 +911,7 @@ emit_tlb_clear_job(struct v3dv_cmd_buffer *cmd_buffer, v3dv_cl_ensure_space_with_branch(rcl, 200 + layer_count * 256 * cl_packet_length(SUPERTILE_COORDINATES)); + v3dv_return_if_oom(cmd_buffer, NULL); const struct v3dv_frame_tiling *tiling = &job->frame_tiling; cl_emit(rcl, TILE_RENDERING_MODE_CFG_COMMON, config) { diff --git a/src/broadcom/vulkan/v3dv_meta_copy.c b/src/broadcom/vulkan/v3dv_meta_copy.c index 27a9b2f24ca..588b7130bd7 100644 --- a/src/broadcom/vulkan/v3dv_meta_copy.c +++ b/src/broadcom/vulkan/v3dv_meta_copy.c @@ -213,6 +213,8 @@ emit_rcl_prologue(struct v3dv_job *job, v3dv_cl_ensure_space_with_branch(rcl, 200 + tiling->layers * 256 * cl_packet_length(SUPERTILE_COORDINATES)); + if (job->cmd_buffer->state.oom) + return NULL; cl_emit(rcl, TILE_RENDERING_MODE_CFG_COMMON, config) { config.early_z_disable = true; @@ -294,6 +296,8 @@ emit_frame_setup(struct v3dv_job *job, uint32_t layer, const union v3dv_clear_value *clear_value) { + v3dv_return_if_oom(NULL, job); + const struct v3dv_frame_tiling *tiling = &job->frame_tiling; struct v3dv_cl *rcl = &job->rcl; @@ -343,6 +347,8 @@ static void emit_supertile_coordinates(struct v3dv_job *job, struct framebuffer_data *framebuffer) { + v3dv_return_if_oom(NULL, job); + struct v3dv_cl *rcl = &job->rcl; const uint32_t min_y = framebuffer->min_y_supertile; @@ -550,6 +556,8 @@ emit_copy_layer_to_buffer_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -633,6 +641,8 @@ emit_copy_image_to_buffer_rcl(struct v3dv_job *job, { struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, NULL); + v3dv_return_if_oom(NULL, job); + for (int layer = 0; layer < job->frame_tiling.layers; layer++) emit_copy_layer_to_buffer(job, buffer, image, framebuffer, layer, region); cl_emit(rcl, END_OF_RENDERING, end); @@ -1056,6 +1066,8 @@ emit_copy_image_layer_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -1112,6 +1124,8 @@ emit_copy_image_rcl(struct v3dv_job *job, { struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, NULL); + v3dv_return_if_oom(NULL, job); + for (int layer = 0; layer < job->frame_tiling.layers; layer++) emit_copy_image_layer(job, dst, src, framebuffer, layer, region); cl_emit(rcl, END_OF_RENDERING, end); @@ -1332,6 +1346,8 @@ emit_clear_image_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -1383,6 +1399,8 @@ emit_clear_image_rcl(struct v3dv_job *job, struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, &clear_info); + v3dv_return_if_oom(NULL, job); + emit_frame_setup(job, 0, clear_value); emit_clear_image(job, image, framebuffer, aspects, layer, level); cl_emit(rcl, END_OF_RENDERING, end); @@ -1556,6 +1574,8 @@ emit_copy_buffer_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -1606,6 +1626,8 @@ emit_copy_buffer_rcl(struct v3dv_job *job, { struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, NULL); + v3dv_return_if_oom(NULL, job); + emit_frame_setup(job, 0, NULL); emit_copy_buffer(job, dst, src, dst_offset, src_offset, framebuffer, format); cl_emit(rcl, END_OF_RENDERING, end); @@ -1787,6 +1809,8 @@ emit_fill_buffer_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -1840,6 +1864,8 @@ emit_fill_buffer_rcl(struct v3dv_job *job, struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, &clear_info); + v3dv_return_if_oom(NULL, job); + emit_frame_setup(job, 0, &clear_value); emit_fill_buffer(job, bo, offset, framebuffer); cl_emit(rcl, END_OF_RENDERING, end); @@ -1921,6 +1947,8 @@ emit_copy_buffer_to_layer_per_tile_list(struct v3dv_job *job, { struct v3dv_cl *cl = &job->indirect; v3dv_cl_ensure_space(cl, 200, 1); + v3dv_return_if_oom(NULL, job); + struct v3dv_cl_reloc tile_list_start = v3dv_cl_get_address(cl); cl_emit(cl, TILE_COORDINATES_IMPLICIT, coords); @@ -2037,6 +2065,8 @@ emit_copy_buffer_to_image_rcl(struct v3dv_job *job, { struct v3dv_cl *rcl = emit_rcl_prologue(job, framebuffer->internal_type, NULL); + v3dv_return_if_oom(NULL, job); + for (int layer = 0; layer < job->frame_tiling.layers; layer++) emit_copy_buffer_to_layer(job, image, buffer, framebuffer, layer, region); cl_emit(rcl, END_OF_RENDERING, end); diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 21885f6ac1e..db9fa76119b 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -1536,4 +1536,29 @@ v3dv_ioctl(int fd, unsigned long request, void *arg) return drmIoctl(fd, request, arg); } +/* Flags OOM conditions in command buffer state. + * + * Note: notice that no-op jobs don't have a command buffer reference. + */ +static inline void +v3dv_flag_oom(struct v3dv_cmd_buffer *cmd_buffer, struct v3dv_job *job) +{ + if (cmd_buffer) { + cmd_buffer->state.oom = true; + } else { + assert(job); + if (job->cmd_buffer) + job->cmd_buffer->state.oom = true; + } +} + +#define v3dv_return_if_oom(_cmd_buffer, _job) do { \ + const struct v3dv_cmd_buffer *__cmd_buffer = _cmd_buffer; \ + if (__cmd_buffer && __cmd_buffer->state.oom) \ + return; \ + const struct v3dv_job *__job = _job; \ + if (__job && __job->cmd_buffer && __job->cmd_buffer->state.oom) \ + return; \ +} while(0) \ + #endif /* V3DV_PRIVATE_H */