compositor-drm: Assign primary framebuffer in assign_planes callout

Determining whether it was possible to use a surface buffer as the
primary framebuffer was always a bit of a hack.  Just before rendering,
we look at the second top-most surface to see if it's the right size and
position and then use it if it is.  If we have a hw cursor and a drm
plane on top, it's no longer the second top-most and it wouldn't be picked
even if it could work.

With this change, we inspect surfaces in drm_assign_planes and try to find
a candidate for the primary fb there.  We track the overlap like for
overlays and if there is a surface that's not overlapped and fills the
output we pick it.

This commit also consolidate the logic to track damage as we move a surface
in and out of the primary plane, which was missing in the drm plane case.
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index fad8977..6a36573 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -46,7 +46,9 @@
 static int option_current_mode = 0;
 
 enum {
-	WESTON_PLANE_DRM_CURSOR = 0x100
+	WESTON_PLANE_DRM_CURSOR =	0x100,
+	WESTON_PLANE_DRM_PLANE =	0x101,
+	WESTON_PLANE_DRM_FB =		0x102
 };
 
 struct drm_compositor {
@@ -144,18 +146,6 @@
 };
 
 static int
-surface_is_primary(struct weston_compositor *ec, struct weston_surface *es)
-{
-	struct weston_surface *primary;
-
-	primary = container_of(ec->surface_list.next, struct weston_surface,
-			       link);
-	if (es == primary)
-		return -1;
-	return 0;
-}
-
-static int
 drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
 {
 	struct weston_compositor *ec = output_base->compositor;
@@ -242,16 +232,14 @@
 }
 
 static int
-drm_output_prepare_scanout_surface(struct drm_output *output)
+drm_output_prepare_scanout_surface(struct weston_output *_output,
+				   struct weston_surface *es)
 {
+	struct drm_output *output = (struct drm_output *) _output;
 	struct drm_compositor *c =
 		(struct drm_compositor *) output->base.compositor;
-	struct weston_surface *es;
 	struct gbm_bo *bo;
 
-	es = container_of(c->base.surface_list.next,
-			  struct weston_surface, link);
-
 	if (es->geometry.x != output->base.x ||
 	    es->geometry.y != output->base.y ||
 	    es->geometry.width != output->base.current->width ||
@@ -285,8 +273,7 @@
 	wl_signal_add(&output->next->buffer->resource.destroy_signal,
 		      &output->next->buffer_destroy_listener);
 
-	pixman_region32_fini(&es->damage);
-	pixman_region32_init(&es->damage);
+	es->plane = WESTON_PLANE_DRM_FB;
 
 	return 0;
 }
@@ -307,7 +294,8 @@
 	}
 
 	wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
-		weston_surface_draw(surface, &output->base, damage);
+		if (surface->plane == WESTON_PLANE_PRIMARY)
+			weston_surface_draw(surface, &output->base, damage);
 
 	wl_signal_emit(&output->base.frame_signal, output);
 
@@ -337,7 +325,6 @@
 	struct drm_mode *mode;
 	int ret = 0;
 
-	drm_output_prepare_scanout_surface(output);
 	if (!output->next)
 		drm_output_render(output, damage);
 	if (!output->next)
@@ -509,18 +496,6 @@
 	return 1;
 }
 
-static int
-drm_surface_overlap_supported(struct weston_output *output_base,
-			      pixman_region32_t *overlap)
-{
-	/* We could potentially use a color key here if the surface left
-	 * to display has rectangular regions
-	 */
-	if (pixman_region32_not_empty(overlap))
-		return 0;
-	return 1;
-}
-
 static void
 drm_disable_unused_sprites(struct weston_output *output_base)
 {
@@ -560,8 +535,7 @@
  */
 static int
 drm_output_prepare_overlay_surface(struct weston_output *output_base,
-				   struct weston_surface *es,
-				   pixman_region32_t *overlap)
+				   struct weston_surface *es)
 {
 	struct weston_compositor *ec = output_base->compositor;
 	struct drm_compositor *c =(struct drm_compositor *) ec;
@@ -583,18 +557,12 @@
 	if (es->output_mask != (1u << output_base->id))
 		return -1;
 
-	if (surface_is_primary(ec, es))
-		return -1;
-
 	if (es->buffer == NULL)
 		return -1;
 
 	if (!drm_surface_transform_supported(es))
 		return -1;
 
-	if (!drm_surface_overlap_supported(output_base, overlap))
-		return -1;
-
 	wl_list_for_each(s, &c->sprite_list, link) {
 		if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
 			continue;
@@ -639,14 +607,6 @@
 		return -1;
 	}
 
-	if (s->surface && s->surface != es) {
-		struct weston_surface *old_surf = s->surface;
-		pixman_region32_fini(&old_surf->damage);
-		pixman_region32_init_rect(&old_surf->damage,
-					  old_surf->geometry.x, old_surf->geometry.y,
-					  old_surf->geometry.width, old_surf->geometry.height);
-	}
-
 	s->pending_fb_id = fb_id;
 	s->pending_surface = es;
 	es->buffer->busy_count++;
@@ -696,6 +656,8 @@
 	s->src_h = (sy2 - sy1) << 8;
 	pixman_region32_fini(&src_rect);
 
+	es->plane = WESTON_PLANE_DRM_PLANE;
+
 	wl_signal_add(&es->buffer->resource.destroy_signal,
 		      &s->pending_destroy_listener);
 
@@ -708,8 +670,7 @@
 
 static void
 weston_output_set_cursor(struct weston_output *output,
-			 struct weston_seat *seat,
-			 pixman_region32_t *overlap)
+			 struct weston_seat *seat)
 {
 	pixman_region32_t cursor_region;
 
@@ -721,26 +682,10 @@
 				  &seat->sprite->transform.boundingbox,
 				  &output->region);
 
-	if (!pixman_region32_not_empty(&cursor_region)) {
-		drm_output_set_cursor(output, NULL);
-		goto out;
-	}
-
-	if (pixman_region32_not_empty(overlap) ||
-	    drm_output_set_cursor(output, seat) < 0) {
-		if (seat->sprite->plane == WESTON_PLANE_DRM_CURSOR) {
-			weston_surface_damage(seat->sprite);
-			drm_output_set_cursor(output, NULL);
-		}
-		seat->sprite->plane = WESTON_PLANE_PRIMARY;
-	} else {
-		if (seat->sprite->plane == WESTON_PLANE_PRIMARY)
-			weston_surface_damage_below(seat->sprite);
-		wl_list_remove(&seat->sprite->link);
+	if (pixman_region32_not_empty(&cursor_region) &&
+	    drm_output_set_cursor(output, seat) == 0)
 		seat->sprite->plane = WESTON_PLANE_DRM_CURSOR;
-	}
 
-out:
 	pixman_region32_fini(&cursor_region);
 }
 
@@ -751,6 +696,7 @@
 	struct weston_surface *es, *next;
 	pixman_region32_t overlap, surface_overlap;
 	struct weston_seat *seat;
+	int prev_plane;
 
 	/*
 	 * Find a surface for each sprite in the output using some heuristics:
@@ -776,26 +722,36 @@
 		pixman_region32_intersect(&surface_overlap, &overlap,
 					  &es->transform.boundingbox);
 
-		if (es == seat->sprite) {
-			weston_output_set_cursor(output, seat,
-						 &surface_overlap);
+		prev_plane = es->plane;
+		es->plane = WESTON_PLANE_PRIMARY;
+		if (pixman_region32_not_empty(&surface_overlap))
+			goto bail;
 
-			if (seat->sprite->plane == WESTON_PLANE_PRIMARY)
-				pixman_region32_union(&overlap, &overlap,
-						      &es->transform.boundingbox);
-		} else if (!drm_output_prepare_overlay_surface(output, es,
-							       &surface_overlap)) {
-			pixman_region32_fini(&es->damage);
-			pixman_region32_init(&es->damage);
-		} else {
+		if (es == seat->sprite)
+			weston_output_set_cursor(output, seat);
+
+		if (es->plane == WESTON_PLANE_PRIMARY)
+			drm_output_prepare_scanout_surface(output, es);
+		if (es->plane == WESTON_PLANE_PRIMARY)
+			drm_output_prepare_overlay_surface(output, es);
+
+	bail:
+		if (es->plane == WESTON_PLANE_PRIMARY)
 			pixman_region32_union(&overlap, &overlap,
 					      &es->transform.boundingbox);
-		}
+
+		if (prev_plane != WESTON_PLANE_PRIMARY &&
+		    es->plane == WESTON_PLANE_PRIMARY)
+			weston_surface_damage(es);
+		else if (prev_plane == WESTON_PLANE_PRIMARY &&
+			 es->plane != WESTON_PLANE_PRIMARY)
+			weston_surface_damage_below(es);
+
 		pixman_region32_fini(&surface_overlap);
 	}
 	pixman_region32_fini(&overlap);
 
-	if (!seat->sprite || !weston_surface_is_mapped(seat->sprite))
+	if (!seat->sprite || seat->sprite->plane == WESTON_PLANE_PRIMARY)
 		drm_output_set_cursor(output, NULL);
 
 	drm_disable_unused_sprites(output);