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 <dani...@collabora.com>
Tested-by: Emre Ucan <eu...@de.adit-jv.com>
---
 libweston/compositor-drm.c | 69 +++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 24 deletions(-)

diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index d045778aa..d4898bc46 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,11 +3272,14 @@ 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,
                                           pending_state,
                                           DRM_OUTPUT_STATE_CLEAR_PLANES);
+       if (!planes_ok)
+               return state;
 
        /*
         * Find a surface for each sprite in the output using some heuristics:
@@ -3339,13 +3347,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 +3365,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);
@@ -3390,8 +3404,15 @@ 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)
+               state = drm_output_propose_state(output_base, pending_state,
+                                                
DRM_OUTPUT_PROPOSE_STATE_MIXED);
 
-       state = drm_output_propose_state(output_base, pending_state);
+       if (!state)
+               state = drm_output_propose_state(output_base, pending_state,
+                                                
DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
 
        wl_list_for_each(ev, &output_base->compositor->view_list, link) {
                struct drm_plane *target_plane = NULL;
-- 
2.17.1

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to