@@ -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 && \
@@ -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;
}
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(-)