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
This commit is contained in:
Jens Arnold 2006-02-16 20:03:07 +00:00
parent 7c64631792
commit 41e1aa888b
3 changed files with 221 additions and 88 deletions

View file

@ -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 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;
bfunc = lcd_blockfuncs[drawmode];
dst = &lcd_framebuffer[y1][x>>2];
mask = pixmask[x & 3];
while(y1++ <= y2) {
pfunc(x, y1);
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 */
nx = x;
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));
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);
data |= *src_row++ << shift;
ny++;
data >>= 2;
if (--numbits == 0)
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 */

View file

@ -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;

4
tools/configure vendored
View file

@ -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=""