[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