From 41e1aa888b9d1fc41aaf158191980cce3e548302 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Thu, 16 Feb 2006 20:03:07 +0000 Subject: [PATCH] Grayscale iPods: Fixed & optimised LCD driver. Further optimisation is possible. * LCD driver now uses proper native bitmaps resembling the LCD internal format. Mono bitmaps are still transposed. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8706 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/lcd-2bit-horz.c | 261 ++++++++++++++++++++++--------- tools/bmp2rb.c | 44 ++++-- tools/configure | 4 +- 3 files changed, 221 insertions(+), 88 deletions(-) diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c index 1045ba654b..f9f5152faa 100644 --- a/firmware/drivers/lcd-2bit-horz.c +++ b/firmware/drivers/lcd-2bit-horz.c @@ -45,6 +45,10 @@ static const unsigned char dibits[16] ICONST_ATTR = { 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF }; +static const unsigned char pixmask[4] ICONST_ATTR = { + 0x03, 0x0C, 0x30, 0xC0 +}; + static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ static int drawmode = DRMODE_SOLID; @@ -70,8 +74,6 @@ static const char scroll_tick_table[16] = { }; -static unsigned char notmask[4] = { 0xfc, 0xf3, 0xcf, 0x3f }; - /* LCD init */ void lcd_init(void) { @@ -154,29 +156,23 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h) /*** low-level drawing functions ***/ -static void setpixel_value(int x, int y, unsigned val) -{ - unsigned char *data = &lcd_framebuffer[y][x>>2]; - - *data = (*data & notmask[x&3]) | (val << ((x&3)<<1)); -} - static void setpixel(int x, int y) { unsigned char *data = &lcd_framebuffer[y][x>>2]; - - *data = (*data & notmask[x&3]) | (fg_pattern << ((x&3)<<1)); + unsigned mask = pixmask[x & 3]; + *data = (*data & ~mask) | (fg_pattern & mask); } static void clearpixel(int x, int y) { - unsigned char *data = &lcd_framebuffer[y][x>>2]; -*data = (*data & notmask[x&3]) | (bg_pattern << ((x&3)<<1)); + unsigned char *data = &lcd_framebuffer[y][x>>2]; + unsigned mask = pixmask[x & 3]; + *data = (*data & ~mask) | (bg_pattern & mask); } static void flippixel(int x, int y) { - lcd_framebuffer[y][x>>2] ^= 3 << (2 * (x & 3)); + lcd_framebuffer[y][x>>2] ^= pixmask[x & 3]; } static void nopixel(int x, int y) @@ -190,6 +186,78 @@ lcd_pixelfunc_type* const lcd_pixelfuncs[8] = { nopixel, clearpixel, nopixel, clearpixel }; +/* 'mask' and 'bits' contain 2 bits per pixel */ +static void flipblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void flipblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address ^= bits & mask; +} + +static void bgblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void bgblock(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= ~bits; + *address = (*address & ~mask) | (bg_pattern & mask); +} + +static void fgblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void fgblock(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= bits; + *address = (*address & ~mask) | (fg_pattern & mask); +} + +static void solidblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void solidblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (bits & mask & fg_pattern) + | (~bits & mask & bg_pattern); +} + +static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address ^= ~bits & mask; +} + +static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= bits; + *address = (*address & ~mask) | (bg_pattern & mask); +} + +static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + mask &= ~bits; + *address = (*address & ~mask) | (fg_pattern & mask); +} + +static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (~bits & mask & fg_pattern) + | (bits & mask & bg_pattern); +} + +lcd_blockfunc_type* const lcd_blockfuncs[8] = { + flipblock, bgblock, fgblock, solidblock, + flipinvblock, bginvblock, fginvblock, solidinvblock +}; + +static inline void setblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (bits & mask); +} /*** drawing functions ***/ @@ -283,16 +351,17 @@ void lcd_drawline(int x1, int y1, int x2, int y2) /* Draw a horizontal line (optimised) */ void lcd_hline(int x1, int x2, int y) { - int x; - - lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; + int nx; + unsigned char *dst; + unsigned mask, mask_right; + lcd_blockfunc_type *bfunc; /* direction flip */ if (x2 < x1) { - x = x1; + nx = x1; x1 = x2; - x2 = x; + x2 = nx; } /* nothing to draw? */ @@ -305,25 +374,35 @@ void lcd_hline(int x1, int x2, int y) if (x2 >= LCD_WIDTH) x2 = LCD_WIDTH-1; - while(x1 <= x2) { - pfunc(x1,y); - ++x1; + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y][x1>>2]; + nx = x2 - (x1 & ~3); + mask = 0xFFu << (2 * (x1 & 3)); + mask_right = 0xFFu >> (2 * (~nx & 3)); + + for (; nx >= 4; nx -= 4) + { + bfunc(dst++, mask, 0xFFu); + mask = 0xFFu; } + mask &= mask_right; + bfunc(dst, mask, 0xFFu); } /* Draw a vertical line (optimised) */ void lcd_vline(int x, int y1, int y2) { - int ny; - - lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; + int y; + unsigned char *dst, *dst_end; + unsigned mask; + lcd_blockfunc_type *bfunc; /* direction flip */ if (y2 < y1) { - ny = y1; + y = y1; y1 = y2; - y2 = ny; + y2 = y; } /* nothing to draw? */ @@ -336,10 +415,17 @@ void lcd_vline(int x, int y1, int y2) if (y2 >= LCD_HEIGHT) y2 = LCD_HEIGHT-1; - - while(y1++ <= y2) { - pfunc(x, y1); + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y1][x>>2]; + mask = pixmask[x & 3]; + + dst_end = dst + (y2 - y1) * (LCD_WIDTH/4); + do + { + bfunc(dst, mask, 0xFFu); + dst += (LCD_WIDTH/4); } + while (dst <= dst_end); } /* Draw a rectangular box */ @@ -360,8 +446,10 @@ void lcd_drawrect(int x, int y, int width, int height) /* Fill a rectangular area */ void lcd_fillrect(int x, int y, int width, int height) { - int ny; - + int nx; + unsigned char *dst, *dst_end; + unsigned mask, mask_right; + lcd_blockfunc_type *bfunc; /* nothing to draw? */ if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) @@ -384,12 +472,36 @@ void lcd_fillrect(int x, int y, int width, int height) if (y + height > LCD_HEIGHT) height = LCD_HEIGHT - y; - ny = y; - while (ny <= height) + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y][x>>2]; + nx = width - 1 + (x & 3); + mask = 0xFFu << (2 * (x & 3)); + mask_right = 0xFFu >> (2 * (~nx & 3)); + + for (; nx >= 4; nx -= 4) { - lcd_hline (x, width, ny); - ny++; + unsigned char *dst_col = dst; + + dst_end = dst_col + height * (LCD_WIDTH/4); + do + { + bfunc(dst_col, mask, 0xFFu); + dst_col += (LCD_WIDTH/4); + } + while (dst_col < dst_end); + + dst++; + mask = 0xFFu; } + mask &= mask_right; + + dst_end = dst + height * (LCD_WIDTH/4); + do + { + bfunc(dst, mask, 0xFFu); + dst += (LCD_WIDTH/4); + } + while (dst < dst_end); } /* About Rockbox' internal monochrome bitmap format: @@ -485,11 +597,10 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig /* About Rockbox' internal native bitmap format: * * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey, - * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB - * at top. + * 10 = dark grey, 11 = black. Bits within a byte are arranged horizontally, + * LSB at the left. * The bytes are stored in row-major order, with byte 0 being top left, - * byte 1 2nd from left etc. The first row of bytes defines pixel rows - * 0..3, the second row defines pixel row 4..7 etc. + * byte 1 2nd from left etc. Each row of bytes defines one pixel row. * * This is the same as the internal lcd hw format. */ @@ -500,8 +611,9 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, int stride, int x, int y, int width, int height) { - int ny, nx, ymax; - const unsigned char * src_end; + int shift, nx; + unsigned char *dst, *dst_end; + unsigned mask, mask_right; /* nothing to draw? */ if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) @@ -526,46 +638,49 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, if (y + height > LCD_HEIGHT) height = LCD_HEIGHT - y; - src += stride * (src_y >> 3) + src_x; /* move starting point */ - src_y &= 7; - src_end = src + width; + stride = (stride + 3) >> 2; /* convert to no. of bytes */ + + src += stride * src_y + (src_x >> 2); /* move starting point */ + src_x &= 3; + x -= src_x; + dst = &lcd_framebuffer[y][x>>2]; + shift = x & 3; + nx = width - 1 + shift + src_x; + + mask = 0xFFu << (2 * (shift + src_x)); + mask_right = 0xFFu >> (2 * (~nx & 3)); - nx = x; + shift *= 2; + dst_end = dst + height * (LCD_WIDTH/4); do { - const unsigned char *src_col = src++; - unsigned data = *src_col >> src_y; - int numbits = 8 - src_y; + const unsigned char *src_row = src; + unsigned char *dst_row = dst; + unsigned mask_row = mask; + unsigned data = 0; - ymax = y + height; - ny = y; - do + for (x = nx; x >= 4; x -= 4) { - if (data & 0x03) - setpixel_value (nx,ny, 0xFF); - else - if (data & 0x01) - setpixel_value (nx,ny, 0x3F); - else - if (data & 0x02) - setpixel_value (nx,ny, 0xCF); - else - setpixel_value (nx,ny, 0x00); - - ny++; - - data >>= 2; - if (--numbits == 0) + data |= *src_row++ << shift; + + if (mask_row & 0xFF) { - src_col += stride; - data = *src_col; - numbits = 4; + setblock(dst_row, mask_row, data); + mask_row = 0xFF; } + else + mask_row >>= 8; + + dst_row++; + data >>= 8; } - while (ny < ymax); - nx++; + data |= *src_row << shift; + setblock(dst_row, mask_row & mask_right, data); + + src += stride; + dst += (LCD_WIDTH/4); } - while (src < src_end); + while (dst < dst_end); } /* Draw a full native bitmap */ diff --git a/tools/bmp2rb.c b/tools/bmp2rb.c index 61c0268c49..d50b8c6f33 100644 --- a/tools/bmp2rb.c +++ b/tools/bmp2rb.c @@ -49,7 +49,7 @@ struct Fileheader { unsigned short Type; /* signature - 'BM' */ - unsigned int Size; /* file size in bytes */ + unsigned int Size; /* file size in bytes */ unsigned short Reserved1; /* 0 */ unsigned short Reserved2; /* 0 */ unsigned int OffBits; /* offset to bitmap */ @@ -278,41 +278,48 @@ int read_bmp_file(char* filename, int transform_bitmap(const struct RGBQUAD *src, int width, int height, int format, unsigned short **dest, int *dst_width, - int *dst_height) + int *dst_height, int *dst_depth) { int row, col; - int dst_w, dst_h; + int dst_w, dst_h, dst_d; switch (format) { case 0: /* Archos recorders, Ondio, Gmini 120/SP, Iriver H1x0 monochrome */ dst_w = width; dst_h = (height + 7) / 8; + dst_d = 8; break; case 1: /* Archos player graphics library */ dst_w = (width + 7) / 8; dst_h = height; + dst_d = 8; break; case 2: /* Iriver H1x0 4-grey */ dst_w = width; dst_h = (height + 3) / 4; + dst_d = 8; break; case 3: /* Canonical 8-bit grayscale */ dst_w = width; dst_h = height; + dst_d = 8; break; case 4: /* 16-bit packed RGB (5-6-5) */ - dst_w = width; - dst_h = height; - break; - case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */ dst_w = width; dst_h = height; + dst_d = 16; + break; + + case 6: /* greyscale iPods 4-grey */ + dst_w = (width + 3) / 4; + dst_h = height; + dst_d = 8; break; default: /* unknown */ @@ -329,6 +336,7 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, memset(*dest, 0, dst_w * dst_h * sizeof(short)); *dst_width = dst_w; *dst_height = dst_h; + *dst_depth = dst_d; switch (format) { @@ -383,6 +391,15 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, (*dest)[row * dst_w + col] = ((rgb&0xff00)>>8)|((rgb&0x00ff)<<8); } break; + + case 6: /* greyscale iPods 4-grey */ + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + { + (*dest)[row * dst_w + (col/4)] |= + (~brightness(src[row * width + col]) & 0xC0) >> (2 * (~col & 3)); + } + break; } return 0; @@ -397,7 +414,7 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, void generate_c_source(char *id, int width, int height, const unsigned short *t_bitmap, int t_width, - int t_height, int format) + int t_height, int t_depth) { FILE *f; int i, a; @@ -411,7 +428,7 @@ void generate_c_source(char *id, int width, int height, "#define BMPHEIGHT_%s %ld\n" "#define BMPWIDTH_%s %ld\n", id, height, id, width); - if(format < 4) + if (t_depth <= 8) fprintf(f, "const unsigned char %s[] = {\n", id); else fprintf(f, "const unsigned short %s[] = {\n", id); @@ -420,7 +437,7 @@ void generate_c_source(char *id, int width, int height, { for (a = 0; a < t_width; a++) { - if(format < 4) + if (t_depth <= 8) fprintf(f, "0x%02x,%c", t_bitmap[i * t_width + a], (a + 1) % 13 ? ' ' : '\n'); else @@ -469,6 +486,7 @@ void print_usage(void) "\t 3 Canonical 8-bit grayscale\n" "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n" "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n" + "\t 6 Greayscale iPod 4-grey\n" , APPLICATION_NAME); printf("build date: " __DATE__ "\n\n"); } @@ -483,7 +501,7 @@ int main(int argc, char **argv) struct RGBQUAD *bitmap = NULL; unsigned short *t_bitmap = NULL; int width, height; - int t_width, t_height; + int t_width, t_height, t_depth; for (i = 1;i < argc;i++) @@ -580,9 +598,9 @@ int main(int argc, char **argv) else { if (transform_bitmap(bitmap, width, height, format, &t_bitmap, - &t_width, &t_height)) + &t_width, &t_height, &t_depth)) exit(1); - generate_c_source(id, width, height, t_bitmap, t_width, t_height, format); + generate_c_source(id, width, height, t_bitmap, t_width, t_height, t_depth); } return 0; diff --git a/tools/configure b/tools/configure index 977465cbdb..03a94137e0 100755 --- a/tools/configure +++ b/tools/configure @@ -766,7 +766,7 @@ toolsdir='\$(ROOTDIR)/tools' arm7tdmicc tool="$rootdir/tools/scramble -add=ip3g" bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" - bmp2rb_native="$rootdir/tools/bmp2rb -f 2" + bmp2rb_native="$rootdir/tools/bmp2rb -f 6" output="rockbox.ipod" appextra="recorder:gui" archosrom="" @@ -785,7 +785,7 @@ toolsdir='\$(ROOTDIR)/tools' arm7tdmicc tool="$rootdir/tools/scramble -add=ip4g" bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" - bmp2rb_native="$rootdir/tools/bmp2rb -f 2" + bmp2rb_native="$rootdir/tools/bmp2rb -f 6" output="rockbox.ipod" appextra="recorder:gui" archosrom=""