diff mbox series

[v3,2/5] drm/i915/display/psr: Calculate Trancoder's SU rect and plane's SF rect

Message ID 20201127105041.2793779-2-gwan-gyeong.mun@intel.com (mailing list archive)
State New, archived
Headers show
Series [v3,1/5] drm/i915/display/psr: Calculate selective fetch plane registers | expand

Commit Message

Gwan-gyeong Mun Nov. 27, 2020, 10:50 a.m. UTC
It implements calculating of Selective Update area for transcoder.
SU follows crtc geometry.
the logic handles the following cases.
 1. plane has moved
 2. plane's alpha value has changed
 3. plane's visibility has changed
 4. plane's damage clips exist
 5. plane's fb has flipped, but there were no damaged clips

And it generates a Selective Fetch area for the plane.
Each SF area follows plane geometry.
SF rect is calculated by intersecting a plane's dst rect and SU rect.
in order to follow the plane's src geometry, the intersected rect
is converted to the plane's src geometry.

The current implementation does not handle a fully obscured plane area.
In order to optimize calculating of SU area, it needs to subtract
the accumulated SU area from the visible area.

Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.h |   9 +
 drivers/gpu/drm/i915/display/intel_psr.c     | 248 +++++++++++++++----
 2 files changed, 211 insertions(+), 46 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 5e0d42d82c11..b2969d8ff625 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -465,6 +465,15 @@  enum phy_fia {
 	     (__i)++) \
 		for_each_if(plane)
 
+#define for_each_oldnew_intel_plane_in_state_reverse(__state, plane, old_plane_state, new_plane_state, __i) \
+	for ((__i) = (__state)->base.dev->mode_config.num_total_plane - 1; \
+	     (__i) >= 0 && \
+		     ((plane) = to_intel_plane((__state)->base.planes[__i].ptr), \
+		      (old_plane_state) = to_intel_plane_state((__state)->base.planes[__i].old_state), \
+		      (new_plane_state) = to_intel_plane_state((__state)->base.planes[__i].new_state), 1); \
+	     (__i)--) \
+		for_each_if(plane)
+
 #define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \
 	for ((__i) = 0; \
 	     (__i) < (__state)->base.dev->mode_config.num_crtc && \
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index d9a395c486d3..f314f550b809 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1249,75 +1249,231 @@  static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
 	crtc_state->psr2_man_track_ctl = val;
 }
 
-static void clip_area_update(struct drm_rect *overlap_damage_area,
-			     struct drm_rect *damage_area)
+/* calculate and update selective update rect with update rect */
+static void
+su_rect_update(struct drm_rect *su_rect, struct drm_rect *update_rect)
 {
-	if (overlap_damage_area->y1 == -1) {
-		overlap_damage_area->y1 = damage_area->y1;
-		overlap_damage_area->y2 = damage_area->y2;
+	if (drm_rect_height(update_rect) <= 0)
 		return;
+
+	if (!drm_rect_height(su_rect)) {
+		/* when select update rect is empty */
+		su_rect->y1 = update_rect->y1;
+		su_rect->y2 = update_rect->y2;
+	} else {
+		su_rect->y1 = min(su_rect->y1, update_rect->y1);
+		su_rect->y2 = max(su_rect->y2, update_rect->y2);
 	}
+}
+
+static void
+plane_get_damage_rect(const struct drm_plane_state *state,
+		      struct drm_rect *damage_rect)
+{
+	struct drm_mode_rect *damage_clips;
+	int i;
+	u32 num_clips = drm_plane_get_damage_clips_count(state);
+
+
+	if (!num_clips)
+		return;
 
-	if (damage_area->y1 < overlap_damage_area->y1)
-		overlap_damage_area->y1 = damage_area->y1;
+	damage_clips = drm_plane_get_damage_clips(state);
 
-	if (damage_area->y2 > overlap_damage_area->y2)
-		overlap_damage_area->y2 = damage_area->y2;
+	/* initialize with first damage_clip */
+	damage_rect->x1 = damage_clips[0].x1;
+	damage_rect->y1 = damage_clips[0].y1;
+	damage_rect->x2 = damage_clips[0].x2;
+	damage_rect->y2 = damage_clips[0].y2;
+
+	for (i = 1; i < num_clips; i++) {
+		/* Selective Fetch has limitattion which only can have one rect */
+		damage_rect->x1 = min(damage_rect->x1, damage_clips[i].x1);
+		damage_rect->x2 = max(damage_rect->x2, damage_clips[i].x2);
+		damage_rect->y1 = min(damage_rect->y1, damage_clips[i].y1);
+		damage_rect->y2 = max(damage_rect->y2, damage_clips[i].y2);
+	}
 }
 
-int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
-				struct intel_crtc *crtc)
+/*
+ * Generate Selective Update area rect
+ * Todo: In order to optimize calculating of SU area, it should subtract
+ * accumulated SU area from the visible area.
+ */
+static void
+psr_generate_su_rect(struct intel_atomic_state *state,
+		     struct intel_crtc_state *crtc_state,
+		     struct drm_rect *su_rect)
 {
-	struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 	struct intel_plane_state *new_plane_state, *old_plane_state;
-	struct drm_rect pipe_clip = { .y1 = -1 };
 	struct intel_plane *plane;
-	bool full_update = false;
-	int i, ret;
+	int i;
 
-	if (!crtc_state->enable_psr2_sel_fetch)
-		return 0;
+	for_each_oldnew_intel_plane_in_state_reverse(state, plane, old_plane_state,
+						     new_plane_state, i) {
+		bool old_alpha, new_alpha, alpha_change;
+		bool visible, visibility_change;
+		bool flip, move;
+		u32 num_clips;
 
-	ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
-	if (ret)
-		return ret;
+		if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+			continue;
 
-	for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,
-					     new_plane_state, i) {
-		struct drm_rect *sel_fetch_area, temp;
+		if (plane->id == PLANE_CURSOR)
+			continue;
 
-		if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+		new_alpha = new_plane_state->uapi.alpha != DRM_BLEND_ALPHA_OPAQUE;
+		old_alpha = old_plane_state->uapi.alpha != DRM_BLEND_ALPHA_OPAQUE;
+		alpha_change = new_alpha != old_alpha;
+		visible = new_plane_state->uapi.visible;
+		visibility_change =
+			old_plane_state->uapi.visible != new_plane_state->uapi.visible;
+		flip = new_plane_state->uapi.fb != old_plane_state->uapi.fb;
+		move = !drm_rect_equals(&new_plane_state->uapi.dst,
+					&old_plane_state->uapi.dst);
+
+		/* 1. plane has moved */
+		if (move && !visibility_change && visible) {
+			su_rect_update(su_rect, &old_plane_state->uapi.dst);
+			su_rect_update(su_rect, &new_plane_state->uapi.dst);
 			continue;
+		}
 
-		/*
-		 * TODO: Not clear how to handle planes with negative position,
-		 * also planes are not updated if they have a negative X
-		 * position so for now doing a full update in this cases
-		 */
-		if (new_plane_state->uapi.dst.y1 < 0 ||
-		    new_plane_state->uapi.dst.x1 < 0) {
-			full_update = true;
-			break;
+		/* 2. plane's alpha value has changed */
+		if (alpha_change && !visibility_change && visible) {
+			su_rect_update(su_rect, &new_plane_state->uapi.dst);
+			continue;
+		}
+
+		/* 3. plane's visibility has changed */
+		if (visibility_change) {
+			if (visible)
+				su_rect_update(su_rect, &new_plane_state->uapi.dst);
+			else
+				su_rect_update(su_rect, &old_plane_state->uapi.dst);
+			continue;
+		}
+
+		num_clips = drm_plane_get_damage_clips_count(&new_plane_state->uapi);
+		/* 4. plane's damage clips exist */
+		if (num_clips && visible) {
+			struct drm_rect damage_rect, src_rect;
+
+			drm_rect_init(&damage_rect, 0, 0, 0, 0);
+			plane_get_damage_rect(&new_plane_state->uapi, &damage_rect);
+			/* convert fixed point float to int */
+			src_rect.x1 = new_plane_state->uapi.src.x1 >> 16;
+			src_rect.x2 = new_plane_state->uapi.src.x2 >> 16;
+			src_rect.y1 = new_plane_state->uapi.src.y1 >> 16;
+			src_rect.y2 = new_plane_state->uapi.src.y2 >> 16;
+
+			/* damage rect is based on src geometry */
+			if (drm_rect_intersect(&damage_rect, &src_rect)) {
+				/*
+				 * su rect is based on dst geometry
+				 * convert damage_rect's src geometry to dst geometry
+				 */
+				damage_rect.x1 =
+					damage_rect.x1 - src_rect.x1 +
+					new_plane_state->uapi.dst.x1;
+				damage_rect.x2 =
+					damage_rect.x2 - src_rect.x1 +
+					new_plane_state->uapi.dst.x1;
+				damage_rect.y1 =
+					damage_rect.y1 - src_rect.y1 +
+					new_plane_state->uapi.dst.y1;
+				damage_rect.y2 =
+					damage_rect.y2 - src_rect.y1 +
+					new_plane_state->uapi.dst.y1;
+
+				su_rect_update(su_rect, &damage_rect);
+			}
+			continue;
+		}
+
+		/* 5. plane's fb has flipped, but there were no damaged clips */
+		if (flip && visible) {
+			su_rect_update(su_rect, &new_plane_state->uapi.dst);
+			continue;
 		}
+	}
+}
+
+/*
+ * Generate Plane's Selective Fetch rect from intersected area between
+ * Selective Update area rect and plane's dst rect.
+ * Todo: Consider to handle a fully obscured plane.
+ */
+static void
+psr_generate_plane_sf_rect(struct intel_atomic_state *state,
+			   struct intel_crtc_state *crtc_state,
+			   const struct drm_rect *su_rect)
+{
+	struct intel_plane_state *new_plane_state, *old_plane_state;
+	struct intel_plane *plane;
+	int i;
+
+	for_each_oldnew_intel_plane_in_state_reverse(state, plane, old_plane_state,
+						     new_plane_state, i) {
+
+		struct drm_rect sf_rect = new_plane_state->uapi.dst;
+
+		if (new_plane_state->uapi.crtc != crtc_state->uapi.crtc)
+			continue;
+
+		if (plane->id == PLANE_CURSOR)
+			continue;
 
 		if (!new_plane_state->uapi.visible)
 			continue;
 
-		/*
-		 * For now doing a selective fetch in the whole plane area,
-		 * optimizations will come in the future.
-		 */
-		sel_fetch_area = &new_plane_state->psr2_sel_fetch_area;
-		sel_fetch_area->y1 = new_plane_state->uapi.src.y1 >> 16;
-		sel_fetch_area->y2 = new_plane_state->uapi.src.y2 >> 16;
-
-		temp = *sel_fetch_area;
-		temp.y1 += new_plane_state->uapi.dst.y1;
-		temp.y2 += new_plane_state->uapi.dst.y2;
-		clip_area_update(&pipe_clip, &temp);
+		if (drm_rect_intersect(&sf_rect, su_rect)) {
+			/*
+			 * su rect is based on dst geometry and sf rect should
+			 * follow src geometry. convert sf rect's dst geometry
+			 * to dst geometry
+			 */
+			sf_rect.x1 = sf_rect.x1 - new_plane_state->uapi.dst.x1 +
+				     (new_plane_state->uapi.src.x1 >> 16);
+			sf_rect.x2 = sf_rect.x2 - new_plane_state->uapi.dst.x1 +
+				     (new_plane_state->uapi.src.x1 >> 16);
+			sf_rect.y1 = sf_rect.y1 - new_plane_state->uapi.dst.y1 +
+				     (new_plane_state->uapi.src.y1 >> 16);
+			sf_rect.y2 = sf_rect.y2 - new_plane_state->uapi.dst.y1 +
+				     (new_plane_state->uapi.src.y1 >> 16);
+
+			new_plane_state->psr2_sel_fetch_area = sf_rect;
+		}
 	}
+}
+
+int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+				struct intel_crtc *crtc)
+{
+	struct intel_crtc_state *crtc_state =
+		intel_atomic_get_new_crtc_state(state, crtc);
+	struct drm_rect su_rect;
+	bool full_update = false;
+	int ret;
+
+	if (!crtc_state->enable_psr2_sel_fetch)
+		return 0;
+
+	ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
+	if (ret)
+		return ret;
+
+	/*
+	 * Generate Selective Update area rect
+	 * Todo: In order to optimize calculating of SU area, it should subtract
+	 * accumulated SU area from the visible area.
+	 */
+	drm_rect_init(&su_rect, 0, 0,
+		      crtc_state->uapi.adjusted_mode.crtc_hdisplay, 0);
+	psr_generate_su_rect(state, crtc_state, &su_rect);
+	psr_generate_plane_sf_rect(state, crtc_state, &su_rect);
+	psr2_man_trk_ctl_calc(crtc_state, &su_rect, full_update);
 
-	psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update);
 	return 0;
 }