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>
This commit is contained in:
Iago Toral Quiroga
2020-05-15 10:46:13 +02:00
committed by Marge Bot
parent 57d0ff8d48
commit 10dbb1e07d
6 changed files with 108 additions and 13 deletions
+6 -2
View File
@@ -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);
+12 -9
View File
@@ -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;
+32 -2
View File
@@ -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) {
+3
View File
@@ -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) {
+30
View File
@@ -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);
+25
View File
@@ -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 */