apps/examples: fb_main need ioctl(FBIOPAN_DISPLAY) to update and adapt to double buffer mode.

Signed-off-by: jianglianfang <jianglianfang@xiaomi.com>
This commit is contained in:
jianglianfang 2023-12-26 16:56:37 +08:00 committed by Xiang Xiao
parent 481d4b6e23
commit 72e186f64a

View File

@ -32,6 +32,7 @@
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <nuttx/video/fb.h> #include <nuttx/video/fb.h>
#include <nuttx/video/rgbcolors.h> #include <nuttx/video/rgbcolors.h>
@ -55,6 +56,9 @@ struct fb_state_s
struct fb_overlayinfo_s oinfo; struct fb_overlayinfo_s oinfo;
#endif #endif
FAR void *fbmem; FAR void *fbmem;
FAR void *fbmem2;
FAR void *act_fbmem;
uint32_t mem2_yoffset;
}; };
/**************************************************************************** /****************************************************************************
@ -87,6 +91,130 @@ static const uint8_t g_rgb8[NCOLORS] =
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* sync_area
****************************************************************************/
static void sync_area(FAR struct fb_state_s *state)
{
if (state->fbmem2 == NULL)
{
return;
}
if (state->act_fbmem == state->fbmem)
{
memcpy(state->fbmem, state->fbmem2,
state->vinfo.yres * state->pinfo.stride);
}
else
{
memcpy(state->fbmem2, state->fbmem,
state->vinfo.yres * state->pinfo.stride);
}
}
/****************************************************************************
* pan_display
****************************************************************************/
static void pan_display(FAR struct fb_state_s *state)
{
struct pollfd pfd;
int ret;
pfd.fd = state->fd;
pfd.events = POLLOUT;
ret = poll(&pfd, 1, 0);
if (ret > 0)
{
if (state->fbmem2 == NULL)
{
return;
}
if (state->act_fbmem == state->fbmem)
{
state->pinfo.yoffset = 0;
}
else
{
state->pinfo.yoffset = state->mem2_yoffset;
}
ioctl(state->fd, FBIOPAN_DISPLAY,
(unsigned long)(uintptr_t)&state->pinfo);
state->act_fbmem = state->act_fbmem == state->fbmem ?
state->fbmem2 : state->fbmem;
}
}
/****************************************************************************
* fb_init_mem2
****************************************************************************/
static int fb_init_mem2(FAR struct fb_state_s *state,
FAR struct fb_planeinfo_s *pinfo)
{
int ret;
uintptr_t buf_offset;
pinfo->display = state->pinfo.display + 1;
ret = ioctl(state->fd, FBIOGET_PLANEINFO,
(unsigned long)(uintptr_t)pinfo);
if (ret < 0)
{
int errcode = errno;
fprintf(stderr, "ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n",
errcode);
return EXIT_FAILURE;
}
/* Check bpp */
if (pinfo->bpp != state->pinfo.bpp)
{
fprintf(stderr, "ERROR: fbmem2 is incorrect");
return -EINVAL;
}
/* Check the buffer address offset,
* It needs to be divisible by pinfo.stride
*/
buf_offset = pinfo->fbmem - state->fbmem;
if ((buf_offset % state->pinfo.stride) != 0)
{
fprintf(stderr, "ERROR: It is detected that buf_offset(%" PRIuPTR ") "
"and stride(%d) are not divisible, please ensure "
"that the driver handles the address offset by itself.",
buf_offset, state->pinfo.stride);
}
/* Calculate the address and yoffset of fbmem2 */
if (buf_offset == 0)
{
/* Use consecutive fbmem2. */
state->mem2_yoffset = state->vinfo.yres;
state->fbmem2 = pinfo->fbmem + state->mem2_yoffset * pinfo->stride;
}
else
{
/* Use non-consecutive fbmem2. */
state->mem2_yoffset = buf_offset / state->pinfo.stride;
state->fbmem2 = pinfo->fbmem;
}
return 0;
}
/**************************************************************************** /****************************************************************************
* draw_rect * draw_rect
****************************************************************************/ ****************************************************************************/
@ -99,7 +227,7 @@ static void draw_rect32(FAR struct fb_state_s *state,
int x; int x;
int y; int y;
row = (FAR uint8_t *)state->fbmem + state->pinfo.stride * area->y; row = (FAR uint8_t *)state->act_fbmem + state->pinfo.stride * area->y;
for (y = 0; y < area->h; y++) for (y = 0; y < area->h; y++)
{ {
dest = ((FAR uint32_t *)row) + area->x; dest = ((FAR uint32_t *)row) + area->x;
@ -120,7 +248,7 @@ static void draw_rect16(FAR struct fb_state_s *state,
int x; int x;
int y; int y;
row = (FAR uint8_t *)state->fbmem + state->pinfo.stride * area->y; row = (FAR uint8_t *)state->act_fbmem + state->pinfo.stride * area->y;
for (y = 0; y < area->h; y++) for (y = 0; y < area->h; y++)
{ {
dest = ((FAR uint16_t *)row) + area->x; dest = ((FAR uint16_t *)row) + area->x;
@ -141,7 +269,7 @@ static void draw_rect8(FAR struct fb_state_s *state,
int x; int x;
int y; int y;
row = (FAR uint8_t *)state->fbmem + state->pinfo.stride * area->y; row = (FAR uint8_t *)state->act_fbmem + state->pinfo.stride * area->y;
for (y = 0; y < area->h; y++) for (y = 0; y < area->h; y++)
{ {
dest = row + area->x; dest = row + area->x;
@ -171,7 +299,7 @@ static void draw_rect1(FAR struct fb_state_s *state,
/* Calculate the framebuffer address of the first row to draw on */ /* Calculate the framebuffer address of the first row to draw on */
row = (FAR uint8_t *)state->fbmem + state->pinfo.stride * area->y; row = (FAR uint8_t *)state->act_fbmem + state->pinfo.stride * area->y;
/* Calculate the position of the first complete (with all bits) byte. /* Calculate the position of the first complete (with all bits) byte.
* Then calculate the last byte with all the bits. * Then calculate the last byte with all the bits.
@ -263,6 +391,10 @@ static void draw_rect(FAR struct fb_state_s *state,
} }
#ifdef CONFIG_FB_UPDATE #ifdef CONFIG_FB_UPDATE
int yoffset = state->act_fbmem == state->fbmem ?
0 : state->mem2_yoffset;
area->y += yoffset;
ret = ioctl(state->fd, FBIO_UPDATE, ret = ioctl(state->fd, FBIO_UPDATE,
(unsigned long)((uintptr_t)area)); (unsigned long)((uintptr_t)area));
if (ret < 0) if (ret < 0)
@ -272,6 +404,11 @@ static void draw_rect(FAR struct fb_state_s *state,
errcode); errcode);
} }
#endif #endif
if (state->pinfo.yres_virtual == (state->vinfo.yres * 2))
{
pan_display(state);
}
} }
/**************************************************************************** /****************************************************************************
@ -285,6 +422,7 @@ static void draw_rect(FAR struct fb_state_s *state,
int main(int argc, FAR char *argv[]) int main(int argc, FAR char *argv[])
{ {
FAR const char *fbdev = g_default_fbdev; FAR const char *fbdev = g_default_fbdev;
struct fb_planeinfo_s pinfo;
struct fb_state_s state; struct fb_state_s state;
struct fb_area_s area; struct fb_area_s area;
int nsteps; int nsteps;
@ -440,8 +578,19 @@ int main(int argc, FAR char *argv[])
printf("Mapped FB: %p\n", state.fbmem); printf("Mapped FB: %p\n", state.fbmem);
/* double buffer mode */
if (state.pinfo.yres_virtual == (state.vinfo.yres * 2))
{
if ((ret = fb_init_mem2(&state, &pinfo)) < 0)
{
goto out;
}
}
/* Draw some rectangles */ /* Draw some rectangles */
state.act_fbmem = state.fbmem;
nsteps = 2 * (NCOLORS - 1) + 1; nsteps = 2 * (NCOLORS - 1) + 1;
xstep = state.vinfo.xres / nsteps; xstep = state.vinfo.xres / nsteps;
ystep = state.vinfo.yres / nsteps; ystep = state.vinfo.yres / nsteps;
@ -465,10 +614,19 @@ int main(int argc, FAR char *argv[])
width -= (2 * xstep); width -= (2 * xstep);
height -= (2 * ystep); height -= (2 * ystep);
/* double buffer mode */
if (state.pinfo.yres_virtual == (state.vinfo.yres * 2))
{
sync_area(&state);
}
} }
printf("Test finished\n"); printf("Test finished\n");
ret = EXIT_SUCCESS;
out:
munmap(state.fbmem, state.pinfo.fblen); munmap(state.fbmem, state.pinfo.fblen);
close(state.fd); close(state.fd);
return EXIT_SUCCESS; return ret;
} }