diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index b45e6add6..95ed0e9a2 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -82,6 +82,8 @@ #define MAX_DMABUF_PLANES 4 #endif +#define DRM_MAX_REUSE_FAILURES 10 + /** * A small wrapper to print information into the 'drm-backend' debug scope. * @@ -224,6 +226,8 @@ struct drm_device { /* struct drm_colorop_3x1d_lut::link */ struct wl_list drm_colorop_3x1d_lut_list; + + int reused_state_failures; }; struct drm_backend { @@ -635,6 +639,9 @@ struct drm_output { submit_frame_cb virtual_submit_frame; enum wdrm_content_type content_type; + + bool reused_state; + bool force_rebuild_state; }; void diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 13b78c8a6..51b3f879b 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1099,6 +1099,7 @@ drm_repaint_flush_device(struct drm_device *device) struct drm_pending_state *pending_state; struct weston_output *base; int ret; + bool failed_reuse = false; pending_state = device->repaint_data; if (!pending_state) @@ -1120,7 +1121,22 @@ drm_repaint_flush_device(struct drm_device *device) if (!base->will_repaint || !tmp || tmp->device != device) continue; - if (ret == -EBUSY) + if (tmp->reused_state) { + failed_reuse = true; + tmp->force_rebuild_state = true; + device->reused_state_failures++; + } + } + + if (failed_reuse) + drm_debug(b, "[repaint] failed with reused state, will rebuild and try again.\n"); + + wl_list_for_each(base, &b->compositor->output_list, link) { + struct drm_output *tmp = to_drm_output(base); + if (!base->will_repaint || !tmp || tmp->device != device) + continue; + + if (ret == -EBUSY || failed_reuse) weston_output_schedule_repaint_restart(base); else weston_output_schedule_repaint_reset(base); diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index 0db96c419..bd512e3e6 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -920,10 +920,17 @@ drm_output_propose_state(struct weston_output *output_base, /* Record the current lowest zpos of the underlay plane */ uint64_t current_lowest_zpos_underlay = DRM_PLANE_ZPOS_INVALID_PLANE; + output->reused_state = false; + if (mode & DRM_OUTPUT_PROPOSE_STATE_REUSE) { struct weston_paint_node *pnode; bool found_primary = false; + if (output->force_rebuild_state) { + debug_propose_fail(output, mode, "previous state failed"); + return NULL; + } + if (output->state_cur->mode == DRM_OUTPUT_PROPOSE_STATE_INVALID) { debug_propose_fail(output, mode, "no previous state"); return NULL; @@ -1005,10 +1012,13 @@ drm_output_propose_state(struct weston_output *output_base, pnode->surface->buffer_release_ref.buffer_release); } - if (drm_pending_state_test(pending_state) != 0) { - debug_propose_fail(output, mode, "atomic test not OK"); - drm_output_state_free(state); - return NULL; + if (device->reused_state_failures > DRM_MAX_REUSE_FAILURES) { + drm_debug(b, "\t\t[reuse] must test due to high number of failures\n"); + if (drm_pending_state_test(pending_state) != 0) { + debug_propose_fail(output, mode, "atomic test not OK"); + drm_output_state_free(state); + return NULL; + } } if (!found_primary) { @@ -1022,7 +1032,7 @@ drm_output_propose_state(struct weston_output *output_base, drm_fb_unref(pstate->fb); pstate->fb = NULL; } - + output->reused_state = true; return state; } @@ -1397,6 +1407,8 @@ drm_assign_planes(struct weston_output *output_base) assert(state); assert(state->planes_enabled == !output_base->disable_planes); + output->force_rebuild_state = false; + drm_debug(b, "\t[repaint] Using %s composition\n", drm_propose_state_mode_to_string(mode));