From f7a2f835ae83409dec1e0487424cec7718385fb6 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Thu, 8 Dec 2016 17:19:09 +0000 Subject: [PATCH] compositor-drm: Add modes to drm_output_propose_state Add support for multiple modes to drm_output_propose_state. Currently we intend to operate in three modes: planes-only (no renderer buffer, client buffers in planes only), mixed-mode (promote client buffers to planes where possible, falling back to the renderer where not), and renderer-only (no plane usage at all). We want to use the first (planes-only) mode where possible: it can avoid us having to allocate buffers for the renderer, and it also gives us the best chance of the optimal configuration, with no composition. In this mode, we walk the scene looking at all views, trying to put them in planes, and failing as soon as we find a view we cannot place in a plane. In the second mode, rather than failing, we assign those views which cannot be on a plane to the renderer, and allow the renderer to composite them. In the third mode, planes are not usable, so everything but the cursor goes to the renderer. We will use this when we cannot use the planes-only mode (because some views cannot be placed in planes), but also cannot use the 'mixed' mode because we have no renderer buffer yet. Since we walk the scene graph from top to bottom, using atomic modesetting we will determine if planes can be promoted in mixed mode by placing a renderer buffer at the bottom of the scene, placing a cursor buffer if applicable, then testing if we can add overlay planes to this mode. Without a buffer from the renderer, we cannot do these tests, so we push everything through the renderer and then switch to mixed mode on the next repaint. This patch implements the mixed and renderer-only modes (previously differentiated only by the sprites_are_broken flag), with the planes-only mode being left for a later patch. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- libweston/compositor-drm.c | 70 +++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index d045778..56e7e5d 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -1939,6 +1939,11 @@ drm_output_assign_state(struct drm_output_state *state, } } +enum drm_output_propose_state_mode { + DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */ + DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer & cursor */ +}; + static struct weston_plane * drm_output_prepare_scanout_view(struct drm_output_state *output_state, struct weston_view *ev) @@ -3121,10 +3126,9 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state, struct wl_shm_buffer *shmbuf; bool needs_update = false; - if (!plane) - return NULL; + assert(!b->cursors_are_broken); - if (b->cursors_are_broken) + if (!plane) return NULL; if (!plane->state_cur->complete) @@ -3259,7 +3263,8 @@ err: static struct drm_output_state * drm_output_propose_state(struct weston_output *output_base, - struct drm_pending_state *pending_state) + struct drm_pending_state *pending_state, + enum drm_output_propose_state_mode mode) { struct drm_output *output = to_drm_output(output_base); struct drm_backend *b = to_drm_backend(output->base.compositor); @@ -3267,6 +3272,7 @@ drm_output_propose_state(struct weston_output *output_base, struct weston_view *ev; pixman_region32_t surface_overlap, renderer_region, occluded_region; struct weston_plane *primary = &output_base->compositor->primary_plane; + bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY); assert(!output->state_last); state = drm_output_state_duplicate(output->state_cur, @@ -3339,13 +3345,16 @@ drm_output_propose_state(struct weston_output *output_base, next_plane = primary; pixman_region32_fini(&surface_overlap); - if (next_plane == NULL) + /* The cursor plane is 'special' in the sense that we can still + * place it in the legacy API, and we gate that with a separate + * cursors_are_broken flag. */ + if (next_plane == NULL && !b->cursors_are_broken) next_plane = drm_output_prepare_cursor_view(state, ev); if (next_plane == NULL && !drm_view_is_opaque(ev)) next_plane = primary; - if (next_plane == NULL && b->sprites_are_broken) + if (next_plane == NULL && !planes_ok) next_plane = primary; if (next_plane == NULL) @@ -3354,24 +3363,27 @@ drm_output_propose_state(struct weston_output *output_base, if (next_plane == NULL) next_plane = drm_output_prepare_overlay_view(state, ev); - if (next_plane == NULL) - next_plane = primary; + if (next_plane && next_plane != primary) { + /* If we have been assigned to an overlay or scanout + * plane, add this area to the occluded region, so + * other views are known to be behind it. The cursor + * plane, however, is special, in that it blends with + * the content underneath it: the area should neither + * be added to the renderer region nor the occluded + * region. */ + if (!output->cursor_plane || + next_plane != &output->cursor_plane->base) { + pixman_region32_union(&occluded_region, + &occluded_region, + &clipped_view); + pixman_region32_fini(&clipped_view); + } + continue; + } - /* If we've been assigned to the 'primary' (renderer) plane, - * add this to our renderer region. If we have been assigned - * to the cursor plane, do nothing, as the cursor plane is - * blended with content underneath it. If neither, we have - * been assigned to an overlay plane, so add this view's - * area to the occluded region. */ - if (next_plane == primary) - pixman_region32_union(&renderer_region, - &renderer_region, - &clipped_view); - else if (!output->cursor_plane || - next_plane != &output->cursor_plane->base) - pixman_region32_union(&occluded_region, - &occluded_region, - &clipped_view); + pixman_region32_union(&renderer_region, + &renderer_region, + &clipped_view); pixman_region32_fini(&clipped_view); } pixman_region32_fini(&renderer_region); @@ -3386,12 +3398,20 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data) struct drm_backend *b = to_drm_backend(output_base->compositor); struct drm_pending_state *pending_state = repaint_data; struct drm_output *output = to_drm_output(output_base); - struct drm_output_state *state; + struct drm_output_state *state = NULL; struct drm_plane_state *plane_state; struct weston_view *ev; struct weston_plane *primary = &output_base->compositor->primary_plane; - state = drm_output_propose_state(output_base, pending_state); + if (!b->sprites_are_broken) + state = drm_output_propose_state(output_base, pending_state, + DRM_OUTPUT_PROPOSE_STATE_MIXED); + + if (!state) + state = drm_output_propose_state(output_base, pending_state, + DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY); + + assert(state); wl_list_for_each(ev, &output_base->compositor->view_list, link) { struct drm_plane *target_plane = NULL; -- 2.7.4