diff --git a/firmware/target/hosted/lcd-linuxfb.c b/firmware/target/hosted/lcd-linuxfb.c index c0eaf07fb4..bcf588b1e8 100644 --- a/firmware/target/hosted/lcd-linuxfb.c +++ b/firmware/target/hosted/lcd-linuxfb.c @@ -34,13 +34,30 @@ #include "sysfs.h" #include "panic.h" +//#define FB_DOUBLEBUF + static int fd = -1; static struct fb_var_screeninfo vinfo; static struct fb_fix_screeninfo finfo; fb_data *framebuffer = NULL; /* global variable, see lcd-target.h */ +#ifdef FB_DOUBLEBUF +static int fb_plane; +static int doublebuf; +#else +#define fb_plane 0 +#endif + static void redraw(void) { +#ifdef FB_DOUBLEBUF + if (doublebuf) { + vinfo.yoffset = fb_plane * LCD_HEIGHT; + fb_plane = !fb_plane; + vinfo.activate = FB_ACTIVATE_VBL; + } +#endif + ioctl(fd, FBIOPAN_DISPLAY, &vinfo); } @@ -53,32 +70,54 @@ void lcd_init_device(void) panicf("Cannot open framebuffer: %s\n", fb_dev); } - /* get fixed and variable information */ + /* get fixed information */ if(ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) { panicf("Cannot read framebuffer fixed information"); } + if (finfo.smem_len < FRAMEBUFFER_SIZE) + panicf("FRAMEBUFFER_SIZE too large for hardware? (%u vs %u)", FRAMEBUFFER_SIZE, finfo.smem_len); +#ifdef FB_DOUBLEBUF + if (finfo.smem_len >= 2*FRAMEBUFFER_SIZE) + doublebuf = 1; + fb_plane = 0; +#endif + + /* get variable information */ if(ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { panicf("Cannot read framebuffer variable information"); } +#ifdef FB_DOUBLEBUF + if (doublebuf) { + vinfo.yres_virtual = vinfo.yres * 2; + if(ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) { + panicf("Cannot write framebuffer variable information"); + } + } + +#if 0 + /* check resolution and framebuffer size */ + if(vinfo.xres != LCD_WIDTH || vinfo.yres != LCD_HEIGHT || vinfo.bits_per_pixel != LCD_DEPTH) + { + panicf("Unexpected framebuffer resolution: %dx%dx%d\n", vinfo.xres, + vinfo.yres, vinfo.bits_per_pixel); + } +#endif +#else /* Make sure we match our desired bitdepth */ if (vinfo.bits_per_pixel != LCD_DEPTH || vinfo.xres != LCD_WIDTH || vinfo.yres != LCD_HEIGHT) { vinfo.bits_per_pixel = LCD_DEPTH; vinfo.xres = LCD_WIDTH; vinfo.yres = LCD_HEIGHT; - vinfo.yres_virtual = vinfo.yres; /* Ensure we're on the correct bank */ if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo)) { panicf("Cannot set framebuffer to %dx%dx%d", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); } } - /* Note: we use a framebuffer size of width*height*bbp. We cannot trust the - * values returned by the driver for line_length */ - if (finfo.smem_len < FRAMEBUFFER_SIZE) - panicf("FRAMEBUFFER_SIZE too large for hardware? (%u vs %u)", FRAMEBUFFER_SIZE, finfo.smem_len); +#endif /* map framebuffer */ framebuffer = mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); @@ -114,13 +153,10 @@ void lcd_enable(bool on) lcd_set_active(on); - if (on) - { + if (on) { send_event(LCD_EVENT_ACTIVATION, NULL); ioctl(fd, FB_BLANK_UNBLANK); - } - else - { + } else { memset(framebuffer, 0, finfo.smem_len); redraw(); ioctl(fd, FB_BLANK_POWERDOWN); @@ -140,7 +176,8 @@ void lcd_update(void) #endif { /* Copy the Rockbox framebuffer to the second framebuffer */ - lcd_copy_buffer_rect(LCD_FRAMEBUF_ADDR(0, 0), FBADDR(0,0), + fb_data *dst = LCD_FRAMEBUF_ADDR(0, 0) + (fb_plane * FRAMEBUFFER_SIZE); + lcd_copy_buffer_rect(dst, FBADDR(0,0), LCD_WIDTH*LCD_HEIGHT, 1); redraw(); } @@ -154,8 +191,8 @@ void lcd_update_rect(int x, int y, int width, int height) if (lcd_active()) #endif { - fb_data *dst = LCD_FRAMEBUF_ADDR(x, y); - fb_data * src = FBADDR(x,y); + fb_data *dst = LCD_FRAMEBUF_ADDR(x, y) + (fb_plane * FRAMEBUFFER_SIZE); + fb_data *src = FBADDR(x,y); /* Copy part of the Rockbox framebuffer to the second framebuffer */ if (width < LCD_WIDTH)