compositor-drm: Use plane_state_coords_for_view for scanout

Now that we have a helper to fill the plane state co-ordinates from a
view, use this for the scanout plane.

We now explicitly check that the view fills exactly the fullscreen area
and nothing else. We then use the new helper to fill out the plane state
values, and do further checks against the filled-in co-ordinates, i.e.
that we're not trying to show an offset into the buffer, or to scale the
image.

This now allows cases where the buffer -> surface -> view -> output
transform chain cancels each other out for scaling: previously, we would
never consider a buffer for scanout unless its scale matched the
output's. We now only look at the final result of the buffer -> output
transformation, to check that this does not result in translation or
scaling.

An audit of the error paths found some places where we would leave a
plane state hanging; this makes them all consistent.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Tested-by: Emre Ucan <eucan@de.adit-jv.com>
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index c35fccd..71f27d1 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1670,8 +1670,8 @@
 	struct drm_plane *scanout_plane = output->scanout_plane;
 	struct drm_plane_state *state;
 	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
-	struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
 	struct gbm_bo *bo;
+	pixman_box32_t *extents;
 
 	/* Don't import buffers which span multiple outputs. */
 	if (ev->output_mask != (1u << output->base.id))
@@ -1686,21 +1686,13 @@
 	if (wl_shm_buffer_get(buffer->resource))
 		return NULL;
 
-	/* Make sure our view is exactly compatible with the output. */
-	if (ev->geometry.x != output->base.x ||
-	    ev->geometry.y != output->base.y)
-		return NULL;
-	if (buffer->width != output->base.current_mode->width ||
-	    buffer->height != output->base.current_mode->height)
-		return NULL;
-
-	if (ev->transform.enabled)
-		return NULL;
-	if (ev->geometry.scissor_enabled)
-		return NULL;
-	if (viewport->buffer.scale != output->base.current_scale)
-		return NULL;
-	if (!drm_view_transform_supported(ev, &output->base))
+	/* Check the view spans exactly the output size, calculated in the
+	 * logical co-ordinate space. */
+	extents = pixman_region32_extents(&ev->transform.boundingbox);
+	if (extents->x1 != output->base.x ||
+	    extents->y1 != output->base.y ||
+	    extents->x2 != output->base.x + output->base.width ||
+	    extents->y2 != output->base.y + output->base.height)
 		return NULL;
 
 	if (ev->alpha != 1.0f)
@@ -1715,44 +1707,48 @@
 		return NULL;
 	}
 
+	state->output = output;
+	if (!drm_plane_state_coords_for_view(state, ev))
+		goto err;
+
+	/* The legacy API does not let us perform cropping or scaling. */
+	if (state->src_x != 0 || state->src_y != 0 ||
+	    state->src_w != state->dest_w << 16 ||
+	    state->src_h != state->dest_h << 16 ||
+	    state->dest_x != 0 || state->dest_y != 0 ||
+	    state->dest_w != (unsigned) output->base.current_mode->width ||
+	    state->dest_h != (unsigned) output->base.current_mode->height)
+		goto err;
+
 	bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
 			   buffer->resource, GBM_BO_USE_SCANOUT);
 
 	/* Unable to use the buffer for scanout */
 	if (!bo)
-		return NULL;
+		goto err;
 
 	state->fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev),
 				       BUFFER_CLIENT);
 	if (!state->fb) {
-		drm_plane_state_put_back(state);
+		/* We need to explicitly destroy the BO. */
 		gbm_bo_destroy(bo);
-		return NULL;
+		goto err;
 	}
 
 	/* Can't change formats with just a pageflip */
 	if (state->fb->format->format != output->gbm_format) {
 		/* No need to destroy the GBM BO here, as it's now owned
 		 * by the FB. */
-		drm_plane_state_put_back(state);
-		return NULL;
+		goto err;
 	}
 
 	drm_fb_set_buffer(state->fb, buffer);
 
-	state->output = output;
-
-	state->src_x = 0;
-	state->src_y = 0;
-	state->src_w = state->fb->width << 16;
-	state->src_h = state->fb->height << 16;
-
-	state->dest_x = 0;
-	state->dest_y = 0;
-	state->dest_w = output->base.current_mode->width;
-	state->dest_h = output->base.current_mode->height;
-
 	return &scanout_plane->base;
+
+err:
+	drm_plane_state_put_back(state);
+	return NULL;
 }
 
 static struct drm_fb *