From 9eeead922ad958cae62015eec8156e47ca47fc58 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 8 Mar 2009 17:22:17 +0000 Subject: 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 --- apps/plugins/lib/grey_draw.c | 160 +++++++++++++++++++++++------------ firmware/drivers/lcd-16bit.c | 193 +++++++++++++++++++++++++++++++------------ 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); } -- cgit v1.2.3