[PATCH 2/5] drm/damage-helper: Decouple partial plane updates from damage clipping

Thomas Zimmermann tzimmermann at suse.de
Tue Sep 20 13:56:16 UTC 2022


Introduce a distinct flag fb_damage_partial_update in plane state to
signal the option for a partial plane update. Replaces the semantics
of having no damaged areas to trigger a full update. Decoupling the
existence of damage clipping from partial plane updates will allow to
sometimes avoid plane updates at all.

By default the new flag is cleared, which triggers a full update. We
also keep doing a full update on modesetting operations or if the
framebuffer has been moved within the plane. Installing damage clipping
areas on a plane state sets the new flag and triggers a partial update
of the given areas.

Userspace that does not support damage clipping continues to work as
before.

Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
---
 drivers/gpu/drm/drm_atomic_state_helper.c |  1 +
 drivers/gpu/drm/drm_damage_helper.c       | 68 ++++++++++++++++-------
 include/drm/drm_plane.h                   |  9 +++
 3 files changed, 59 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index bf31b9d92094..85b13c221bd8 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -338,6 +338,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
 	state->fence = NULL;
 	state->commit = NULL;
 	state->fb_damage_clips = NULL;
+	state->fb_damage_partial_update = false;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
 
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index 4b1f26ef119f..16f0d5a97ee3 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -55,30 +55,48 @@ static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
  * @state: The driver state object.
  * @new_plane_state: Plane state for which to verify damage.
  *
- * This helper function makes sure that damage from plane state is discarded
- * for full modeset. If there are more reasons a driver would want to do a full
- * plane update rather than processing individual damage regions, then those
- * cases should be taken care of here.
+ * This helper function makes sure that damage from plane state is set up
+ * for full plane updates if necessary. This happens for full modesets on the
+ * plane's CRTC, and for pageflips without damage. If there are more reasons
+ * a driver would want to do a full plane update rather than processing
+ * individual damage regions, then those cases should be taken care of here.
  *
- * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
- * full plane update should happen. It also ensure helper iterator will return
- * &drm_plane_state.src as damage.
+ * Note that &drm_plane_state.fb_damage_partial_update == false in plane state
+ * means that a full plane update should happen. It also ensures the helper
+ * iterator will return &drm_plane_state.src as damage.
  */
 void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
 					  struct drm_plane_state *new_plane_state)
 {
 	struct drm_crtc_state *new_crtc_state;
+	struct drm_crtc *new_crtc = new_plane_state->crtc;
+	bool partial_update = false;
 
-	if (new_plane_state->crtc) {
-		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
+	if (new_crtc) {
+		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
 
 		if (WARN_ON(!new_crtc_state))
-			return;
+			goto out;
 
-		if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
-			drm_property_blob_put(new_plane_state->fb_damage_clips);
-			new_plane_state->fb_damage_clips = NULL;
-		}
+		/*
+		 * The plane's CRTC does a modeset; always do full update.
+		 */
+		if (drm_atomic_crtc_needs_modeset(new_crtc_state))
+			goto out;
+	}
+
+	/*
+	 * Damage clips are a good indicator for partial updates.
+	 */
+	if (new_plane_state->fb_damage_clips)
+		partial_update = true;
+
+out:
+	new_plane_state->fb_damage_partial_update = partial_update;
+
+	if (!new_plane_state->fb_damage_partial_update) {
+		drm_property_blob_put(new_plane_state->fb_damage_clips);
+		new_plane_state->fb_damage_clips = NULL;
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
@@ -224,13 +242,24 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
 				   const struct drm_plane_state *state)
 {
 	struct drm_rect src;
+	bool partial_update;
+
 	memset(iter, 0, sizeof(*iter));
 
 	if (!state || !state->crtc || !state->fb || !state->visible)
 		return;
 
-	iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
-	iter->num_clips = drm_plane_get_damage_clips_count(state);
+	partial_update = state->fb_damage_partial_update;
+
+	/*
+	 * Only allow a partial update if the framebuffer did not move
+	 * within the plane. Otherwise do a full update. We have to test
+	 * this here, instead of drm_atomic_helper_check_plane_damage(),
+	 * as the plane's atomic_check helper could meanwhile have changed
+	 * the source coordinates.
+	 */
+	if (partial_update)
+		partial_update = drm_rect_equals(&state->src, &old_state->src);
 
 	/* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
 	src = drm_plane_state_src(state);
@@ -240,9 +269,10 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
 	iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF);
 	iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF);
 
-	if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
-		iter->clips = NULL;
-		iter->num_clips = 0;
+	if (partial_update) {
+		iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
+		iter->num_clips = drm_plane_get_damage_clips_count(state);
+	} else {
 		iter->full_update = true;
 	}
 }
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 89ea54652e87..3ba91349d799 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -190,6 +190,15 @@ struct drm_plane_state {
 	 */
 	struct drm_property_blob *fb_damage_clips;
 
+	/**
+	 * @fb_damage_partial_update:
+	 *
+	 * Marks the plane for a partial update. The value of this field
+	 * depends on the supplied atomic state and the operation that
+	 * initiated the update.
+	 */
+	bool fb_damage_partial_update;
+
 	/**
 	 * @src:
 	 *
-- 
2.37.3



More information about the dri-devel mailing list