From 960a6feb9a38e7df31c14f208f9d4603ecf357ac Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 20 Aug 2015 12:56:12 +0200 Subject: [PATCH 01/10] splash command: depend on CONFIG_VIDEO The splash command only makes sense with framebuffer support enabled, so add the corresponding dependency to Kconfig. Signed-off-by: Sascha Hauer --- commands/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/Kconfig b/commands/Kconfig index 133dcbf22..25ed9ddaf 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1458,6 +1458,7 @@ endif config CMD_SPLASH bool select IMAGE_RENDERER + depends on VIDEO prompt "splash" help Display a BMP image on a framebuffer device From 5c12f6b9f19269fffabb9e03f970f606c48a39b3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 10:12:58 +0200 Subject: [PATCH 02/10] video: fbconsole: do not enter when we are already in fbconsole Make it possible to issue console messages from inside the fbconsole code without entering the fbconsole again. Signed-off-by: Sascha Hauer --- drivers/video/fbconsole.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index b36807999..b7983072b 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -40,6 +40,7 @@ struct fbc_priv { u8 csi[256]; int active; + int in_console; }; static int fbc_getc(struct console_device *cdev) @@ -282,6 +283,10 @@ static void fbc_putc(struct console_device *cdev, char c) struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); + if (priv->in_console) + return; + priv->in_console = 1; + switch (priv->state) { case LIT: switch (c) { @@ -329,6 +334,7 @@ static void fbc_putc(struct console_device *cdev, char c) } break; } + priv->in_console = 0; } static int setup_font(struct fbc_priv *priv) From eac28050d0838da535ccd8e41ea3975f6143ff7b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:29:07 +0200 Subject: [PATCH 03/10] fb: return original fb_info in FBIOGET_SCREENINFO Signed-off-by: Sascha Hauer --- drivers/video/fb.c | 4 +++- lib/gui/graphic_utils.c | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 29b4c7101..dbda8d469 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -11,10 +11,12 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data) { struct fb_info *info = cdev->priv; + struct fb_info **fb; switch (req) { case FBIOGET_SCREENINFO: - memcpy(data, info, sizeof(*info)); + fb = data; + *fb = info; break; case FBIO_ENABLE: info->fbops->fb_enable(info); diff --git a/lib/gui/graphic_utils.c b/lib/gui/graphic_utils.c index 47003a083..f928ee16f 100644 --- a/lib/gui/graphic_utils.c +++ b/lib/gui/graphic_utils.c @@ -281,7 +281,7 @@ struct screen *fb_open(const char * fbdev, bool offscreen) info = xzalloc(sizeof(*info)); - ret = ioctl(fd, FBIOGET_SCREENINFO, info); + ret = ioctl(fd, FBIOGET_SCREENINFO, &info); if (ret) { goto failed_screeninfo; } @@ -310,10 +310,8 @@ void fb_close(struct screen *sc) { free(sc->offscreenbuf); - if (sc->fd > 0) { + if (sc->fd > 0) close(sc->fd); - free(sc->info); - } free(sc); } From 6f964990646cd728827e1d8689404878fae0a1fd Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:34:28 +0200 Subject: [PATCH 04/10] fb: Add shadowfb support For speeding up rendering we need shadow framebuffers. This is currently implemented in the gui functions. This does not work properly when two users (splash and fbconsole) use the same framebuffer since in this case two different shadow framebuffers will be used. This patch implements shadowfb handling in the fb core directly. With this the fb device gets a parameter 'shadowfb'. When this is true the fb core will allocate a shadow fb and provide it to the users. Signed-off-by: Sascha Hauer --- drivers/video/fb.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ include/fb.h | 3 +++ 2 files changed, 50 insertions(+) diff --git a/drivers/video/fb.c b/drivers/video/fb.c index dbda8d469..3672c4420 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -31,11 +31,40 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data) return 0; } +static int fb_alloc_shadowfb(struct fb_info *info) +{ + if (info->screen_base_shadow && info->shadowfb) + return 0; + + if (!info->screen_base_shadow && !info->shadowfb) + return 0; + + if (info->shadowfb) { + info->screen_base_shadow = memalign(PAGE_SIZE, + info->line_length * info->yres); + if (!info->screen_base_shadow) + return -ENOMEM; + memcpy(info->screen_base_shadow, info->screen_base, + info->line_length * info->yres); + } else { + free(info->screen_base_shadow); + info->screen_base_shadow = NULL; + } + + return 0; +} + int fb_enable(struct fb_info *info) { + int ret; + if (info->enabled) return 0; + ret = fb_alloc_shadowfb(info); + if (ret) + return ret; + info->fbops->fb_enable(info); info->enabled = true; @@ -188,6 +217,22 @@ static void fb_info(struct device_d *dev) fb_print_modes(&info->edid_modes); } +void *fb_get_screen_base(struct fb_info *info) +{ + return info->screen_base_shadow ? + info->screen_base_shadow : info->screen_base; +} + +int fb_set_shadowfb(struct param_d *p, void *priv) +{ + struct fb_info *info = priv; + + if (!info->enabled) + return 0; + + return fb_alloc_shadowfb(info); +} + int register_framebuffer(struct fb_info *info) { int id = get_free_deviceid("fb"); @@ -245,6 +290,8 @@ int register_framebuffer(struct fb_info *info) for (i = 0; i < info->edid_modes.num_modes; i++) names[i + info->modes.num_modes] = info->edid_modes.modes[i].name; dev_add_param_enum(dev, "mode_name", fb_set_modename, NULL, &info->current_mode, names, num_modes, info); + info->shadowfb = 1; + dev_add_param_bool(dev, "shadowfb", fb_set_shadowfb, NULL, &info->shadowfb, info); info->mode = fb_num_to_mode(info, 0); diff --git a/include/fb.h b/include/fb.h index 311d5db19..cf113c430 100644 --- a/include/fb.h +++ b/include/fb.h @@ -118,6 +118,7 @@ struct fb_info { struct device_d dev; /* This is this fb device */ void *screen_base; + void *screen_base_shadow; unsigned long screen_size; void *priv; @@ -141,6 +142,7 @@ struct fb_info { int register_simplefb; /* If true a simplefb device node will * be created. */ + int shadowfb; }; struct display_timings *of_get_display_timings(struct device_node *np); @@ -167,5 +169,6 @@ void fb_edid_add_modes(struct fb_info *info); void fb_of_reserve_add_fixup(struct fb_info *info); int register_fbconsole(struct fb_info *fb); +void *fb_get_screen_base(struct fb_info *info); #endif /* __FB_H */ From 38a71cde8f6e8ce175428dff16b1a89b4b7a7843 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:38:58 +0200 Subject: [PATCH 05/10] splash command: simplify offscreen rendering Signed-off-by: Sascha Hauer --- commands/splash.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/commands/splash.c b/commands/splash.c index 90f0a0cdf..29e30ae3b 100644 --- a/commands/splash.c +++ b/commands/splash.c @@ -18,6 +18,7 @@ static int do_splash(int argc, char *argv[]) int offscreen = 0; u32 bg_color = 0x00000000; bool do_bg = false; + void *buf; memset(&s, 0, sizeof(s)); @@ -58,15 +59,11 @@ static int do_splash(int argc, char *argv[]) return PTR_ERR(sc); } - if (sc->offscreenbuf) { - if (do_bg) - gu_memset_pixel(sc->info, sc->offscreenbuf, bg_color, - sc->s.width * sc->s.height); - else - memcpy(sc->offscreenbuf, sc->fb, sc->fbsize); - } else if (do_bg) { - gu_memset_pixel(sc->info, sc->fb, bg_color, sc->s.width * sc->s.height); - } + buf = gui_screen_render_buffer(sc); + + if (do_bg) + gu_memset_pixel(sc->info, buf, bg_color, + sc->s.width * sc->s.height); ret = image_renderer_file(sc, &s, image_file); if (ret > 0) From 7c5937d245b4ecf3c1c33eecfda0851aa277dbc6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:41:17 +0200 Subject: [PATCH 06/10] gui: Use fb provided shadowfb for offscreen rendering The fb core now has builtin support for offscreen rendering, use this and drop offscreen handling in the gui code. Signed-off-by: Sascha Hauer --- commands/splash.c | 6 +----- drivers/video/fbconsole.c | 2 +- include/gui/graphic_utils.h | 4 ++-- include/gui/gui.h | 6 +----- lib/gui/graphic_utils.c | 24 +++++++----------------- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/commands/splash.c b/commands/splash.c index 29e30ae3b..15b296b68 100644 --- a/commands/splash.c +++ b/commands/splash.c @@ -15,7 +15,6 @@ static int do_splash(int argc, char *argv[]) int opt; char *fbdev = "/dev/fb0"; char *image_file; - int offscreen = 0; u32 bg_color = 0x00000000; bool do_bg = false; void *buf; @@ -42,8 +41,6 @@ static int do_splash(int argc, char *argv[]) case 'y': s.y = simple_strtoul(optarg, NULL, 0); break; - case 'o': - offscreen = 1; } } @@ -53,7 +50,7 @@ static int do_splash(int argc, char *argv[]) } image_file = argv[optind]; - sc = fb_open(fbdev, offscreen); + sc = fb_open(fbdev); if (IS_ERR(sc)) { perror("fd_open"); return PTR_ERR(sc); @@ -86,7 +83,6 @@ BAREBOX_CMD_HELP_OPT ("-f FB\t", "framebuffer device (default /dev/fb0)") BAREBOX_CMD_HELP_OPT ("-x XOFFS", "x offset (default center)") BAREBOX_CMD_HELP_OPT ("-y YOFFS", "y offset (default center)") BAREBOX_CMD_HELP_OPT ("-b COLOR", "background color in 0xttrrggbb") -BAREBOX_CMD_HELP_OPT ("-o\t", "render offscreen") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(splash) diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index b7983072b..8805b554b 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -376,7 +376,7 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags) if (ret) return ret; - priv->sc = fb_create_screen(fb, 0); + priv->sc = fb_create_screen(fb); if (IS_ERR(priv->sc)) return PTR_ERR(priv->sc); diff --git a/include/gui/graphic_utils.h b/include/gui/graphic_utils.h index ab8c3fcff..ff4d9a07b 100644 --- a/include/gui/graphic_utils.h +++ b/include/gui/graphic_utils.h @@ -19,8 +19,8 @@ void gu_set_pixel(struct fb_info *info, void *adr, u32 px); void gu_set_rgb_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b); void gu_set_rgba_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b, u8 a); void gu_memset_pixel(struct fb_info *info, void* buf, u32 color, size_t size); -struct screen *fb_create_screen(struct fb_info *info, bool offscreen); -struct screen *fb_open(const char *fbdev, bool offscreen); +struct screen *fb_create_screen(struct fb_info *info); +struct screen *fb_open(const char *fbdev); void fb_close(struct screen *sc); void gu_screen_blit(struct screen *sc); void gu_invert_area(struct fb_info *info, void *buf, int startx, int starty, int width, diff --git a/include/gui/gui.h b/include/gui/gui.h index 03e60aa0d..133149bee 100644 --- a/include/gui/gui.h +++ b/include/gui/gui.h @@ -23,16 +23,12 @@ struct screen { struct surface s; void *fb; - void *offscreenbuf; int fbsize; }; static inline void *gui_screen_render_buffer(struct screen *sc) { - if (sc->offscreenbuf) - return sc->offscreenbuf; - return sc->fb; + return fb_get_screen_base(sc->info); } - #endif /* __GUI_H__ */ diff --git a/lib/gui/graphic_utils.c b/lib/gui/graphic_utils.c index f928ee16f..b57b4a1f9 100644 --- a/lib/gui/graphic_utils.c +++ b/lib/gui/graphic_utils.c @@ -245,7 +245,7 @@ void gu_rgba_blend(struct fb_info *info, struct image *img, void* buf, int heigh } } -struct screen *fb_create_screen(struct fb_info *info, bool offscreen) +struct screen *fb_create_screen(struct fb_info *info) { struct screen *sc; @@ -257,19 +257,12 @@ struct screen *fb_create_screen(struct fb_info *info, bool offscreen) sc->s.height = info->yres; sc->fbsize = info->line_length * sc->s.height; sc->fb = info->screen_base; - - if (offscreen) { - /* - * Don't fail if malloc fails, just continue rendering directly - * on the framebuffer - */ - sc->offscreenbuf = malloc(sc->fbsize); - } + sc->info = info; return sc; } -struct screen *fb_open(const char * fbdev, bool offscreen) +struct screen *fb_open(const char * fbdev) { int fd, ret; struct fb_info *info; @@ -286,7 +279,7 @@ struct screen *fb_open(const char * fbdev, bool offscreen) goto failed_screeninfo; } - sc = fb_create_screen(info, offscreen); + sc = fb_create_screen(info); if (IS_ERR(sc)) { ret = PTR_ERR(sc); goto failed_create; @@ -298,7 +291,6 @@ struct screen *fb_open(const char * fbdev, bool offscreen) return sc; failed_create: - free(sc->offscreenbuf); free(sc); failed_screeninfo: close(fd); @@ -308,8 +300,6 @@ failed_screeninfo: void fb_close(struct screen *sc) { - free(sc->offscreenbuf); - if (sc->fd > 0) close(sc->fd); @@ -318,8 +308,8 @@ void fb_close(struct screen *sc) void gu_screen_blit(struct screen *sc) { - if (!sc->offscreenbuf) - return; + struct fb_info *info = sc->info; - memcpy(sc->fb, sc->offscreenbuf, sc->fbsize); + if (info->screen_base_shadow) + memcpy(info->screen_base, info->screen_base_shadow, sc->fbsize); } From cabfe34ca70acbb009ad94b2578fde99957472a7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:42:58 +0200 Subject: [PATCH 07/10] gui: implement blitting screen areas So far we only supported blitting the whole screen from the shadow fb to the framebuffer. Add a function to blit areas. Signed-off-by: Sascha Hauer --- include/gui/graphic_utils.h | 2 ++ lib/gui/graphic_utils.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/gui/graphic_utils.h b/include/gui/graphic_utils.h index ff4d9a07b..231b3a941 100644 --- a/include/gui/graphic_utils.h +++ b/include/gui/graphic_utils.h @@ -25,5 +25,7 @@ void fb_close(struct screen *sc); void gu_screen_blit(struct screen *sc); void gu_invert_area(struct fb_info *info, void *buf, int startx, int starty, int width, int height); +void gu_screen_blit_area(struct screen *sc, int startx, int starty, int width, + int height); #endif /* __GRAPHIC_UTILS_H__ */ diff --git a/lib/gui/graphic_utils.c b/lib/gui/graphic_utils.c index b57b4a1f9..4c1885d55 100644 --- a/lib/gui/graphic_utils.c +++ b/lib/gui/graphic_utils.c @@ -306,6 +306,25 @@ void fb_close(struct screen *sc) free(sc); } +void gu_screen_blit_area(struct screen *sc, int startx, int starty, int width, + int height) +{ + struct fb_info *info = sc->info; + int bpp = info->bits_per_pixel >> 3; + + if (info->screen_base_shadow) { + int y; + void *fb = info->screen_base + starty * sc->info->line_length + startx * bpp; + void *fboff = info->screen_base_shadow + starty * sc->info->line_length + startx * bpp; + + for (y = starty; y < starty + height; y++) { + memcpy(fb, fboff, width * bpp); + fb += sc->info->line_length; + fboff += sc->info->line_length; + } + } +} + void gu_screen_blit(struct screen *sc) { struct fb_info *info = sc->info; From 3b3d5f412dc31a1f920932471eab771ef3d20319 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:44:16 +0200 Subject: [PATCH 08/10] fb: fbconsole: print cursor after clearing the screen Signed-off-by: Sascha Hauer --- drivers/video/fbconsole.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 8805b554b..745833a9f 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -251,6 +251,7 @@ static void fbc_parse_csi(struct fbc_priv *priv) return; case 'J': cls(priv); + video_invertchar(priv, priv->x, priv->y); return; case 'H': video_invertchar(priv, priv->x, priv->y); From f84415497e5e50f7635a17652875ff106f92f03d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 7 Aug 2015 14:45:46 +0200 Subject: [PATCH 09/10] fb: fbconsole: Add missing blits When using offscreen rendering we need some more points where we blit the offscreen buffer to the screen. Add them. Signed-off-by: Sascha Hauer --- drivers/video/fbconsole.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 745833a9f..b10503eb8 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -58,6 +58,7 @@ static void cls(struct fbc_priv *priv) void *buf = gui_screen_render_buffer(priv->sc); memset(buf, 0, priv->fb->line_length * priv->fb->yres); + gu_screen_blit(priv->sc); } struct rgb { @@ -138,6 +139,8 @@ static void video_invertchar(struct fbc_priv *priv, int x, int y) gu_invert_area(priv->fb, buf, x * priv->font_width, y * priv->font_height, priv->font_width, priv->font_height); + gu_screen_blit_area(priv->sc, x * priv->font_width, y * priv->font_height, + priv->font_width, priv->font_height); } static void printchar(struct fbc_priv *priv, int c) @@ -170,7 +173,10 @@ static void printchar(struct fbc_priv *priv, int c) default: drawchar(priv, priv->x, priv->y, c); - gu_screen_blit(priv->sc); + + gu_screen_blit_area(priv->sc, priv->x * priv->font_width, + priv->y * priv->font_height, + priv->font_width, priv->font_height); priv->x++; if (priv->x > priv->cols) { @@ -188,6 +194,7 @@ static void printchar(struct fbc_priv *priv, int c) memcpy(buf, buf + line_height, line_height * (priv->rows + 1)); memset(buf + line_height * priv->rows, 0, line_height); + gu_screen_blit(priv->sc); priv->y = priv->rows; } From 2b7e24c1e967dce9672800bf64afa15e6090bbb8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 14 Aug 2015 12:16:44 +0200 Subject: [PATCH 10/10] video: fbcon: needs console support Fixes: In function `register_fbconsole': drivers/video/fbconsole.c:425: undefined reference to `console_register Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/video/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d7f5b0763..ebae7386d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -7,6 +7,7 @@ if VIDEO config FRAMEBUFFER_CONSOLE bool + depends on !CONSOLE_NONE select IMAGE_RENDERER select FONTS prompt "framebuffer console support"