diff --git a/commands/Kconfig b/commands/Kconfig index 133dcbf..25ed9dd 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1458,6 +1458,7 @@ config CMD_SPLASH bool select IMAGE_RENDERER + depends on VIDEO prompt "splash" help Display a BMP image on a framebuffer device diff --git a/commands/splash.c b/commands/splash.c index 90f0a0c..15b296b 100644 --- a/commands/splash.c +++ b/commands/splash.c @@ -15,9 +15,9 @@ int opt; char *fbdev = "/dev/fb0"; char *image_file; - int offscreen = 0; u32 bg_color = 0x00000000; bool do_bg = false; + void *buf; memset(&s, 0, sizeof(s)); @@ -41,8 +41,6 @@ case 'y': s.y = simple_strtoul(optarg, NULL, 0); break; - case 'o': - offscreen = 1; } } @@ -52,21 +50,17 @@ } image_file = argv[optind]; - sc = fb_open(fbdev, offscreen); + sc = fb_open(fbdev); if (IS_ERR(sc)) { perror("fd_open"); 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) @@ -89,7 +83,6 @@ 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/Kconfig b/drivers/video/Kconfig index d7f5b07..ebae738 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -7,6 +7,7 @@ config FRAMEBUFFER_CONSOLE bool + depends on !CONSOLE_NONE select IMAGE_RENDERER select FONTS prompt "framebuffer console support" diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 29b4c71..3672c44 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); @@ -29,11 +31,40 @@ 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; @@ -186,6 +217,22 @@ 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"); @@ -243,6 +290,8 @@ 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/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index b368079..b10503e 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -40,6 +40,7 @@ u8 csi[256]; int active; + int in_console; }; static int fbc_getc(struct console_device *cdev) @@ -57,6 +58,7 @@ 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 { @@ -137,6 +139,8 @@ 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) @@ -169,7 +173,10 @@ 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) { @@ -187,6 +194,7 @@ 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; } @@ -250,6 +258,7 @@ return; case 'J': cls(priv); + video_invertchar(priv, priv->x, priv->y); return; case 'H': video_invertchar(priv, priv->x, priv->y); @@ -282,6 +291,10 @@ 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 +342,7 @@ } break; } + priv->in_console = 0; } static int setup_font(struct fbc_priv *priv) @@ -370,7 +384,7 @@ 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/fb.h b/include/fb.h index 311d5db..cf113c4 100644 --- a/include/fb.h +++ b/include/fb.h @@ -118,6 +118,7 @@ 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 @@ 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_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 */ diff --git a/include/gui/graphic_utils.h b/include/gui/graphic_utils.h index ab8c3fc..231b3a9 100644 --- a/include/gui/graphic_utils.h +++ b/include/gui/graphic_utils.h @@ -19,11 +19,13 @@ 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, 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/include/gui/gui.h b/include/gui/gui.h index 03e60aa..133149b 100644 --- a/include/gui/gui.h +++ b/include/gui/gui.h @@ -23,16 +23,12 @@ 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 47003a0..4c1885d 100644 --- a/lib/gui/graphic_utils.c +++ b/lib/gui/graphic_utils.c @@ -245,7 +245,7 @@ } } -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 @@ 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; @@ -281,12 +274,12 @@ info = xzalloc(sizeof(*info)); - ret = ioctl(fd, FBIOGET_SCREENINFO, info); + ret = ioctl(fd, FBIOGET_SCREENINFO, &info); if (ret) { 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 @@ return sc; failed_create: - free(sc->offscreenbuf); free(sc); failed_screeninfo: close(fd); @@ -308,20 +300,35 @@ 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); } +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) { - 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); }