summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2009-03-08 17:22:17 +0000
committerJens Arnold <amiconn@rockbox.org>2009-03-08 17:22:17 +0000
commit9eeead922ad958cae62015eec8156e47ca47fc58 (patch)
treef920b48878aae27cf77f301396eb811d9e8a187a
parent87d1744e91e016b650a3c7826a93cd6afcaf0383 (diff)
downloadrockbox-9eeead922ad958cae62015eec8156e47ca47fc58.tar.gz
rockbox-9eeead922ad958cae62015eec8156e47ca47fc58.zip
Optimize hline, fillrect and mono bitmap drawing for chunky displays (16 bit colour and greylib). Speeds up text rendering by 20..45% on colour coldfire, by 30..50% on colour ARM, and is noticeable in archos pictureflow.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20242 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/lib/grey_draw.c160
-rw-r--r--firmware/drivers/lcd-16bit.c193
2 files changed, 246 insertions, 107 deletions
diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c
index 286cae06a4..65f2211b7f 100644
--- a/apps/plugins/lib/grey_draw.c
+++ b/apps/plugins/lib/grey_draw.c
@@ -155,8 +155,7 @@ void grey_hline(int x1, int x2, int y)
int value = 0;
unsigned char *dst;
bool fillopt = false;
- void (*pfunc)(unsigned char *address);
-
+
/* direction flip */
if (x2 < x1)
{
@@ -170,12 +169,7 @@ void grey_hline(int x1, int x2, int y)
|| (x1 >= _grey_info.width) || (x2 < 0))
return;
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= _grey_info.width)
- x2 = _grey_info.width - 1;
-
+ /* drawmode and optimisation */
if (_grey_info.drawmode & DRMODE_INVERSEVID)
{
if (_grey_info.drawmode & DRMODE_BG)
@@ -192,17 +186,25 @@ void grey_hline(int x1, int x2, int y)
value = _grey_info.fg_brightness;
}
}
- pfunc = _grey_pixelfuncs[_grey_info.drawmode];
+ if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT)
+ return;
+
+ /* clipping */
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 >= _grey_info.width)
+ x2 = _grey_info.width - 1;
+
dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x1];
if (fillopt)
rb->memset(dst, value, x2 - x1 + 1);
- else
+ else /* DRMODE_COMPLEMENT */
{
unsigned char *dst_end = dst + x2 - x1;
do
- pfunc(dst++);
- while (dst <= dst_end);
+ *dst = ~(*dst);
+ while (++dst <= dst_end);
}
}
@@ -335,29 +337,13 @@ void grey_fillrect(int x, int y, int width, int height)
int value = 0;
unsigned char *dst, *dst_end;
bool fillopt = false;
- void (*pfunc)(unsigned char *address);
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
|| (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
return;
- /* clipping */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > _grey_info.width)
- width = _grey_info.width - x;
- if (y + height > _grey_info.height)
- height = _grey_info.height - y;
-
+ /* drawmode and optimisation */
if (_grey_info.drawmode & DRMODE_INVERSEVID)
{
if (_grey_info.drawmode & DRMODE_BG)
@@ -374,7 +360,25 @@ void grey_fillrect(int x, int y, int width, int height)
value = _grey_info.fg_brightness;
}
}
- pfunc = _grey_pixelfuncs[_grey_info.drawmode];
+ if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT)
+ return;
+
+ /* clipping */
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ height += y;
+ y = 0;
+ }
+ if (x + width > _grey_info.width)
+ width = _grey_info.width - x;
+ if (y + height > _grey_info.height)
+ height = _grey_info.height - y;
+
dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x];
dst_end = dst + _GREY_MULUQ(_grey_info.width, height);
@@ -382,14 +386,14 @@ void grey_fillrect(int x, int y, int width, int height)
{
if (fillopt)
rb->memset(dst, value, width);
- else
+ else /* DRMODE_COMPLEMENT */
{
unsigned char *dst_row = dst;
unsigned char *row_end = dst_row + width;
do
- pfunc(dst_row++);
- while (dst_row < row_end);
+ *dst_row = ~(*dst_row);
+ while (++dst_row < row_end);
}
dst += _grey_info.width;
}
@@ -411,8 +415,9 @@ void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
{
const unsigned char *src_end;
unsigned char *dst, *dst_end;
- void (*fgfunc)(unsigned char *address);
- void (*bgfunc)(unsigned char *address);
+ unsigned dmask = 0x100; /* bit 8 == sentinel */
+ int drmode = _grey_info.drawmode;
+ int dwidth;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
@@ -440,37 +445,84 @@ void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src += _GREY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
+ dwidth = _grey_info.width;
+ dst = &_grey_info.buffer[_GREY_MULUQ(dwidth, y) + x];
- fgfunc = _grey_pixelfuncs[_grey_info.drawmode];
- bgfunc = _grey_pixelfuncs[_grey_info.drawmode ^ DRMODE_INVERSEVID];
- dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x];
+ if (drmode & DRMODE_INVERSEVID)
+ {
+ dmask = 0x1ff; /* bit 8 == sentinel */
+ drmode &= DRMODE_SOLID; /* mask out inversevid */
+ }
do
{
const unsigned char *src_col = src++;
unsigned char *dst_col = dst++;
- unsigned data = *src_col >> src_y;
- int numbits = 8 - src_y;
+ unsigned data = (*src_col ^ dmask) >> src_y;
+ int fg, bg;
+
+ dst_end = dst_col + _GREY_MULUQ(dwidth, height);
- dst_end = dst_col + _GREY_MULUQ(_grey_info.width, height);
- do
+#define UPDATE_SRC do { \
+ data >>= 1; \
+ if (data == 0x001) { \
+ src_col += stride; \
+ data = *src_col ^ dmask; \
+ } \
+ } while (0)
+
+ switch (drmode)
{
- if (data & 0x01)
- fgfunc(dst_col);
- else
- bgfunc(dst_col);
+ case DRMODE_COMPLEMENT:
+ do
+ {
+ if (data & 0x01)
+ *dst_col = ~(*dst_col);
- dst_col += _grey_info.width;
+ dst_col += dwidth;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ break;
- data >>= 1;
- if (--numbits == 0)
+ case DRMODE_BG:
+ bg = _grey_info.bg_brightness;
+ do
{
- src_col += stride;
- data = *src_col;
- numbits = 8;
+ if (!(data & 0x01))
+ *dst_col = bg;
+
+ dst_col += dwidth;
+ UPDATE_SRC;
}
+ while (dst_col < dst_end);
+ break;
+
+ case DRMODE_FG:
+ fg = _grey_info.fg_brightness;
+ do
+ {
+ if (data & 0x01)
+ *dst_col = fg;
+
+ dst_col += dwidth;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ break;
+
+ case DRMODE_SOLID:
+ fg = _grey_info.fg_brightness;
+ bg = _grey_info.bg_brightness;
+ do
+ {
+ *dst_col = (data & 0x01) ? fg : bg;
+ dst_col += dwidth;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ break;
}
- while (dst_col < dst_end);
}
while (src < src_end);
}
@@ -491,7 +543,7 @@ void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
|| (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
return;
-
+
/* clipping */
if (x < 0)
{
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index 9b700a0669..c3e076b392 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -428,7 +428,6 @@ void lcd_hline(int x1, int x2, int y)
unsigned bits = 0;
enum fill_opt fillopt = OPT_NONE;
fb_data *dst, *dst_end;
- lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
/* direction flip */
if (x2 < x1)
@@ -444,18 +443,7 @@ void lcd_hline(int x1, int x2, int y)
(x2 < 0))
return;
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= current_vp->width)
- x2 = current_vp->width-1;
-
- width = x2 - x1 + 1;
-
- /* Adjust x1 and y to viewport */
- x1 += current_vp->x;
- y += current_vp->y;
-
+ /* drawmode and optimisation */
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (current_vp->drawmode & DRMODE_BG)
@@ -477,6 +465,21 @@ void lcd_hline(int x1, int x2, int y)
bits = current_vp->fg_pattern;
}
}
+ if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
+ return;
+
+ /* clipping */
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 >= current_vp->width)
+ x2 = current_vp->width-1;
+
+ width = x2 - x1 + 1;
+
+ /* Adjust x1 and y to viewport */
+ x1 += current_vp->x;
+ y += current_vp->y;
+
dst = LCDADDR(x1, y);
switch (fillopt)
@@ -490,11 +493,11 @@ void lcd_hline(int x1, int x2, int y)
width * sizeof(fb_data));
break;
- case OPT_NONE:
+ case OPT_NONE: /* DRMODE_COMPLEMENT */
dst_end = dst + width;
do
- pfunc(dst++);
- while (dst < dst_end);
+ *dst = ~(*dst);
+ while (++dst < dst_end);
break;
}
}
@@ -558,29 +561,13 @@ void lcd_fillrect(int x, int y, int width, int height)
unsigned bits = 0;
enum fill_opt fillopt = OPT_NONE;
fb_data *dst, *dst_end;
- lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
- /* clipping */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > current_vp->width)
- width = current_vp->width - x;
- if (y + height > current_vp->height)
- height = current_vp->height - y;
-
+ /* drawmode and optimisation */
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (current_vp->drawmode & DRMODE_BG)
@@ -602,6 +589,25 @@ void lcd_fillrect(int x, int y, int width, int height)
bits = current_vp->fg_pattern;
}
}
+ if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
+ return;
+
+ /* clipping */
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ height += y;
+ y = 0;
+ }
+ if (x + width > current_vp->width)
+ width = current_vp->width - x;
+ if (y + height > current_vp->height)
+ height = current_vp->height - y;
+
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
dst_end = dst + height * LCD_WIDTH;
@@ -620,12 +626,12 @@ void lcd_fillrect(int x, int y, int width, int height)
width * sizeof(fb_data));
break;
- case OPT_NONE:
+ case OPT_NONE: /* DRMODE_COMPLEMENT */
dst_row = dst;
row_end = dst_row + width;
do
- pfunc(dst_row++);
- while (dst_row < row_end);
+ *dst_row = ~(*dst_row);
+ while (++dst_row < row_end);
break;
}
dst += LCD_WIDTH;
@@ -717,7 +723,8 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
{
const unsigned char *src_end;
fb_data *dst, *dst_end;
- lcd_fastpixelfunc_type *fgfunc, *bgfunc;
+ unsigned dmask = 0x100; /* bit 8 == sentinel */
+ int drmode = current_vp->drawmode;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
@@ -745,35 +752,115 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
-
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
- fgfunc = lcd_fastpixelfuncs[current_vp->drawmode];
- bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
+
+ if (drmode & DRMODE_INVERSEVID)
+ {
+ dmask = 0x1ff; /* bit 8 == sentinel */
+ drmode &= DRMODE_SOLID; /* mask out inversevid */
+ }
+
do
{
const unsigned char *src_col = src++;
- unsigned data = *src_col >> src_y;
+ unsigned data = (*src_col ^ dmask) >> src_y;
fb_data *dst_col = dst++;
- int numbits = 8 - src_y;
+ int fg, bg;
+ long bo;
+
dst_end = dst_col + height * LCD_WIDTH;
- do
+
+#define UPDATE_SRC do { \
+ data >>= 1; \
+ if (data == 0x001) { \
+ src_col += stride; \
+ data = *src_col ^ dmask; \
+ } \
+ } while (0)
+
+ switch (drmode)
{
- if (data & 0x01)
- fgfunc(dst_col);
+ case DRMODE_COMPLEMENT:
+ do
+ {
+ if (data & 0x01)
+ *dst_col = ~(*dst_col);
+
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ break;
+
+ case DRMODE_BG:
+ if (lcd_backdrop)
+ {
+ bo = lcd_backdrop_offset;
+ do
+ {
+ if (!(data & 0x01))
+ *dst_col = *(fb_data *)((long)dst_col + bo);
+
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ }
else
- bgfunc(dst_col);
+ {
+ bg = current_vp->bg_pattern;
+ do
+ {
+ if (!(data & 0x01))
+ *dst_col = bg;
+
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ }
+ break;
- dst_col += LCD_WIDTH;
+ case DRMODE_FG:
+ fg = current_vp->fg_pattern;
+ do
+ {
+ if (data & 0x01)
+ *dst_col = fg;
- data >>= 1;
- if (--numbits == 0)
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ break;
+
+ case DRMODE_SOLID:
+ fg = current_vp->fg_pattern;
+ if (lcd_backdrop)
{
- src_col += stride;
- data = *src_col;
- numbits = 8;
+ bo = lcd_backdrop_offset;
+ do
+ {
+ *dst_col = (data & 0x01) ? fg
+ : *(fb_data *)((long)dst_col + bo);
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
}
+ else
+ {
+ bg = current_vp->bg_pattern;
+ do
+ {
+ *dst_col = (data & 0x01) ? fg : bg;
+ dst_col += LCD_WIDTH;
+ UPDATE_SRC;
+ }
+ while (dst_col < dst_end);
+ }
+ break;
}
- while (dst_col < dst_end);
}
while (src < src_end);
}