diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9e97620ea9..4db3f10124 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -50,6 +50,11 @@ config VIDEO_FB bool "Framebuffer character driver" default n +config VIDEO_FB_NPOLLWAITERS + int "Video fb poll count of each layer" + depends on VIDEO_FB + default 2 + config VIDEO_STREAM bool "Video Stream Support" default n diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 532522931c..97515eb00b 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -41,17 +41,30 @@ #include #include #include +#include /**************************************************************************** * Pre-processor definitions ****************************************************************************/ -#define FB_NO_OVERLAY -1 - /**************************************************************************** * Private Types ****************************************************************************/ +struct fb_priv_s +{ + int overlay; /* Overlay number */ +}; + +struct fb_paninfo_s +{ + FAR struct circbuf_s buf; /* Pan buffer queued list */ + + /* Polling fds of waiting threads */ + + FAR struct pollfd *fds[CONFIG_VIDEO_FB_NPOLLWAITERS]; +}; + /* This structure defines one framebuffer device. Note that which is * everything in this structure is constant data set up and initialization * time. Therefore, no there is requirement for serialized access to this @@ -60,23 +73,21 @@ struct fb_chardev_s { - FAR struct fb_vtable_s *vtable; /* Framebuffer interface */ - FAR struct pollfd *fds; /* Polling structure of waiting thread */ - uint8_t plane; /* Video plan number */ - volatile int pollcnt; /* Poll ready count */ - clock_t vsyncoffset; /* VSync offset ticks */ - struct wdog_s wdog; /* VSync offset timer */ -#ifdef CONFIG_FB_OVERLAY - int overlay; /* Overlay number */ -#endif - mutex_t lock; /* Mutual exclusion */ - int16_t crefs; /* Number of open references */ + FAR struct fb_vtable_s *vtable; /* Framebuffer interface */ + uint8_t plane; /* Video plan number */ + clock_t vsyncoffset; /* VSync offset ticks */ + struct wdog_s wdog; /* VSync offset timer */ + mutex_t lock; /* Mutual exclusion */ + int16_t crefs; /* Number of open references */ + FAR struct fb_paninfo_s *paninfo; /* Pan info array */ + size_t paninfo_count; /* Pan info count */ }; struct fb_panelinfo_s { FAR void *fbmem; /* Start of frame buffer memory */ size_t fblen; /* Size of the framebuffer */ + uint8_t fbcount; /* Count of frame buffer */ uint8_t bpp; /* Bits per pixel */ }; @@ -84,6 +95,13 @@ struct fb_panelinfo_s * Private Function Prototypes ****************************************************************************/ +static FAR struct pollfd **fb_get_free_pollfds(FAR struct fb_chardev_s *fb, + int overlay); +static FAR struct circbuf_s *fb_get_panbuf(FAR struct fb_chardev_s *fb, + int overlay); +static int fb_add_paninfo(FAR struct fb_vtable_s *vtable, + FAR const union fb_paninfo_u *info, + int overlay); static int fb_open(FAR struct file *filep); static int fb_close(FAR struct file *filep); static ssize_t fb_read(FAR struct file *filep, FAR char *buffer, @@ -97,7 +115,8 @@ static int fb_mmap(FAR struct file *filep, static int fb_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static int fb_get_panelinfo(FAR struct fb_chardev_s *fb, - FAR struct fb_panelinfo_s *panelinfo); + FAR struct fb_panelinfo_s *panelinfo, + int overlay); static int fb_get_planeinfo(FAR struct fb_chardev_s *fb, FAR struct fb_planeinfo_s *pinfo, uint8_t display); @@ -123,6 +142,93 @@ static const struct file_operations g_fb_fops = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: fb_get_free_pollfds + ****************************************************************************/ + +static FAR struct pollfd **fb_get_free_pollfds(FAR struct fb_chardev_s *fb, + int overlay) +{ + FAR struct fb_paninfo_s *paninfo; + int id = overlay + 1; + int i; + + DEBUGASSERT(id >= 0 && id < fb->paninfo_count); + + paninfo = &fb->paninfo[id]; + + for (i = 0; i < CONFIG_VIDEO_FB_NPOLLWAITERS; ++i) + { + if (!paninfo->fds[i]) + { + return &paninfo->fds[i]; + } + } + + return NULL; +} + +/**************************************************************************** + * Name: fb_get_panbuf + ****************************************************************************/ + +static FAR struct circbuf_s *fb_get_panbuf(FAR struct fb_chardev_s *fb, + int overlay) +{ + int id = overlay + 1; + + DEBUGASSERT(id >= 0 && id < fb->paninfo_count); + + return &(fb->paninfo[id].buf); +} + +/**************************************************************************** + * Name: fb_add_paninfo + ****************************************************************************/ + +static int fb_add_paninfo(FAR struct fb_vtable_s *vtable, + FAR const union fb_paninfo_u *info, + int overlay) +{ + FAR struct circbuf_s *panbuf; + FAR struct fb_chardev_s *fb; + irqstate_t flags; + ssize_t ret; + + DEBUGASSERT(vtable != NULL); + + /* Prevent calling before getting the vtable. */ + + fb = vtable->priv; + if (fb == NULL) + { + return -EINVAL; + } + + panbuf = fb_get_panbuf(fb, overlay); + if (panbuf == NULL) + { + return -EINVAL; + } + + /* Disable the interrupt when writing to the queue to + * prevent it from being modified by the interrupted + * thread during the writing process. + */ + + flags = enter_critical_section(); + + /* Write planeinfo information to the queue. */ + + ret = circbuf_write(panbuf, info, sizeof(union fb_paninfo_u)); + DEBUGASSERT(ret == sizeof(union fb_paninfo_u)); + + /* Re-enable interrupts */ + + leave_critical_section(flags); + return ret <= 0 ? -ENOSPC : OK; +} + /**************************************************************************** * Name: fb_open ****************************************************************************/ @@ -131,6 +237,7 @@ static int fb_open(FAR struct file *filep) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; int ret; inode = filep->f_inode; @@ -144,20 +251,34 @@ static int fb_open(FAR struct file *filep) return ret; } + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + ret = -ENOMEM; + goto err_out; + } + if (fb->crefs == 0) { - if (fb->vtable->open != NULL) + if (fb->vtable->open != NULL && + (ret = fb->vtable->open(fb->vtable)) < 0) { - ret = fb->vtable->open(fb->vtable); + goto err_fb; } } - if (ret >= 0) - { - fb->crefs++; - DEBUGASSERT(fb->crefs > 0); - } + fb->crefs++; + DEBUGASSERT(fb->crefs > 0); + priv->overlay = FB_NO_OVERLAY; + filep->f_priv = priv; + + nxmutex_unlock(&fb->lock); + return 0; + +err_fb: + kmm_free(priv); +err_out: nxmutex_unlock(&fb->lock); return ret; } @@ -170,12 +291,14 @@ static int fb_close(FAR struct file *filep) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; int ret; inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; - DEBUGASSERT(fb->vtable != NULL); + DEBUGASSERT(fb->vtable != NULL && priv != NULL); ret = nxmutex_lock(&fb->lock); if (ret < 0) @@ -195,6 +318,7 @@ static int fb_close(FAR struct file *filep) { DEBUGASSERT(fb->crefs > 0); fb->crefs--; + kmm_free(priv); } nxmutex_unlock(&fb->lock); @@ -209,6 +333,7 @@ static ssize_t fb_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; struct fb_panelinfo_s panelinfo; size_t start; size_t end; @@ -221,10 +346,13 @@ static ssize_t fb_read(FAR struct file *filep, FAR char *buffer, size_t len) inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; + + DEBUGASSERT(fb->vtable != NULL && priv != NULL); /* Get panel info */ - ret = fb_get_panelinfo(fb, &panelinfo); + ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay); if (ret < 0) { @@ -263,6 +391,7 @@ static ssize_t fb_write(FAR struct file *filep, FAR const char *buffer, { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; struct fb_panelinfo_s panelinfo; size_t start; size_t end; @@ -275,10 +404,13 @@ static ssize_t fb_write(FAR struct file *filep, FAR const char *buffer, inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; + + DEBUGASSERT(fb->vtable != NULL && priv != NULL); /* Get panel info */ - ret = fb_get_panelinfo(fb, &panelinfo); + ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay); if (ret < 0) { @@ -322,6 +454,7 @@ static off_t fb_seek(FAR struct file *filep, off_t offset, int whence) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; struct fb_panelinfo_s panelinfo; off_t newpos; int ret; @@ -332,6 +465,9 @@ static off_t fb_seek(FAR struct file *filep, off_t offset, int whence) inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; + + DEBUGASSERT(fb->vtable != NULL && priv != NULL); /* Determine the new, requested file position */ @@ -349,7 +485,7 @@ static off_t fb_seek(FAR struct file *filep, off_t offset, int whence) /* Get panel info */ - ret = fb_get_panelinfo(fb, &panelinfo); + ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay); if (ret < 0) { @@ -507,14 +643,15 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg) case FBIO_SELECT_OVERLAY: /* Select video overlay */ { struct fb_overlayinfo_s oinfo; + FAR struct fb_priv_s *priv = filep->f_priv; - DEBUGASSERT(fb->vtable != NULL && + DEBUGASSERT(priv != NULL && fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL); memset(&oinfo, 0, sizeof(oinfo)); ret = fb->vtable->getoverlayinfo(fb->vtable, arg, &oinfo); - if (ret == OK) + if (ret >= 0) { - fb->overlay = arg; + priv->overlay = arg; } } break; @@ -625,10 +762,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct fb_overlayinfo_s *oinfo = (FAR struct fb_overlayinfo_s *)((uintptr_t)arg); + union fb_paninfo_u paninfo; - DEBUGASSERT(oinfo != 0 && fb->vtable != NULL && - fb->vtable->panoverlay != NULL); - ret = fb->vtable->panoverlay(fb->vtable, oinfo); + DEBUGASSERT(oinfo != 0 && fb->vtable != NULL); + + memcpy(&paninfo, oinfo, sizeof(*oinfo)); + + if (fb->vtable->panoverlay != NULL) + { + fb->vtable->panoverlay(fb->vtable, oinfo); + } + + ret = fb_add_paninfo(fb->vtable, &paninfo, oinfo->overlay); } break; @@ -676,15 +821,18 @@ static int fb_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct fb_planeinfo_s *pinfo = (FAR struct fb_planeinfo_s *)((uintptr_t)arg); + union fb_paninfo_u paninfo; - DEBUGASSERT(pinfo != NULL && fb->vtable != NULL && - fb->vtable->pandisplay != NULL); - ret = fb->vtable->pandisplay(fb->vtable, pinfo); - fb->pollcnt--; + DEBUGASSERT(pinfo != NULL && fb->vtable != NULL); - /* Check pan display overrun. */ + memcpy(&paninfo, pinfo, sizeof(*pinfo)); - DEBUGASSERT(fb->pollcnt >= 0); + if (fb->vtable->pandisplay != NULL) + { + fb->vtable->pandisplay(fb->vtable, pinfo); + } + + ret = fb_add_paninfo(fb->vtable, &paninfo, FB_NO_OVERLAY); } break; @@ -844,6 +992,7 @@ static int fb_mmap(FAR struct file *filep, FAR struct mm_map_entry_s *map) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; struct fb_panelinfo_s panelinfo; int ret; @@ -851,10 +1000,13 @@ static int fb_mmap(FAR struct file *filep, FAR struct mm_map_entry_s *map) inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; + + DEBUGASSERT(fb->vtable != NULL && priv != NULL); /* Get panel info */ - ret = fb_get_panelinfo(fb, &panelinfo); + ret = fb_get_panelinfo(fb, &panelinfo, priv->overlay); if (ret < 0) { @@ -885,36 +1037,52 @@ static int fb_poll(FAR struct file *filep, struct pollfd *fds, bool setup) { FAR struct inode *inode; FAR struct fb_chardev_s *fb; + FAR struct fb_priv_s *priv; + FAR struct circbuf_s *panbuf; + FAR struct pollfd **pollfds; + irqstate_t flags; + int ret = OK; /* Get the framebuffer instance */ inode = filep->f_inode; fb = inode->i_private; + priv = filep->f_priv; + + DEBUGASSERT(fb->vtable != NULL && priv != NULL); + + flags = enter_critical_section(); if (setup) { - if (fb->fds == NULL) + pollfds = fb_get_free_pollfds(fb, priv->overlay); + if (pollfds == NULL) { - fb->fds = fds; - fds->priv = &fb->fds; - } - else - { - return -EBUSY; + ret = -EBUSY; + goto errout; } - if (fb->pollcnt > 0) + *pollfds = fds; + fds->priv = pollfds; + + panbuf = fb_get_panbuf(fb, priv->overlay); + if (!circbuf_is_full(panbuf)) { - poll_notify(&fb->fds, 1, POLLOUT); + poll_notify(pollfds, 1, POLLOUT); } } - else if (fds->priv) + else if (fds->priv != NULL) { - fb->fds = NULL; + /* This is a request to tear down the poll. */ + + FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv; + *slot = NULL; fds->priv = NULL; } - return OK; +errout: + leave_critical_section(flags); + return ret; } /**************************************************************************** @@ -922,18 +1090,20 @@ static int fb_poll(FAR struct file *filep, struct pollfd *fds, bool setup) ****************************************************************************/ static int fb_get_panelinfo(FAR struct fb_chardev_s *fb, - FAR struct fb_panelinfo_s *panelinfo) + FAR struct fb_panelinfo_s *panelinfo, + int overlay) { struct fb_planeinfo_s pinfo; + struct fb_videoinfo_s vinfo; int ret; #ifdef CONFIG_FB_OVERLAY - if (fb->overlay != FB_NO_OVERLAY) + if (overlay != FB_NO_OVERLAY) { struct fb_overlayinfo_s oinfo; DEBUGASSERT(fb->vtable->getoverlayinfo != NULL); memset(&oinfo, 0, sizeof(oinfo)); - ret = fb->vtable->getoverlayinfo(fb->vtable, fb->overlay, &oinfo); + ret = fb->vtable->getoverlayinfo(fb->vtable, overlay, &oinfo); if (ret < 0) { @@ -941,9 +1111,11 @@ static int fb_get_panelinfo(FAR struct fb_chardev_s *fb, return ret; } - panelinfo->fbmem = oinfo.fbmem; - panelinfo->fblen = oinfo.fblen; - panelinfo->bpp = oinfo.bpp; + panelinfo->fbmem = oinfo.fbmem; + panelinfo->fblen = oinfo.fblen; + panelinfo->fbcount = oinfo.yres_virtual == 0 ? + 1 : (oinfo.yres_virtual / oinfo.yres); + panelinfo->bpp = oinfo.bpp; return OK; } #endif @@ -954,9 +1126,18 @@ static int fb_get_panelinfo(FAR struct fb_chardev_s *fb, return ret; } - panelinfo->fbmem = pinfo.fbmem; - panelinfo->fblen = pinfo.fblen; - panelinfo->bpp = pinfo.bpp; + ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo); + if (ret < 0) + { + gerr("ERROR: getvideoinfo() failed: %d\n", ret); + return ret; + } + + panelinfo->fbmem = pinfo.fbmem; + panelinfo->fblen = pinfo.fblen; + panelinfo->fbcount = pinfo.yres_virtual == 0 ? + 1 : (pinfo.yres_virtual / vinfo.yres); + panelinfo->bpp = pinfo.bpp; return OK; } @@ -994,19 +1175,25 @@ static int fb_get_planeinfo(FAR struct fb_chardev_s *fb, static void fb_do_pollnotify(wdparm_t arg) { - FAR struct fb_chardev_s *fb = (FAR struct fb_chardev_s *)arg; + FAR struct fb_paninfo_s *paninfo = (FAR struct fb_paninfo_s *)arg; + irqstate_t flags; + int i; - fb->pollcnt++; + flags = enter_critical_section(); - /* Notify framebuffer is writable. */ + for (i = 0; i < CONFIG_VIDEO_FB_NPOLLWAITERS; i++) + { + if (paninfo->fds[i] != NULL) + { + /* Notify framebuffer is writable. */ - poll_notify(&fb->fds, 1, POLLOUT); + poll_notify(&paninfo->fds[i], 1, POLLOUT); + } + } + + leave_critical_section(flags); } -/**************************************************************************** - * Public Functions - ****************************************************************************/ - /**************************************************************************** * Name: fb_pollnotify * @@ -1018,9 +1205,10 @@ static void fb_do_pollnotify(wdparm_t arg) * ****************************************************************************/ -void fb_pollnotify(FAR struct fb_vtable_s *vtable) +static void fb_pollnotify(FAR struct fb_vtable_s *vtable, int overlay) { FAR struct fb_chardev_s *fb; + int id = overlay + 1; DEBUGASSERT(vtable != NULL); @@ -1033,16 +1221,170 @@ void fb_pollnotify(FAR struct fb_vtable_s *vtable) return; } + DEBUGASSERT(id >= 0 && id < fb->paninfo_count); + if (fb->vsyncoffset > 0) { - wd_start(&fb->wdog, fb->vsyncoffset, fb_do_pollnotify, (wdparm_t)fb); + wd_start(&fb->wdog, fb->vsyncoffset, fb_do_pollnotify, + (wdparm_t)(&fb->paninfo[id])); } else { - fb_do_pollnotify((wdparm_t)fb); + fb_do_pollnotify((wdparm_t)(&fb->paninfo[id])); } } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fb_peek_paninfo + * Description: + * Peek a frame from pan info queue of the specified overlay. + * + * Input Parameters: + * vtable - Pointer to framebuffer's virtual table. + * info - Pointer to pan info. + * overlay - Overlay index. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + ****************************************************************************/ + +int fb_peek_paninfo(FAR struct fb_vtable_s *vtable, + FAR union fb_paninfo_u *info, + int overlay) +{ + FAR struct circbuf_s *panbuf; + FAR struct fb_chardev_s *fb; + irqstate_t flags; + ssize_t ret; + + /* Prevent calling before getting the vtable. */ + + fb = vtable->priv; + if (fb == NULL) + { + return -EINVAL; + } + + panbuf = fb_get_panbuf(fb, overlay); + if (panbuf == NULL) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + /* Attempt to peek a frame from the vsync queue. */ + + ret = circbuf_peek(panbuf, info, sizeof(union fb_paninfo_u)); + DEBUGASSERT(ret <= 0 || ret == sizeof(union fb_paninfo_u)); + + /* Re-enable interrupts */ + + leave_critical_section(flags); + return ret <= 0 ? -ENOSPC : OK; +} + +/**************************************************************************** + * Name: fb_remove_paninfo + * Description: + * Remove a frame from pan info queue of the specified overlay. + * + * Input Parameters: + * vtable - Pointer to framebuffer's virtual table. + * overlay - Overlay index. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + ****************************************************************************/ + +int fb_remove_paninfo(FAR struct fb_vtable_s *vtable, int overlay) +{ + FAR struct circbuf_s *panbuf; + FAR struct fb_chardev_s *fb; + irqstate_t flags; + ssize_t ret; + + fb = vtable->priv; + if (fb == NULL) + { + return -EINVAL; + } + + panbuf = fb_get_panbuf(fb, overlay); + if (panbuf == NULL) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + /* Attempt to take a frame from the pan info. */ + + ret = circbuf_skip(panbuf, sizeof(union fb_paninfo_u)); + DEBUGASSERT(ret <= 0 || ret == sizeof(union fb_paninfo_u)); + + /* Re-enable interrupts */ + + leave_critical_section(flags); + + if (ret == sizeof(union fb_paninfo_u)) + { + fb_pollnotify(vtable, overlay); + } + + return ret <= 0 ? -ENOSPC : OK; +} + +/**************************************************************************** + * Name: fb_paninfo_count + * Description: + * Get pan info count of specified overlay pan info queue. + * + * Input Parameters: + * vtable - Pointer to framebuffer's virtual table. + * overlay - Overlay index. + * + * Returned Value: + * a non-negative value is returned on success; a negated errno value is + * returned on any failure. + ****************************************************************************/ + +int fb_paninfo_count(FAR struct fb_vtable_s *vtable, int overlay) +{ + FAR struct circbuf_s *panbuf; + FAR struct fb_chardev_s *fb; + irqstate_t flags; + ssize_t ret; + + /* Prevent calling before getting the vtable. */ + + fb = vtable->priv; + if (fb == NULL) + { + return -EINVAL; + } + + panbuf = fb_get_panbuf(fb, overlay); + if (panbuf == NULL) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + ret = circbuf_used(panbuf) / sizeof(union fb_paninfo_u); + + leave_critical_section(flags); + + return ret; +} + /**************************************************************************** * Name: fb_register * @@ -1071,13 +1413,10 @@ int fb_register(int display, int plane) FAR struct fb_chardev_s *fb; struct fb_panelinfo_s panelinfo; struct fb_videoinfo_s vinfo; - struct fb_planeinfo_s pinfo; -#ifdef CONFIG_FB_OVERLAY - struct fb_overlayinfo_s oinfo; -#endif char devname[16]; int nplanes; int ret; + size_t i; /* Allocate a framebuffer state instance */ @@ -1087,13 +1426,6 @@ int fb_register(int display, int plane) return -ENOMEM; } -#ifdef CONFIG_FB_OVERLAY - - /* Set the default overlay number */ - - fb->overlay = FB_NO_OVERLAY; -#endif - /* Initialize the frame buffer device. */ ret = up_fbinitialize(display); @@ -1127,57 +1459,38 @@ int fb_register(int display, int plane) nplanes = vinfo.nplanes; DEBUGASSERT(vinfo.nplanes > 0 && (unsigned)plane < vinfo.nplanes); - /* Get plane info */ - - ret = fb_get_planeinfo(fb, &pinfo, 0); - if (ret < 0) - { - goto errout_with_fb; - } - - /* The initial value of pollcnt is the number of virtual framebuffers */ - - if (pinfo.yres_virtual > 0) - { - fb->pollcnt = pinfo.yres_virtual / vinfo.yres; - DEBUGASSERT(fb->pollcnt > 0); - } - else - { - fb->pollcnt = 1; - } - - /* Get panel info */ - - ret = fb_get_panelinfo(fb, &panelinfo); - - if (ret < 0) - { - goto errout_with_fb; - } - - /* Clear the framebuffer memory */ - - memset(panelinfo.fbmem, 0, panelinfo.fblen); - #ifdef CONFIG_FB_OVERLAY - /* Initialize first overlay but do not select */ + fb->paninfo_count = vinfo.noverlays; +#endif - DEBUGASSERT(fb->vtable->getoverlayinfo != NULL); - memset(&oinfo, 0, sizeof(oinfo)); - ret = fb->vtable->getoverlayinfo(fb->vtable, 0, &oinfo); - if (ret < 0) + /* Add the primary framebuffer */ + + fb->paninfo_count += 1; + fb->paninfo = kmm_zalloc(sizeof(struct fb_paninfo_s) * fb->paninfo_count); + + if (fb->paninfo == NULL) { - gerr("ERROR: getoverlayinfo() failed: %d\n", ret); + gerr("ERROR: alloc panbuf failed\n"); goto errout_with_fb; } - /* Clear the overlay memory. Necessary when plane 0 and overlay 0 - * different. - */ + for (i = 0; i < fb->paninfo_count; i++) + { + ret = fb_get_panelinfo(fb, &panelinfo, i - 1); + if (ret < 0) + { + goto errout_with_paninfo; + } - memset(oinfo.fbmem, 0, oinfo.fblen); -#endif + ret = circbuf_init(&(fb->paninfo[i].buf), NULL, panelinfo.fbcount + * sizeof(union fb_paninfo_u)); + + DEBUGASSERT(ret == 0); + + /* Clear the framebuffer memory */ + + memset(panelinfo.fbmem, 0, panelinfo.fblen); + } /* Register the framebuffer device */ @@ -1196,15 +1509,23 @@ int fb_register(int display, int plane) if (ret < 0) { gerr("ERROR: register_driver() failed: %d\n", ret); - goto errout_with_fb; + goto errout_with_nxmutex; } fb->vtable->priv = fb; return OK; -errout_with_fb: +errout_with_nxmutex: nxmutex_destroy(&fb->lock); +errout_with_paninfo: + while (i-- > 0) + { + circbuf_uninit(&(fb->paninfo[i].buf)); + } + + kmm_free(fb->paninfo); +errout_with_fb: kmm_free(fb); return ret; } diff --git a/include/nuttx/video/fb.h b/include/nuttx/video/fb.h index 9c69e45182..f597f502e6 100644 --- a/include/nuttx/video/fb.h +++ b/include/nuttx/video/fb.h @@ -181,6 +181,8 @@ /* Hardware overlay acceleration ********************************************/ +#define FB_NO_OVERLAY -1 + #ifdef CONFIG_FB_OVERLAY # define FB_ACCL_TRANSP 0x01 /* Hardware tranparency support */ # define FB_ACCL_CHROMA 0x02 /* Hardware chromakey support */ @@ -673,6 +675,14 @@ struct fb_setcursor_s }; #endif +union fb_paninfo_u +{ + struct fb_planeinfo_s planeinfo; +#ifdef CONFIG_FB_OVERLAY + struct fb_overlayinfo_s overlayinfo; +#endif +}; + /* The framebuffer "object" is accessed through within the OS via * the following vtable: */ @@ -996,17 +1006,55 @@ FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane); void up_fbuninitialize(int display); /**************************************************************************** - * Name: fb_pollnotify - * + * Name: fb_peek_paninfo * Description: - * Notify the waiting thread that the framebuffer can be written. + * Peek a frame from pan info queue of the specified overlay. * * Input Parameters: - * vtable - Pointer to framebuffer's virtual table. + * vtable - Pointer to framebuffer's virtual table. + * info - Pointer to pan info. + * overlay - Overlay index. * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. ****************************************************************************/ -void fb_pollnotify(FAR struct fb_vtable_s *vtable); +int fb_peek_paninfo(FAR struct fb_vtable_s *vtable, + FAR union fb_paninfo_u *info, + int overlay); + +/**************************************************************************** + * Name: fb_remove_paninfo + * Description: + * Remove a frame from pan info queue of the specified overlay. + * + * Input Parameters: + * vtable - Pointer to framebuffer's virtual table. + * overlay - Overlay index. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + ****************************************************************************/ + +int fb_remove_paninfo(FAR struct fb_vtable_s *vtable, int overlay); + +/**************************************************************************** + * Name: fb_paninfo_count + * Description: + * Get pan info count of specified overlay pan info queue. + * + * Input Parameters: + * vtable - Pointer to framebuffer's virtual table. + * overlay - Overlay index. + * + * Returned Value: + * a non-negative value is returned on success; a negated errno value is + * returned on any failure. + ****************************************************************************/ + +int fb_paninfo_count(FAR struct fb_vtable_s *vtable, int overlay); /**************************************************************************** * Name: fb_register