summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2006-02-16 20:03:07 +0000
committerJens Arnold <amiconn@rockbox.org>2006-02-16 20:03:07 +0000
commit41e1aa888b9d1fc41aaf158191980cce3e548302 (patch)
tree2f04f7e5a6f93559defdf037b6b918eb44112ac3
parent7c64631792f5bb3bd804ff5880808d275be89a4d (diff)
downloadrockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.zip
rockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.tar.gz
rockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.tar.bz2
rockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.tar.xz
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
-rw-r--r--firmware/drivers/lcd-2bit-horz.c261
-rw-r--r--tools/bmp2rb.c40
-rwxr-xr-xtools/configure4
3 files changed, 219 insertions, 86 deletions
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 1045ba6..f9f5152 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)
+ {
+ 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
{
- lcd_hline (x, width, ny);
- ny++;
+ 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 61c0268..d50b8c6 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) */
+ case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
dst_w = width;
dst_h = height;
+ dst_d = 16;
break;
- case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
- dst_w = width;
+ 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 977465c..03a9413 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=""