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:
parent
7c64631792
commit
41e1aa888b
3 changed files with 221 additions and 88 deletions
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
4
tools/configure
vendored
4
tools/configure
vendored
|
@ -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=""
|
||||
|
|
Loading…
Reference in a new issue