drm: Add helper iterator functions for plane fb_damage_clips blob
authorDeepak Rawat <drawat@vmware.com>
Wed, 30 May 2018 21:42:52 +0000 (14:42 -0700)
committerThomas Hellstrom <thellstrom@vmware.com>
Wed, 5 Dec 2018 09:00:36 +0000 (10:00 +0100)
With fb_damage_clips blob property in drm_plane_state, this patch adds
helper iterator to traverse the damage clips that lie inside plane src.
Iterator will return full plane src as damage in case need full plane
update or damage is not specified.

v2:
- Plane src clipping correction
- Handle no plane update case in iter_next

Signed-off-by: Deepak Rawat <drawat@vmware.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
drivers/gpu/drm/drm_damage_helper.c
include/drm/drm_damage_helper.h
include/drm/drm_plane.h

index d04937556bc780aa374dfd37837d4acbcf9c2f7e..f339b1481750f66f45f54c59bdde49b293c3a2dd 100644 (file)
@@ -65,6 +65,9 @@
  *
  * Drivers that are interested in damage interface for plane should enable
  * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
+ * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
+ * drm_atomic_helper_damage_iter_next() helper iterator function to get damage
+ * rectangles clipped to &drm_plane_state.src.
  */
 
 /**
@@ -116,3 +119,90 @@ void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
        }
 }
 EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
+
+/**
+ * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
+ * @iter: The iterator to initialize.
+ * @old_state: Old plane state for validation.
+ * @new_state: Plane state from which to iterate the damage clips.
+ *
+ * Initialize an iterator, which clips plane damage
+ * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
+ * returns full plane src in case damage is not present because either
+ * user-space didn't sent or driver discarded it (it want to do full plane
+ * update). Currently this iterator returns full plane src in case plane src
+ * changed but that can be changed in future to return damage.
+ *
+ * For the case when plane is not visible or plane update should not happen the
+ * first call to iter_next will return false. Note that this helper use clipped
+ * &drm_plane_state.src, so driver calling this helper should have called
+ * drm_atomic_helper_check_plane_state() earlier.
+ */
+void
+drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
+                                  const struct drm_plane_state *old_state,
+                                  const struct drm_plane_state *state)
+{
+       memset(iter, 0, sizeof(*iter));
+
+       if (!state || !state->crtc || !state->fb || !state->visible)
+               return;
+
+       iter->clips = drm_helper_get_plane_damage_clips(state);
+       iter->num_clips = drm_plane_get_damage_clips_count(state);
+
+       /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
+       iter->plane_src.x1 = state->src.x1 >> 16;
+       iter->plane_src.y1 = state->src.y1 >> 16;
+       iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
+       iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
+
+       if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
+               iter->clips = 0;
+               iter->num_clips = 0;
+               iter->full_update = true;
+       }
+}
+EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
+
+/**
+ * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
+ * @iter: The iterator to advance.
+ * @rect: Return a rectangle in fb coordinate clipped to plane src.
+ *
+ * Since plane src is in 16.16 fixed point and damage clips are whole number,
+ * this iterator round off clips that intersect with plane src. Round down for
+ * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
+ * off for full plane src, in case it's returned as damage. This iterator will
+ * skip damage clips outside of plane src.
+ *
+ * Return: True if the output is valid, false if reached the end.
+ *
+ * If the first call to iterator next returns false then it means no need to
+ * update the plane.
+ */
+bool
+drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
+                                  struct drm_rect *rect)
+{
+       bool ret = false;
+
+       if (iter->full_update) {
+               *rect = iter->plane_src;
+               iter->full_update = false;
+               return true;
+       }
+
+       while (iter->curr_clip < iter->num_clips) {
+               *rect = iter->clips[iter->curr_clip];
+               iter->curr_clip++;
+
+               if (drm_rect_intersect(rect, &iter->plane_src)) {
+                       ret = true;
+                       break;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
index 59584cbf3d408d31dbddc44c8f79ade605f482e4..b9a0d05fb09364712898882b8e3513f9356588f9 100644 (file)
 
 #include <drm/drm_atomic_helper.h>
 
+/**
+ * drm_atomic_for_each_plane_damage - Iterator macro for plane damage.
+ * @iter: The iterator to advance.
+ * @rect: Return a rectangle in fb coordinate clipped to plane src.
+ *
+ * Note that if the first call to iterator macro return false then no need to do
+ * plane update. Iterator will return full plane src when damage is not passed
+ * by user-space.
+ */
+#define drm_atomic_for_each_plane_damage(iter, rect) \
+       while (drm_atomic_helper_damage_iter_next(iter, rect))
+
+/**
+ * struct drm_atomic_helper_damage_iter - Closure structure for damage iterator.
+ *
+ * This structure tracks state needed to walk the list of plane damage clips.
+ */
+struct drm_atomic_helper_damage_iter {
+       /* private: Plane src in whole number. */
+       struct drm_rect plane_src;
+       /* private: Rectangles in plane damage blob. */
+       const struct drm_rect *clips;
+       /* private: Number of rectangles in plane damage blob. */
+       uint32_t num_clips;
+       /* private: Current clip iterator is advancing on. */
+       uint32_t curr_clip;
+       /* private: Whether need full plane update. */
+       bool full_update;
+};
+
 void drm_plane_enable_fb_damage_clips(struct drm_plane *plane);
 void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
                                          struct drm_plane_state *plane_state);
+void
+drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
+                                  const struct drm_plane_state *old_state,
+                                  const struct drm_plane_state *new_state);
+bool
+drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
+                                  struct drm_rect *rect);
+
+/**
+ * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect.
+ * @state: Plane state.
+ *
+ * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect
+ * can be obtained by simply typecasting &drm_mode_rect. This is because both
+ * are signed 32 and during drm_atomic_check_only() it is verified that damage
+ * clips are inside fb.
+ *
+ * Return: Clips in plane fb_damage_clips blob property.
+ */
+static inline struct drm_rect *
+drm_helper_get_plane_damage_clips(const struct drm_plane_state *state)
+{
+       return (struct drm_rect *)drm_plane_get_damage_clips(state);
+}
 
 #endif
index 87153ecb5f1fbaebf6bffc7c9ee65c21661824c8..6078c700d9ba547c6aba90d83df7bec4fa8bbb7e 100644 (file)
@@ -830,7 +830,9 @@ drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
  * drm_plane_get_damage_clips - Returns damage clips.
  * @state: Plane state.
  *
- * Note that this function returns uapi type &drm_mode_rect.
+ * Note that this function returns uapi type &drm_mode_rect. Drivers might
+ * instead be interested in internal &drm_rect which can be obtained by calling
+ * drm_helper_get_plane_damage_clips().
  *
  * Return: Damage clips in plane fb_damage_clips blob property.
  */