[PATCH 2/2] drm/i915/fbc: nuke CFB if Plane setting (except for surf addr) changes

Austin Hu <[email protected]>
Newsgroups org.freedesktop.lists.intel-gfx,org.freedesktop.lists.intel-xe
Message-ID <[email protected]>
When FBC Dirty Rectangle mode is enabled, any non-PLANE_SURF register
update requires fetching the full plane frame buffer from memory to
re-compress and update the CFB in stolen memory.

Check plane state attributes during atomic commits and force a full
CFB nuke if any setting other than the surface address changes.

Signed-off-by: Austin Hu <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_fbc.c | 126 ++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index c0fed695af0d..6bf5c0947671 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -1516,8 +1516,124 @@ static bool intel_fbc_is_ok(const struct intel_plane_state *plane_state)
 		intel_fbc_is_cfb_ok(plane_state);
 }
 
+/*
+ * From BSpec about "FBC Dirty Rectangle", when Dirty Rectangle mode is active,
+ * partial updates only apply to surface address changes. Any other plane state
+ * modification requires Plane to fetch full-plane pixel data from memory to
+ * re-compress and update the entire CFB in stolen memory. Once fully
+ * re-compressed, subsequent atomic commits go ahead with FBC dirty rectangle
+ * updates for smooth visual updates.
+ *
+ * So check any Plane attribute changed except for its surface address by
+ * referring to intel_async_flip_check_hw() which also checks async flip.
+ */
+static bool intel_fbc_dirty_rect_needs_nuke(struct intel_atomic_state *state,
+					    struct intel_plane *plane)
+{
+	struct intel_display *display = to_intel_display(state);
+	const struct intel_plane_state *old_plane_state =
+		intel_atomic_get_old_plane_state(state, plane);
+	const struct intel_plane_state *new_plane_state =
+		intel_atomic_get_new_plane_state(state, plane);
+
+	/*
+	 * If the plane state isn't part of this atomic transaction or during
+	 * initial plane setup, conservatively force a full CFB nuke.
+	 */
+	if (!old_plane_state || !new_plane_state)
+		return true;
+
+	if (old_plane_state->view.color_plane[0].mapping_stride !=
+	    new_plane_state->view.color_plane[0].mapping_stride) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Stride changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->hw.fb->modifier !=
+	    new_plane_state->hw.fb->modifier) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Modifier changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->hw.fb->format != new_plane_state->hw.fb->format) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Pixel format changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->hw.rotation != new_plane_state->hw.rotation) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Rotation changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (skl_plane_aux_dist(old_plane_state, 0) !=
+	    skl_plane_aux_dist(new_plane_state, 0)) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] AUX_DIST changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (!drm_rect_equals(&old_plane_state->uapi.src,
+			     &new_plane_state->uapi.src) ||
+	    !drm_rect_equals(&old_plane_state->uapi.dst,
+			     &new_plane_state->uapi.dst)) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Size/coords changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->hw.alpha != new_plane_state->hw.alpha) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Alpha changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->decrypt != new_plane_state->decrypt) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Decryption changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	/* Includes pixel_blend_mode, color_encoding & color_range checking. */
+	if (old_plane_state->color_ctl != new_plane_state->color_ctl) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Color ctl changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->cus_ctl != new_plane_state->cus_ctl) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] CUS ctl changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	if (old_plane_state->view.color_plane[0].x !=
+	    new_plane_state->view.color_plane[0].x) {
+		drm_dbg_kms(display->drm,
+			    "[PLANE:%d:%s] Color plane 0 x changed in FBC DIRTY RECT\n",
+			    plane->base.base.id, plane->base.name);
+		return true;
+	}
+
+	return false;
+}
+
 static void
-__intel_fbc_prepare_dirty_rect(const struct intel_plane_state *plane_state,
+__intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state,
+			       const struct intel_plane_state *plane_state,
 			       const struct intel_crtc_state *crtc_state)
 {
 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
@@ -1538,7 +1654,10 @@ __intel_fbc_prepare_dirty_rect(const struct intel_plane_state *plane_state,
 		return;
 	}
 
-	if (drm_rect_visible(damage)) {
+	if (intel_fbc_dirty_rect_needs_nuke(state, plane)) {
+		/* compress the entire region due to non PLANE_SURF updating. */
+		*fbc_dirty_rect = DRM_RECT_INIT(0, y_offset, width, height);
+	} else if (drm_rect_visible(damage)) {
 		int y1, y2;
 
 		if (plane_state->hw.rotation & DRM_MODE_ROTATE_180) {
@@ -1598,8 +1717,7 @@ intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state,
 		mutex_lock(&fbc->lock);
 
 		if (fbc->state.plane == plane)
-			__intel_fbc_prepare_dirty_rect(plane_state,
-						       crtc_state);
+			__intel_fbc_prepare_dirty_rect(state, plane_state, crtc_state);
 
 		mutex_unlock(&fbc->lock);
 	}
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.