summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIago Toral Quiroga <itoral@igalia.com>2020-05-15 10:46:13 +0200
committerMarge Bot <eric+marge@anholt.net>2020-10-13 21:21:30 +0000
commit10dbb1e07daaaf52719b5d22b50b809c389d5b51 (patch)
treec5dcdb21246982419641c41e3dc82dce90da3710
parent57d0ff8d481bda738cbc41fad5fb2c62a825d83d (diff)
v3dv: make the driver more robust against OOM
This is generally very difficult to handle properly everywhere, but at least this is good enough to make the few CTS tests for this happy. Fixes (on Rpi4): dEQP-VK.wsi.xlib.swapchain.simulate_oom.* Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
-rw-r--r--src/broadcom/vulkan/v3dv_bo.c8
-rw-r--r--src/broadcom/vulkan/v3dv_cl.c21
-rw-r--r--src/broadcom/vulkan/v3dv_cmd_buffer.c34
-rw-r--r--src/broadcom/vulkan/v3dv_meta_clear.c3
-rw-r--r--src/broadcom/vulkan/v3dv_meta_copy.c30
-rw-r--r--src/broadcom/vulkan/v3dv_private.h25
6 files changed, 108 insertions, 13 deletions
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 */