This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 249df8c1d9f video/fb: guarantee fb read-write integrity to prevent 
display tearing
249df8c1d9f is described below

commit 249df8c1d9f4942b7105344ccd01d051bd7b3957
Author: zhanxiaoqi <[email protected]>
AuthorDate: Wed Apr 15 10:54:52 2026 +0800

    video/fb: guarantee fb read-write integrity to prevent display tearing
    
    Serialization has been added to the paths of fb_read/fb_write, as well as
    partial reading of plane/video information, updatearea, pandisplay, etc.
    This covers the scenario where "one thread draws/switches via the character
    device interface while another thread reads the framebuffer via the
    character device interface", ensuring that the read framebuffer data
    is complete and preventing screen tearing.
    
    Signed-off-by: zhanxiaoqi <[email protected]>
---
 drivers/video/fb.c | 45 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 1f7e15d6e8d..881a7b1d94d 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -47,6 +47,7 @@
 #include <nuttx/circbuf.h>
 #include <nuttx/sched_note.h>
 
+#include <nuttx/mutex.h>
 #ifdef CONFIG_VIDEO_FB_SPLASHSCREEN
 #  include <nuttx/signal.h>
 #endif
@@ -115,8 +116,9 @@ struct fb_chardev_s
   uint8_t                  plane;          /* Video plan number              */
   clock_t                  vsyncoffset;    /* VSync offset ticks             */
   FAR struct fb_priv_s    *head;
-  FAR struct fb_paninfo_s *paninfo;       /* Pan info array                  */
-  size_t                   paninfo_count; /* Pan info count                  */
+  FAR struct fb_paninfo_s *paninfo;        /* Pan info array                 */
+  size_t                   paninfo_count;  /* Pan info count                 */
+  mutex_t                  lock;           /* Framebuffer device lock        */
 };
 
 struct fb_panelinfo_s
@@ -248,7 +250,9 @@ static int fb_splashscreen(FAR struct fb_videoinfo_s *vinfo,
   FAR uint8_t                      *dst;
   unsigned int                      row;
   unsigned int                      nrun;
+  unsigned int                      width;
   FAR fb_pixel_t                    *buf;
+  FAR fb_pixel_t                    *bufp;
   FAR fb_pixel_t                    colour;
   int                               ret = OK;
 
@@ -293,8 +297,7 @@ static int fb_splashscreen(FAR struct fb_videoinfo_s *vinfo,
 
   for (row = 0; row < g_splscr.height; row++)
     {
-      unsigned int width;
-      FAR fb_pixel_t *bufp = buf; /* Start address of the buffer */
+      bufp = buf; /* Start address of the buffer */
 
       /* Process each run-length encoded pixel in the image */
 
@@ -563,10 +566,12 @@ static ssize_t fb_read(FAR struct file *filep, FAR char 
*buffer, size_t len)
 
   /* Get panel info */
 
+  nxmutex_lock(&fb->lock);
   ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
 
   if (ret < 0)
     {
+      nxmutex_unlock(&fb->lock);
       return ret;
     }
 
@@ -575,6 +580,7 @@ static ssize_t fb_read(FAR struct file *filep, FAR char 
*buffer, size_t len)
   start = filep->f_pos;
   if (start >= panelinfo.fblen)
     {
+      nxmutex_unlock(&fb->lock);
       return 0;  /* Return end-of-file */
     }
 
@@ -590,6 +596,7 @@ static ssize_t fb_read(FAR struct file *filep, FAR char 
*buffer, size_t len)
 
   memcpy(buffer, panelinfo.fbmem + start, size);
   filep->f_pos += size;
+  nxmutex_unlock(&fb->lock);
   return size;
 }
 
@@ -621,10 +628,12 @@ static ssize_t fb_write(FAR struct file *filep, FAR const 
char *buffer,
 
   /* Get panel info */
 
+  nxmutex_lock(&fb->lock);
   ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
 
   if (ret < 0)
     {
+      nxmutex_unlock(&fb->lock);
       return ret;
     }
 
@@ -633,6 +642,7 @@ static ssize_t fb_write(FAR struct file *filep, FAR const 
char *buffer,
   start = filep->f_pos;
   if (start >= panelinfo.fblen)
     {
+      nxmutex_unlock(&fb->lock);
       return -EFBIG;  /* Cannot extend the framebuffer */
     }
 
@@ -648,6 +658,7 @@ static ssize_t fb_write(FAR struct file *filep, FAR const 
char *buffer,
 
   memcpy(panelinfo.fbmem + start, buffer, size);
   filep->f_pos += size;
+  nxmutex_unlock(&fb->lock);
   return size;
 }
 
@@ -775,7 +786,9 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
               break;
             }
 
+          nxmutex_lock(&fb->lock);
           ret = fb->vtable->getvideoinfo(fb->vtable, vinfo);
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
@@ -785,7 +798,9 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
             (FAR struct fb_planeinfo_s *)((uintptr_t)arg);
 
           DEBUGASSERT(pinfo != NULL);
+          nxmutex_lock(&fb->lock);
           ret = fb_get_planeinfo(fb, pinfo, pinfo->display);
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
@@ -867,7 +882,9 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
               break;
             }
 
+          nxmutex_lock(&fb->lock);
           ret = fb->vtable->updatearea(fb->vtable, area);
+          nxmutex_unlock(&fb->lock);
         }
         break;
 #endif
@@ -1144,16 +1161,19 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
 
           memcpy(&paninfo, pinfo, sizeof(*pinfo));
 
+          nxmutex_lock(&fb->lock);
           if (fb->vtable->pandisplay != NULL)
             {
               ret = fb->vtable->pandisplay(fb->vtable, pinfo);
               if (ret < 0)
                 {
+                  nxmutex_unlock(&fb->lock);
                   break;
                 }
             }
 
           ret = fb_add_paninfo(fb, &paninfo, FB_NO_OVERLAY);
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
@@ -1183,15 +1203,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
               break;
             }
 
+          nxmutex_lock(&fb->lock);
           ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
           if (ret < 0)
             {
+              nxmutex_unlock(&fb->lock);
               break;
             }
 
           ret = fb_get_planeinfo(fb, &pinfo, 0);
           if (ret < 0)
             {
+              nxmutex_unlock(&fb->lock);
               break;
             }
 
@@ -1263,6 +1286,8 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
                 varinfo->transp.length = 8;
                 break;
           }
+
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
@@ -1280,15 +1305,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
               break;
             }
 
+          nxmutex_lock(&fb->lock);
           ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
           if (ret < 0)
             {
+              nxmutex_unlock(&fb->lock);
               break;
             }
 
           ret = fb_get_planeinfo(fb, &pinfo, 0);
           if (ret < 0)
             {
+              nxmutex_unlock(&fb->lock);
               break;
             }
 
@@ -1305,12 +1333,15 @@ static int fb_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
           fixinfo->visual      = FB_ISMONO(vinfo.fmt) ?
                                  FB_VISUAL_MONO10 : FB_VISUAL_TRUECOLOR;
           fixinfo->line_length = pinfo.stride;
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
       case FBIOGET_PANINFOCNT:
         {
+          nxmutex_lock(&fb->lock);
           ret = fb_paninfo_count(fb->vtable, (int)arg);
+          nxmutex_unlock(&fb->lock);
         }
         break;
 
@@ -1364,10 +1395,12 @@ static int fb_mmap(FAR struct file *filep, FAR struct 
mm_map_entry_s *map)
 
   /* Get panel info */
 
+  nxmutex_lock(&fb->lock);
   ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
 
   if (ret < 0)
     {
+      nxmutex_unlock(&fb->lock);
       return ret;
     }
 
@@ -1385,9 +1418,11 @@ static int fb_mmap(FAR struct file *filep, FAR struct 
mm_map_entry_s *map)
 #else
       map->vaddr = (FAR char *)panelinfo.fbmem + map->offset;
 #endif
+      nxmutex_unlock(&fb->lock);
       return OK;
     }
 
+  nxmutex_unlock(&fb->lock);
   return -EINVAL;
 }
 
@@ -1918,6 +1953,7 @@ int fb_register_device(int display, int plane,
   DEBUGASSERT(vtable != NULL);
   fb->plane  = plane;
   fb->vtable = vtable;
+  nxmutex_init(&fb->lock);
 
   /* Initialize the frame buffer instance. */
 
@@ -2030,6 +2066,7 @@ errout_with_paninfo:
 
   kmm_free(fb->paninfo);
 errout_with_fb:
+  nxmutex_destroy(&fb->lock);
   kmm_free(fb);
   return ret;
 }

Reply via email to