mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 14:27:37 +08:00
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 <zhanxiaoqi@bytedance.com>
This commit is contained in:
committed by
Alan C. Assis
parent
3acfea8efc
commit
249df8c1d9
+41
-4
@@ -47,6 +47,7 @@
|
|||||||
#include <nuttx/circbuf.h>
|
#include <nuttx/circbuf.h>
|
||||||
#include <nuttx/sched_note.h>
|
#include <nuttx/sched_note.h>
|
||||||
|
|
||||||
|
#include <nuttx/mutex.h>
|
||||||
#ifdef CONFIG_VIDEO_FB_SPLASHSCREEN
|
#ifdef CONFIG_VIDEO_FB_SPLASHSCREEN
|
||||||
# include <nuttx/signal.h>
|
# include <nuttx/signal.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -115,8 +116,9 @@ struct fb_chardev_s
|
|||||||
uint8_t plane; /* Video plan number */
|
uint8_t plane; /* Video plan number */
|
||||||
clock_t vsyncoffset; /* VSync offset ticks */
|
clock_t vsyncoffset; /* VSync offset ticks */
|
||||||
FAR struct fb_priv_s *head;
|
FAR struct fb_priv_s *head;
|
||||||
FAR struct fb_paninfo_s *paninfo; /* Pan info array */
|
FAR struct fb_paninfo_s *paninfo; /* Pan info array */
|
||||||
size_t paninfo_count; /* Pan info count */
|
size_t paninfo_count; /* Pan info count */
|
||||||
|
mutex_t lock; /* Framebuffer device lock */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fb_panelinfo_s
|
struct fb_panelinfo_s
|
||||||
@@ -248,7 +250,9 @@ static int fb_splashscreen(FAR struct fb_videoinfo_s *vinfo,
|
|||||||
FAR uint8_t *dst;
|
FAR uint8_t *dst;
|
||||||
unsigned int row;
|
unsigned int row;
|
||||||
unsigned int nrun;
|
unsigned int nrun;
|
||||||
|
unsigned int width;
|
||||||
FAR fb_pixel_t *buf;
|
FAR fb_pixel_t *buf;
|
||||||
|
FAR fb_pixel_t *bufp;
|
||||||
FAR fb_pixel_t colour;
|
FAR fb_pixel_t colour;
|
||||||
int ret = OK;
|
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++)
|
for (row = 0; row < g_splscr.height; row++)
|
||||||
{
|
{
|
||||||
unsigned int width;
|
bufp = buf; /* Start address of the buffer */
|
||||||
FAR fb_pixel_t *bufp = buf; /* Start address of the buffer */
|
|
||||||
|
|
||||||
/* Process each run-length encoded pixel in the image */
|
/* 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 */
|
/* Get panel info */
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return ret;
|
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;
|
start = filep->f_pos;
|
||||||
if (start >= panelinfo.fblen)
|
if (start >= panelinfo.fblen)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return 0; /* Return end-of-file */
|
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);
|
memcpy(buffer, panelinfo.fbmem + start, size);
|
||||||
filep->f_pos += size;
|
filep->f_pos += size;
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,10 +628,12 @@ static ssize_t fb_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
|
|
||||||
/* Get panel info */
|
/* Get panel info */
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,6 +642,7 @@ static ssize_t fb_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
start = filep->f_pos;
|
start = filep->f_pos;
|
||||||
if (start >= panelinfo.fblen)
|
if (start >= panelinfo.fblen)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return -EFBIG; /* Cannot extend the framebuffer */
|
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);
|
memcpy(panelinfo.fbmem + start, buffer, size);
|
||||||
filep->f_pos += size;
|
filep->f_pos += size;
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -775,7 +786,9 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb->vtable->getvideoinfo(fb->vtable, vinfo);
|
ret = fb->vtable->getvideoinfo(fb->vtable, vinfo);
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
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);
|
(FAR struct fb_planeinfo_s *)((uintptr_t)arg);
|
||||||
|
|
||||||
DEBUGASSERT(pinfo != NULL);
|
DEBUGASSERT(pinfo != NULL);
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb_get_planeinfo(fb, pinfo, pinfo->display);
|
ret = fb_get_planeinfo(fb, pinfo, pinfo->display);
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -867,7 +882,9 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb->vtable->updatearea(fb->vtable, area);
|
ret = fb->vtable->updatearea(fb->vtable, area);
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -1144,16 +1161,19 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
memcpy(&paninfo, pinfo, sizeof(*pinfo));
|
memcpy(&paninfo, pinfo, sizeof(*pinfo));
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
if (fb->vtable->pandisplay != NULL)
|
if (fb->vtable->pandisplay != NULL)
|
||||||
{
|
{
|
||||||
ret = fb->vtable->pandisplay(fb->vtable, pinfo);
|
ret = fb->vtable->pandisplay(fb->vtable, pinfo);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fb_add_paninfo(fb, &paninfo, FB_NO_OVERLAY);
|
ret = fb_add_paninfo(fb, &paninfo, FB_NO_OVERLAY);
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1183,15 +1203,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
|
ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fb_get_planeinfo(fb, &pinfo, 0);
|
ret = fb_get_planeinfo(fb, &pinfo, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1263,6 +1286,8 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
varinfo->transp.length = 8;
|
varinfo->transp.length = 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1280,15 +1305,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
|
ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fb_get_planeinfo(fb, &pinfo, 0);
|
ret = fb_get_planeinfo(fb, &pinfo, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1305,12 +1333,15 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
fixinfo->visual = FB_ISMONO(vinfo.fmt) ?
|
fixinfo->visual = FB_ISMONO(vinfo.fmt) ?
|
||||||
FB_VISUAL_MONO10 : FB_VISUAL_TRUECOLOR;
|
FB_VISUAL_MONO10 : FB_VISUAL_TRUECOLOR;
|
||||||
fixinfo->line_length = pinfo.stride;
|
fixinfo->line_length = pinfo.stride;
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FBIOGET_PANINFOCNT:
|
case FBIOGET_PANINFOCNT:
|
||||||
{
|
{
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb_paninfo_count(fb->vtable, (int)arg);
|
ret = fb_paninfo_count(fb->vtable, (int)arg);
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1364,10 +1395,12 @@ static int fb_mmap(FAR struct file *filep, FAR struct mm_map_entry_s *map)
|
|||||||
|
|
||||||
/* Get panel info */
|
/* Get panel info */
|
||||||
|
|
||||||
|
nxmutex_lock(&fb->lock);
|
||||||
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1385,9 +1418,11 @@ static int fb_mmap(FAR struct file *filep, FAR struct mm_map_entry_s *map)
|
|||||||
#else
|
#else
|
||||||
map->vaddr = (FAR char *)panelinfo.fbmem + map->offset;
|
map->vaddr = (FAR char *)panelinfo.fbmem + map->offset;
|
||||||
#endif
|
#endif
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxmutex_unlock(&fb->lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1918,6 +1953,7 @@ int fb_register_device(int display, int plane,
|
|||||||
DEBUGASSERT(vtable != NULL);
|
DEBUGASSERT(vtable != NULL);
|
||||||
fb->plane = plane;
|
fb->plane = plane;
|
||||||
fb->vtable = vtable;
|
fb->vtable = vtable;
|
||||||
|
nxmutex_init(&fb->lock);
|
||||||
|
|
||||||
/* Initialize the frame buffer instance. */
|
/* Initialize the frame buffer instance. */
|
||||||
|
|
||||||
@@ -2030,6 +2066,7 @@ errout_with_paninfo:
|
|||||||
|
|
||||||
kmm_free(fb->paninfo);
|
kmm_free(fb->paninfo);
|
||||||
errout_with_fb:
|
errout_with_fb:
|
||||||
|
nxmutex_destroy(&fb->lock);
|
||||||
kmm_free(fb);
|
kmm_free(fb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user