From 5365cbe0a5af0ef357e7fc70e793141ccd38f23e Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Mon, 26 Oct 2009 01:35:31 +0000 Subject: Color targets: Ported assembler optimised transparent bitmap drawing from Gigabeat S/F/X to all ARM targets (~23..40% speedup). * C optimised transparent bitmap drawing for non-ARM targets and sims. * Use the more compact boundary checking for non-transparent native bitmap drawing as well. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23353 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/lcd-16bit.c | 119 +++++++++++++++-------- firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c | 63 ------------ firmware/target/arm/s3c2440/lcd-s3c2440.c | 65 ------------- 3 files changed, 80 insertions(+), 167 deletions(-) diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index d1b417a00a..cee6c2aeef 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -788,34 +788,36 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y, int stride, int x, int y, int width, int height) { - fb_data *dst, *dst_end; + fb_data *dst; - /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || - (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) - return; + if (x + width > current_vp->width) + width = current_vp->width - x; /* Clip right */ - /* clipping */ - if (x < 0) + if (x < 0) /* Clip left */ { width += x; src_x -= x; x = 0; } - if (y < 0) + + if (width <= 0) + return; /* nothing left to do */ + + if (y + height > current_vp->height) + height = current_vp->height - y; /* Clip bottom */ + + if (y < 0) /* Clip top */ { height += y; src_y -= 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; + + if (height <= 0) + return; /* nothing left to do */ src += stride * src_y + src_x; /* move starting point */ dst = LCDADDR(current_vp->x + x, current_vp->y + y); - dst_end = dst + height * LCD_WIDTH; do { @@ -823,7 +825,7 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y, src += stride; dst += LCD_WIDTH; } - while (dst < dst_end); + while (--height > 0); } /* Draw a full native bitmap */ @@ -832,60 +834,99 @@ void lcd_bitmap(const fb_data *src, int x, int y, int width, int height) lcd_bitmap_part(src, 0, 0, width, x, y, width, height); } -#if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \ - || defined(SIMULATOR) -/* Draw a partial native bitmap */ +/* Draw a partial native bitmap with transparency and foreground colors */ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, int stride, int x, int y, int width, int height) { - fb_data *dst, *dst_end; + fb_data *dst; + unsigned fg = current_vp->fg_pattern; - /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || - (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) - return; + if (x + width > current_vp->width) + width = current_vp->width - x; /* Clip right */ - /* clipping */ - if (x < 0) + if (x < 0) /* Clip left */ { width += x; src_x -= x; x = 0; } - if (y < 0) + + if (width <= 0) + return; /* nothing left to do */ + + if (y + height > current_vp->height) + height = current_vp->height - y; /* Clip bottom */ + + if (y < 0) /* Clip top */ { height += y; src_y -= 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; + + if (height <= 0) + return; /* nothing left to do */ src += stride * src_y + src_x; /* move starting point */ dst = LCDADDR(current_vp->x + x, current_vp->y + y); - dst_end = dst + height * LCD_WIDTH; +#ifdef CPU_ARM + { + int w, px; + asm volatile ( + ".rowstart: \n" + "mov %[w], %[width] \n" /* Load width for inner loop */ + ".nextpixel: \n" + "ldrh %[px], [%[s]], #2 \n" /* Load src pixel */ + "add %[d], %[d], #2 \n" /* Uncoditionally increment dst */ + /* done here for better pipelining */ + "cmp %[px], %[fgcolor] \n" /* Compare to foreground color */ + "streqh %[fgpat], [%[d], #-2] \n" /* Store foregroud if match */ + "cmpne %[px], %[transcolor] \n" /* Compare to transparent color */ + "strneh %[px], [%[d], #-2] \n" /* Store dst if not transparent */ + "subs %[w], %[w], #1 \n" /* Width counter has run down? */ + "bgt .nextpixel \n" /* More in this row? */ + "add %[s], %[s], %[sstp], lsl #1 \n" /* Skip over to start of next line */ + "add %[d], %[d], %[dstp], lsl #1 \n" + "subs %[h], %[h], #1 \n" /* Height counter has run down? */ + "bgt .rowstart \n" /* More rows? */ + : [w]"=&r"(w), [h]"+&r"(height), [px]"=&r"(px), + [s]"+&r"(src), [d]"+&r"(dst) + : [width]"r"(width), + [sstp]"r"(stride - width), + [dstp]"r"(LCD_WIDTH - width), + [transcolor]"r"(TRANSPARENT_COLOR), + [fgcolor]"r"(REPLACEWITHFG_COLOR), + [fgpat]"r"(fg) + ); + } +#else /* optimized C version */ do { - int i; - for(i = 0;i < width;i++) + const fb_data *src_row = src; + fb_data *dst_row = dst; + fb_data *row_end = dst_row + width; + do { - if (src[i] == REPLACEWITHFG_COLOR) - dst[i] = current_vp->fg_pattern; - else if(src[i] != TRANSPARENT_COLOR) - dst[i] = src[i]; + unsigned data = *src_row++; + if (data != TRANSPARENT_COLOR) + { + if (data == REPLACEWITHFG_COLOR) + *dst_row = fg; + else + *dst_row = data; + } } + while (++dst_row < row_end); src += stride; dst += LCD_WIDTH; } - while (dst < dst_end); + while (--height > 0); +#endif } -#endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */ -/* Draw a full native bitmap with a transparent color */ +/* Draw a full native bitmap with transparent and foreground colors */ void lcd_bitmap_transparent(const fb_data *src, int x, int y, int width, int height) { diff --git a/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c b/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c index fa1aed0fd6..ea3bfaf519 100644 --- a/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c @@ -146,69 +146,6 @@ void lcd_update(void) LCD_WIDTH*LCD_HEIGHT, 1); } -void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, - int stride, int x, int y, int width, - int height) -{ - int w, px; - fb_data *dst; - - if (x + width > current_vp->width) - width = current_vp->width - x; /* Clip right */ - - if (x < 0) /* Clip left */ - { - width += x; - src_x -= x; - x = 0; - } - - if (width <= 0) - return; /* nothing left to do */ - - if (y + height > current_vp->height) - height = current_vp->height - y; /* Clip bottom */ - - if (y < 0) /* Clip top */ - { - height += y; - src_y -= y; - y = 0; - } - - if (height <= 0) - return; /* nothing left to do */ - - src += stride * src_y + src_x; /* move starting point */ - dst = &lcd_framebuffer[current_vp->y+y][current_vp->x+x]; - - asm volatile ( - ".rowstart: \r\n" - "mov %[w], %[width] \r\n" /* Load width for inner loop */ - ".nextpixel: \r\n" - "ldrh %[px], [%[s]], #2 \r\n" /* Load src pixel */ - "add %[d], %[d], #2 \r\n" /* Uncoditionally increment dst */ - "cmp %[px], %[fgcolor] \r\n" /* Compare to foreground color */ - "streqh %[fgpat], [%[d], #-2] \r\n" /* Store foregroud if match */ - "cmpne %[px], %[transcolor] \r\n" /* Compare to transparent color */ - "strneh %[px], [%[d], #-2] \r\n" /* Store dst if not transparent */ - "subs %[w], %[w], #1 \r\n" /* Width counter has run down? */ - "bgt .nextpixel \r\n" /* More in this row? */ - "add %[s], %[s], %[sstp], lsl #1 \r\n" /* Skip over to start of next line */ - "add %[d], %[d], %[dstp], lsl #1 \r\n" - "subs %[h], %[h], #1 \r\n" /* Height counter has run down? */ - "bgt .rowstart \r\n" /* More rows? */ - : [w]"=&r"(w), [h]"+&r"(height), [px]"=&r"(px), - [s]"+&r"(src), [d]"+&r"(dst) - : [width]"r"(width), - [sstp]"r"(stride - width), - [dstp]"r"(LCD_WIDTH - width), - [transcolor]"r"(TRANSPARENT_COLOR), - [fgcolor]"r"(REPLACEWITHFG_COLOR), - [fgpat]"r"(current_vp->fg_pattern) - ); -} - void lcd_yuv_set_options(unsigned options) { lcd_yuv_options = options; diff --git a/firmware/target/arm/s3c2440/lcd-s3c2440.c b/firmware/target/arm/s3c2440/lcd-s3c2440.c index d702b5713a..4a4674e87f 100644 --- a/firmware/target/arm/s3c2440/lcd-s3c2440.c +++ b/firmware/target/arm/s3c2440/lcd-s3c2440.c @@ -455,71 +455,6 @@ void lcd_update(void) LCD_WIDTH*LCD_HEIGHT, 1); } -#if defined(TOSHIBA_GIGABEAT_F) || defined(TOSHIBA_GIGABEAT_S) -void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, - int stride, int x, int y, int width, - int height) -{ - int w, px; - fb_data *dst; - - if (x + width > current_vp->width) - width = current_vp->width - x; /* Clip right */ - - if (x < 0) /* Clip left */ - { - width += x; - src_x -= x; - x = 0; - } - - if (width <= 0) - return; /* nothing left to do */ - - if (y + height > current_vp->height) - height = current_vp->height - y; /* Clip bottom */ - - if (y < 0) /* Clip top */ - { - height += y; - src_y -= y; - y = 0; - } - - if (height <= 0) - return; /* nothing left to do */ - - src += stride * src_y + src_x; /* move starting point */ - dst = &lcd_framebuffer[current_vp->y+y][current_vp->x+x]; - - asm volatile ( - ".rowstart: \r\n" - "mov %[w], %[width] \r\n" /* Load width for inner loop */ - ".nextpixel: \r\n" - "ldrh %[px], [%[s]], #2 \r\n" /* Load src pixel */ - "add %[d], %[d], #2 \r\n" /* Uncoditionally increment dst */ - "cmp %[px], %[fgcolor] \r\n" /* Compare to foreground color */ - "streqh %[fgpat], [%[d], #-2] \r\n" /* Store foregroud if match */ - "cmpne %[px], %[transcolor] \r\n" /* Compare to transparent color */ - "strneh %[px], [%[d], #-2] \r\n" /* Store dst if not transparent */ - "subs %[w], %[w], #1 \r\n" /* Width counter has run down? */ - "bgt .nextpixel \r\n" /* More in this row? */ - "add %[s], %[s], %[sstp], lsl #1 \r\n" /* Skip over to start of next line */ - "add %[d], %[d], %[dstp], lsl #1 \r\n" - "subs %[h], %[h], #1 \r\n" /* Height counter has run down? */ - "bgt .rowstart \r\n" /* More rows? */ - : [w]"=&r"(w), [h]"+&r"(height), [px]"=&r"(px), - [s]"+&r"(src), [d]"+&r"(dst) - : [width]"r"(width), - [sstp]"r"(stride - width), - [dstp]"r"(LCD_WIDTH - width), - [transcolor]"r"(TRANSPARENT_COLOR), - [fgcolor]"r"(REPLACEWITHFG_COLOR), - [fgpat]"r"(current_vp->fg_pattern) - ); -} -#endif - void lcd_yuv_set_options(unsigned options) { lcd_yuv_options = options; -- cgit v1.2.3