dm: video: Add damage tracking API
authorAlexander Graf <agraf@csgraf.de>
Thu, 9 Jun 2022 22:59:15 +0000 (00:59 +0200)
committerSimon Glass <sjg@chromium.org>
Thu, 1 May 2025 10:30:48 +0000 (04:30 -0600)
We are going to introduce image damage tracking to fasten up screen
refresh on large displays. This patch adds damage tracking for up to
one rectangle of the screen which is typically enough to hold blt or
text print updates. Callers into this API and a reduced dcache flush
code path will follow in later patches.

Signed-off-by: Alexander Graf <agraf@csgraf.de>
Reported-by: Da Xue <da@libre.computer>
[Alper: Use xstart/yend, document new fields, return void from
        video_damage(), declare priv, drop headers, use IS_ENABLED()]
Co-developed-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Link: https://lore.kernel.org/u-boot/20230821135111.3558478-5-alpernebiyasak@gmail.com/
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/video/Kconfig
drivers/video/video-uclass.c
include/video.h

index 7335394..bc9c7c1 100644 (file)
@@ -98,6 +98,19 @@ config VIDEO_COPY
          To use this, your video driver must set @copy_base in
          struct video_uc_plat.
 
+config VIDEO_DAMAGE
+       bool "Enable damage tracking of frame buffer regions"
+       help
+         On some machines (most ARM), the display frame buffer resides in
+         RAM. To make the display controller pick up screen updates, we
+         have to flush frame buffer contents from CPU caches into RAM which
+         can be a slow operation.
+
+         This feature adds damage tracking to collect information about regions
+         that received updates. When we want to sync, we then only flush
+         regions of the frame buffer that were modified before, speeding up
+         screen refreshes significantly.
+
 config BACKLIGHT_PWM
        bool "Generic PWM based Backlight Driver"
        depends on BACKLIGHT && DM_PWM
index c684c99..8e2edd7 100644 (file)
@@ -369,6 +369,34 @@ void video_set_default_colors(struct udevice *dev, bool invert)
        priv->colour_bg = video_index_to_colour(priv, back);
 }
 
+/* Notify about changes in the frame buffer */
+#ifdef CONFIG_VIDEO_DAMAGE
+void video_damage(struct udevice *vid, int x, int y, int width, int height)
+{
+       struct video_priv *priv = dev_get_uclass_priv(vid);
+       int xend = x + width;
+       int yend = y + height;
+
+       if (x > priv->xsize)
+               return;
+
+       if (y > priv->ysize)
+               return;
+
+       if (xend > priv->xsize)
+               xend = priv->xsize;
+
+       if (yend > priv->ysize)
+               yend = priv->ysize;
+
+       /* Span a rectangle across all old and new damage */
+       priv->damage.xstart = min(x, priv->damage.xstart);
+       priv->damage.ystart = min(y, priv->damage.ystart);
+       priv->damage.xend = max(xend, priv->damage.xend);
+       priv->damage.yend = max(yend, priv->damage.yend);
+}
+#endif
+
 /* Flush video activity to the caches */
 int video_sync(struct udevice *vid, bool force)
 {
@@ -402,6 +430,13 @@ int video_sync(struct udevice *vid, bool force)
 #endif
        priv->last_sync = get_timer(0);
 
+       if (IS_ENABLED(CONFIG_VIDEO_DAMAGE)) {
+               priv->damage.xstart = priv->xsize;
+               priv->damage.ystart = priv->ysize;
+               priv->damage.xend = 0;
+               priv->damage.yend = 0;
+       }
+
        return 0;
 }
 
index a1f7fd7..7eed112 100644 (file)
@@ -85,6 +85,11 @@ enum video_format {
  * @fb_size:   Frame buffer size
  * @copy_fb:   Copy of the frame buffer to keep up to date; see struct
  *             video_uc_plat
+ * @damage:    A bounding box of framebuffer regions updated since last sync
+ * @damage.xstart:     X start position in pixels from the left
+ * @damage.ystart:     Y start position in pixels from the top
+ * @damage.xend:       X end position in pixels from the left
+ * @damage.xend:       Y end position in pixels from the top
  * @line_length:       Length of each frame buffer line, in bytes. This can be
  *             set by the driver, but if not, the uclass will set it after
  *             probing
@@ -113,6 +118,12 @@ struct video_priv {
        void *fb;
        int fb_size;
        void *copy_fb;
+       struct {
+               int xstart;
+               int ystart;
+               int xend;
+               int yend;
+       } damage;
        int line_length;
        u32 colour_fg;
        u32 colour_bg;
@@ -259,8 +270,9 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
  * @return: 0 on success, error code otherwise
  *
  * Some frame buffers are cached or have a secondary frame buffer. This
- * function syncs these up so that the current contents of the U-Boot frame
- * buffer are displayed to the user.
+ * function syncs the damaged parts of them up so that the current contents
+ * of the U-Boot frame buffer are displayed to the user. It clears the damage
+ * buffer.
  */
 int video_sync(struct udevice *vid, bool force);
 
@@ -380,6 +392,30 @@ static inline int video_sync_copy_all(struct udevice *dev)
 
 #endif
 
+#ifdef CONFIG_VIDEO_DAMAGE
+/**
+ * video_damage() - Notify the video subsystem about screen updates.
+ *
+ * @vid:       Device to sync
+ * @x:         Upper left X coordinate of the damaged rectangle
+ * @y:         Upper left Y coordinate of the damaged rectangle
+ * @width:     Width of the damaged rectangle
+ * @height:    Height of the damaged rectangle
+ *
+ * Some frame buffers are cached or have a secondary frame buffer. This
+ * function notifies the video subsystem about rectangles that were updated
+ * within the frame buffer. They may only get written to the screen on the
+ * next call to video_sync().
+ */
+void video_damage(struct udevice *vid, int x, int y, int width, int height);
+#else
+static inline void video_damage(struct udevice *vid, int x, int y, int width,
+                               int height)
+{
+       return;
+}
+#endif /* CONFIG_VIDEO_DAMAGE */
+
 /**
  * video_is_active() - Test if one video device it active
  *