compositor-drm: fix z-order inversion in plane assignment
authorMatt Hoosier <matt.hoosier@gmail.com>
Thu, 24 Aug 2017 14:24:20 +0000 (09:24 -0500)
committerDaniel Stone <daniels@collabora.com>
Mon, 4 Dec 2017 19:11:46 +0000 (19:11 +0000)
As discussed in the following thread:

https://lists.freedesktop.org/archives/wayland-devel/2017-August/034755.html

the existing plane assignment in the DRM backend is vulnerable to
accidental masking of the intended fullscreen surface. This change
adds a simple stateful memory to the plane assignment algorithm
to prevent that.

Reviewed-by: Daniel Stone <daniels@collabora.com>
libweston/compositor-drm.c

index 1b4db51..b77209c 100644 (file)
@@ -1869,6 +1869,7 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
        struct weston_view *ev, *next;
        pixman_region32_t overlap, surface_overlap;
        struct weston_plane *primary, *next_plane;
+       bool picked_scanout = false;
 
        /*
         * Find a surface for each sprite in the output using some heuristics:
@@ -1915,14 +1916,23 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
                                          &ev->transform.boundingbox);
 
                next_plane = NULL;
-               if (pixman_region32_not_empty(&surface_overlap))
+               if (pixman_region32_not_empty(&surface_overlap) || picked_scanout)
                        next_plane = primary;
                if (next_plane == NULL)
                        next_plane = drm_output_prepare_cursor_view(output, ev);
-               if (next_plane == NULL)
+
+               /* If a higher-stacked view already got assigned to scanout, it's incorrect to
+                * assign a subsequent (lower-stacked) view to scanout.
+                */
+               if (next_plane == NULL) {
                        next_plane = drm_output_prepare_scanout_view(output, ev);
+                       if (next_plane)
+                               picked_scanout = true;
+               }
+
                if (next_plane == NULL)
                        next_plane = drm_output_prepare_overlay_view(output, ev);
+
                if (next_plane == NULL)
                        next_plane = primary;