compositor-drm: refine overlay src and dest coordinate calculation

For desktop shell, its output size may different with current mode.
When prepare overlay plane, compositor should take this scale to
calculate the dest coordinate. And src coordinate should get from buffer.

Upstream-Status: Inappropriate [i.MX-specific]

Signed-off-by: Haihua Hu <jared.hu@nxp.com>
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 47f1412..8e34847 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1481,6 +1481,30 @@
 	return true;
 }
 
+static void
+drm_clip_overlay_coordinate(struct drm_output * output,
+				struct drm_plane_state * state)
+{
+	uint32_t src_w = state->src_w >> 16;
+	uint32_t src_h = state->src_h >> 16;
+	/* handle out of screen case */
+	if (state->dest_x + state->dest_w > output->base.current_mode->width){
+		int32_t crop_width = output->base.current_mode->width - state->dest_x;
+		if(crop_width > 0) {
+			state->src_w = ALIGNTO((crop_width * src_w / state->dest_w), 2) << 16;
+			state->dest_w = crop_width;
+		}
+	}
+
+	if (state->dest_y + state->dest_h > output->base.current_mode->height){
+		int32_t crop_height = output->base.current_mode->height - state->dest_y;
+		if(crop_height > 0) {
+			state->src_h = ALIGNTO((crop_height * src_h / state->dest_h), 2) << 16;
+			state->dest_h = crop_height;
+		}
+	}
+}
+
 /**
  * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
  * a given plane.
@@ -1490,14 +1514,21 @@
 				struct weston_view *ev)
 {
 	struct drm_output *output = state->output;
-	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
-	pixman_region32_t dest_rect, src_rect;
+	struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+	pixman_region32_t dest_rect;
 	pixman_box32_t *box, tbox;
-	float sxf1, syf1, sxf2, syf2;
+	int32_t scale;
+	int src_x, src_y, src_width, src_height;
 
 	if (!drm_view_transform_supported(ev, &output->base))
 		return false;
 
+	if (viewport->buffer.scale != output->base.current_scale){
+		scale = MAX(viewport->buffer.scale, output->base.current_scale);
+	} else {
+		scale = output->base.current_scale;
+	}
+
 	/* Update the base weston_plane co-ordinates. */
 	box = pixman_region32_extents(&ev->transform.boundingbox);
 	state->plane->base.x = box->x1;
@@ -1514,7 +1545,7 @@
 	tbox = weston_transformed_rect(output->base.width,
 				       output->base.height,
 				       output->base.transform,
-				       output->base.current_scale,
+				       scale,
 				       *box);
 	state->dest_x = tbox.x1;
 	state->dest_y = tbox.y1;
@@ -1522,50 +1553,29 @@
 	state->dest_h = tbox.y2 - tbox.y1;
 	pixman_region32_fini(&dest_rect);
 
-	/* Now calculate the source rectangle, by finding the extents of the
-	 * view, and working backwards to source co-ordinates. */
-	pixman_region32_init(&src_rect);
-	pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
-				  &output->base.region);
-	box = pixman_region32_extents(&src_rect);
-	weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
-	weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
-	weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
-	weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
-	pixman_region32_fini(&src_rect);
+	src_x = wl_fixed_to_int (viewport->buffer.src_x);
+	src_y = wl_fixed_to_int (viewport->buffer.src_y);
+	src_width = wl_fixed_to_int (viewport->buffer.src_width);
+	src_height = wl_fixed_to_int (viewport->buffer.src_height);
 
-	/* Buffer transforms may mean that x2 is to the left of x1, and/or that
-	 * y2 is above y1. */
-	if (sxf2 < sxf1) {
-		double tmp = sxf1;
-		sxf1 = sxf2;
-		sxf2 = tmp;
+	if(src_width != -1 && src_width > 0 && src_x >=0 && src_y >= 0
+		&& src_x * scale < state->fb->width
+		&& src_y * scale < state->fb->height)
+	{
+		state->src_x = (src_x * scale) << 16;
+		state->src_y = (src_y * scale) << 16;
+		state->src_w = MIN(state->fb->width - src_x * scale, src_width * scale) << 16;
+		state->src_h = MIN(state->fb->height - src_y * scale, src_height * scale) << 16;
 	}
-	if (syf2 < syf1) {
-		double tmp = syf1;
-		syf1 = syf2;
-		syf2 = tmp;
-	}
-
-	/* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
-	state->src_x = wl_fixed_from_double(sxf1) << 8;
-	state->src_y = wl_fixed_from_double(syf1) << 8;
-	state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
-	state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
-
-	/* Clamp our source co-ordinates to surface bounds; it's possible
-	 * for intermediate translations to give us slightly incorrect
-	 * co-ordinates if we have, for example, multiple zooming
-	 * transformations. View bounding boxes are also explicitly rounded
-	 * greedily. */
-	if (state->src_x < 0)
+	else
+	{
 		state->src_x = 0;
-	if (state->src_y < 0)
 		state->src_y = 0;
-	if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
-		state->src_w = (buffer->width << 16) - state->src_x;
-	if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
-		state->src_h = (buffer->height << 16) - state->src_y;
+		state->src_w = state->fb->width << 16;
+		state->src_h = state->fb->height << 16;
+	}
+
+	drm_clip_overlay_coordinate(output, state);
 
 	return true;
 }
@@ -3254,7 +3264,15 @@
 
 		state->ev = ev;
 		state->output = output;
+
+		/* We hold one reference for the lifetime of this function;
+		 * from calling drm_fb_get_from_view, to the out label where
+		 * we unconditionally drop the reference. So, we take another
+		 * reference here to live within the state. */
+		state->fb = drm_fb_ref(fb);
+
 		if (!drm_plane_state_coords_for_view(state, ev)) {
+			drm_fb_unref(fb);
 			drm_plane_state_put_back(state);
 			state = NULL;
 			continue;
@@ -3262,17 +3280,12 @@
 		if (!b->atomic_modeset &&
 		    (state->src_w != state->dest_w << 16 ||
 		     state->src_h != state->dest_h << 16)) {
+			drm_fb_unref(fb);
 			drm_plane_state_put_back(state);
 			state = NULL;
 			continue;
 		}
 
-		/* We hold one reference for the lifetime of this function;
-		 * from calling drm_fb_get_from_view, to the out label where
-		 * we unconditionally drop the reference. So, we take another
-		 * reference here to live within the state. */
-		state->fb = drm_fb_ref(fb);
-
 		/* In planes-only mode, we don't have an incremental state to
 		 * test against, so we just hope it'll work. */
 		if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY)