[PATCH v18 3/4] compositor-drm: Add modes to drm_output_propose_state

Daniel Stone daniels at collabora.com
Tue Jul 10 13:56:17 UTC 2018


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.

Signed-off-by: Daniel Stone <daniels at collabora.com>
Tested-by: Emre Ucan <eucan at de.adit-jv.com>
---
 libweston/compositor-drm.c | 86 +++++++++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 25 deletions(-)

diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 4a48e2d02..81fcd2412 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1939,16 +1939,25 @@ 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_PLANES_ONLY, /**< only assign to 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)
 {
 	struct drm_output *output = output_state->output;
+	struct drm_backend *b = to_drm_backend(output->base.compositor);
 	struct drm_plane *scanout_plane = output->scanout_plane;
 	struct drm_plane_state *state;
 	struct drm_fb *fb;
 	pixman_box32_t *extents;
 
+	assert(!b->sprites_are_broken);
+
 	/* Check the view spans exactly the output size, calculated in the
 	 * logical co-ordinate space. */
 	extents = pixman_region32_extents(&ev->transform.boundingbox);
@@ -3004,8 +3013,7 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
 	struct drm_fb *fb;
 	unsigned int i;
 
-	if (b->sprites_are_broken)
-		return NULL;
+	assert(!b->sprites_are_broken);
 
 	fb = drm_fb_get_from_view(output_state, ev);
 	if (!fb)
@@ -3119,10 +3127,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)
@@ -3257,13 +3264,17 @@ 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);
 	struct drm_output_state *state;
 	struct weston_view *ev;
 	pixman_region32_t surface_overlap, renderer_region, occluded_region;
 	struct weston_plane *primary = &output_base->compositor->primary_plane;
+	bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
+	bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
 
 	assert(!output->state_last);
 	state = drm_output_state_duplicate(output->state_cur,
@@ -3336,7 +3347,10 @@ 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))
@@ -3351,30 +3365,46 @@ 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) {
+			/* 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);
+		/* We have been assigned to the primary (renderer) plane:
+		 * check if this is OK, and add ourselves to the renderer
+		 * region if so. */
+		if (!renderer_ok) {
+			pixman_region32_fini(&clipped_view);
+			goto err;
+		}
+		pixman_region32_union(&renderer_region,
+				      &renderer_region,
+				      &clipped_view);
 		pixman_region32_fini(&clipped_view);
 	}
 	pixman_region32_fini(&renderer_region);
 	pixman_region32_fini(&occluded_region);
 
 	return state;
+
+err:
+	pixman_region32_fini(&renderer_region);
+	pixman_region32_fini(&occluded_region);
+	drm_output_state_free(state);
+	return NULL;
 }
 
 static void
@@ -3387,8 +3417,14 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
 	struct drm_plane_state *plane_state;
 	struct weston_view *ev;
 	struct weston_plane *primary = &output_base->compositor->primary_plane;
+	enum drm_output_propose_state_mode mode;
+
+	if (b->sprites_are_broken)
+		mode = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY;
+	else
+		mode = DRM_OUTPUT_PROPOSE_STATE_MIXED;
 
-	state = drm_output_propose_state(output_base, pending_state);
+	state = drm_output_propose_state(output_base, pending_state, mode);
 
 	wl_list_for_each(ev, &output_base->compositor->view_list, link) {
 		struct drm_plane *target_plane = NULL;
-- 
2.17.1



More information about the wayland-devel mailing list