diff --git a/components/drivers/graphic/graphic.c b/components/drivers/graphic/graphic.c index d1692c851e1..90bdde28bbd 100644 --- a/components/drivers/graphic/graphic.c +++ b/components/drivers/graphic/graphic.c @@ -107,14 +107,25 @@ static rt_err_t plane_fb_remap(struct rt_graphic_plane *plane, static rt_err_t plane_fb_pan_display(struct rt_graphic_plane *plane, struct rt_device_rect_info *rect) { - void *framebuffer_end = plane->framebuffer; rt_size_t byte_per_pixel = plane->bits_per_pixel / 8; + rt_size_t offset, row_bytes, span; - framebuffer_end += rect->x * byte_per_pixel; - framebuffer_end += rect->y * plane->line_length; - framebuffer_end += rect->width * rect->height * byte_per_pixel; + if (!plane->framebuffer || !byte_per_pixel || !rect->width || !rect->height) + { + return -RT_EINVAL; + } + + row_bytes = rect->width * byte_per_pixel; - if (framebuffer_end < plane->framebuffer + plane->framebuffer_len) + if (rect->x * byte_per_pixel + row_bytes > plane->line_length) + { + return -RT_EINVAL; + } + + offset = rect->y * plane->line_length + rect->x * byte_per_pixel; + span = (rect->height - 1) * plane->line_length + row_bytes; + + if (offset <= plane->framebuffer_len && span <= plane->framebuffer_len - offset) { return plane->ops->fb_pan_display(plane, rect); } @@ -203,6 +214,7 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) { rt_err_t err = RT_EOK; rt_bool_t need_schedule = RT_FALSE; + rt_bool_t wait_vsync = RT_FALSE; struct rt_graphic_device *gdev = raw_to_graphic(dev); _retry: @@ -520,7 +532,7 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) case RTGRAPHIC_CTRL_WAIT_VSYNC: if (gdev->ops->wait_vsync) { - err = gdev->ops->wait_vsync(gdev); + wait_vsync = RT_TRUE; } break; @@ -555,6 +567,8 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) var->yres = plane->height; var->xres_virtual = plane->width; var->yres_virtual = plane->height * (plane->framebuffer_len / plane->screen_len); + var->xoffset = plane->x; + var->yoffset = plane->y; var->bits_per_pixel = plane->bits_per_pixel; if (plane == gdev->primary_plane) @@ -668,10 +682,16 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) for (int i = 0; i < plane->modes_nr; ++i) { - /* Check supported and commit */ - if (plane->modes[i] == mode && plane->mode != mode) + if (plane->modes[i] == mode) { - err = plane_fb_remap(plane, mode, &rect); + err = RT_EOK; + + if (plane->mode != mode) + { + err = plane_fb_remap(plane, mode, &rect); + } + + break; } } @@ -685,6 +705,11 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) err = plane_fb_pan_display(plane, &rect); } + if (!err && (var->activate & FB_ACTIVATE_VBL) && gdev->ops->wait_vsync) + { + wait_vsync = RT_TRUE; + } + if (!err && var->rotate && plane->ops->prop_set) { err = plane->ops->prop_set(plane, RT_GRAPHIC_PLANE_PROP_ROTATE, @@ -733,6 +758,11 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) fix->mmio_start = fix->smem_start; fix->mmio_len = plane->screen_len; fix->line_length = plane->line_length; + + if (plane->ops->fb_pan_display && plane->framebuffer_len > plane->screen_len) + { + fix->ypanstep = 1; + } } else { @@ -769,6 +799,11 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) rect.height = var->yres; err = plane_fb_pan_display(plane, &rect); + + if (!err && (var->activate & FB_ACTIVATE_VBL) && gdev->ops->wait_vsync) + { + wait_vsync = RT_TRUE; + } } else { @@ -901,7 +936,7 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) case FBIO_WAITFORVSYNC: if (gdev->ops->wait_vsync) { - err = gdev->ops->wait_vsync(gdev); + wait_vsync = RT_TRUE; } break; @@ -930,6 +965,11 @@ static rt_err_t _graphic_control(rt_device_t dev, int cmd, void *args) spin_unlock(&gdev->lock); + if (!err && wait_vsync) + { + err = gdev->ops->wait_vsync(gdev); + } + return err; } diff --git a/components/drivers/include/drivers/lcd.h b/components/drivers/include/drivers/lcd.h index 11fa8e6dccc..35530b8f374 100644 --- a/components/drivers/include/drivers/lcd.h +++ b/components/drivers/include/drivers/lcd.h @@ -40,6 +40,15 @@ #define FBIOGET_DISPINFO 0x4618 #define FBIO_WAITFORVSYNC 0x4620 +/* fb_var_screeninfo.activate */ +#define FB_ACTIVATE_NOW 0 +#define FB_ACTIVATE_NXTOPEN 1 +#define FB_ACTIVATE_TEST 2 +#define FB_ACTIVATE_MASK 15 +#define FB_ACTIVATE_VBL 16 +#define FB_ACTIVATE_ALL 64 +#define FB_ACTIVATE_FORCE 128 + struct fb_bitfield { uint32_t offset; /* beginning of bitfield */ diff --git a/examples/test/dm_graphic_test.c b/examples/test/dm_graphic_test.c index a6894ddc6e6..9017994ab31 100644 --- a/examples/test/dm_graphic_test.c +++ b/examples/test/dm_graphic_test.c @@ -11,6 +11,7 @@ #include #include +#include #include #ifdef RT_USING_GRAPHIC @@ -225,7 +226,10 @@ rt_err_t graphic_start(const char *gdev, int count) { rt_err_t err; rt_uint8_t *vfb, *fb, *pixel, bpp; + rt_size_t frame_len, page_count, front_page; + struct rt_device_rect_info rect; struct rt_device_graphic_info info; + struct fb_var_screeninfo var; struct rt_device *dev = rt_device_find(gdev); void (*conv_func)(rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, void *pixel); @@ -244,7 +248,21 @@ rt_err_t graphic_start(const char *gdev, int count) goto _end; } - if (!(vfb = rt_malloc(info.smem_len))) + if ((err = rt_device_control(dev, FBIOGET_VSCREENINFO, &var))) + { + goto _end; + } + + frame_len = (rt_size_t)info.pitch * info.height; + page_count = frame_len ? info.smem_len / frame_len : 0; + + if (!page_count) + { + err = -RT_EINVAL; + goto _end; + } + + if (!(vfb = rt_malloc(frame_len))) { err = -RT_ENOMEM; goto _end; @@ -252,6 +270,19 @@ rt_err_t graphic_start(const char *gdev, int count) bpp = info.bits_per_pixel / 8; conv_func = conv_funcs[info.pixel_format]; + front_page = var.yoffset / info.height; + + if (page_count > 1) + { + /* Explicit page flips do not need the legacy periodic update timer. */ + var.pixclock = 0; + var.activate = FB_ACTIVATE_NOW; + + if ((err = rt_device_control(dev, FBIOPUT_VSCREENINFO, &var))) + { + goto _free_vfb; + } + } for (int frame = 0; frame < count; ++frame) { @@ -275,9 +306,39 @@ rt_err_t graphic_start(const char *gdev, int count) fb += info.pitch; } - rt_memcpy(info.framebuffer, vfb, info.smem_len); + if (page_count > 1) + { + front_page = (front_page + 1) % page_count; + rt_memcpy((rt_uint8_t *)info.framebuffer + front_page * frame_len, + vfb, frame_len); + + var.xoffset = 0; + var.yoffset = front_page * info.height; + var.activate = FB_ACTIVATE_VBL; + err = rt_device_control(dev, FBIOPAN_DISPLAY, &var); + } + else + { + rt_memcpy(info.framebuffer, vfb, frame_len); + rect.x = 0; + rect.y = 0; + rect.width = info.width; + rect.height = info.height; + err = rt_device_control(dev, RTGRAPHIC_CTRL_RECT_UPDATE, &rect); + + if (!err) + { + err = rt_device_control(dev, RTGRAPHIC_CTRL_WAIT_VSYNC, RT_NULL); + } + } + + if (err) + { + break; + } } +_free_vfb: rt_free(vfb); _end: