From c5a309afbd60114a4cb8b7f758647f7a6af0a6bd Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Tue, 8 Aug 2006 13:44:43 +0000 Subject: H300: * Implemented lcd_yuv_blit(). Speeds up video playback by about 7%. No bounds check in lcd_yuv_blit() (by convention), implementations for other targets should be adapted. * Fixed off-by-one bug in lcd_update_rect() git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10484 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/lcd-h300.c | 141 ++++++++++++++++++++++++++++++++++++++++++-- firmware/export/lcd.h | 3 +- 2 files changed, 138 insertions(+), 6 deletions(-) (limited to 'firmware') diff --git a/firmware/drivers/lcd-h300.c b/firmware/drivers/lcd-h300.c index 0bdb123d41..c3f5d48f87 100644 --- a/firmware/drivers/lcd-h300.c +++ b/firmware/drivers/lcd-h300.c @@ -77,18 +77,20 @@ static int xoffset = 0; /* needed for flip */ #define R_HORIZ_RAM_ADDR_POS 0x44 #define R_VERT_RAM_ADDR_POS 0x45 +#define LCD_CMD (*(volatile unsigned short *)0xf0000000) +#define LCD_DATA (*(volatile unsigned short *)0xf0000002) /* called very frequently - inline! */ static inline void lcd_write_reg(int reg, int val) { - *(volatile unsigned short *)0xf0000000 = reg; - *(volatile unsigned short *)0xf0000002 = val; + LCD_CMD = reg; + LCD_DATA = val; } /* called very frequently - inline! */ static inline void lcd_begin_write_gram(void) { - *(volatile unsigned short *)0xf0000000 = R_WRITE_DATA_2_GRAM; + LCD_CMD = R_WRITE_DATA_2_GRAM; } /*** hardware configuration ***/ @@ -299,6 +301,135 @@ void lcd_blit(const fb_data* data, int x, int by, int width, /*if(display_on)*/ } +#define CSUB_X 2 +#define CSUB_Y 2 + +#define RYFAC (31*257) +#define GYFAC (63*257) +#define BYFAC (31*257) +#define RVFAC 11170 /* 31 * 257 * 1.402 */ +#define GVFAC (-11563) /* 63 * 257 * -0.714136 */ +#define GUFAC (-5572) /* 63 * 257 * -0.344136 */ +#define BUFAC 14118 /* 31 * 257 * 1.772 */ + +#define ROUNDOFFS (127*257) + +/* Performance function to blit a YUV bitmap directly to the LCD */ +void lcd_yuv_blit(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + if (display_on) + { + int ymax; + + width = (width + 1) & ~1; + height = (height + 1) & ~1; + ymax = y + height - 1; + + /* set update window */ + + /* horiz ram addr */ + lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax << 8) | y); + + /* vert ram addr */ + lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset)); + lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y); + lcd_begin_write_gram(); + + for (; y <= ymax; y++) + { + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + const unsigned char *ysrc = src[0] + stride * src_y + src_x; + const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + const unsigned char *row_end = ysrc + width; + + int y, u, v; + int rc, gc, bc; + int red, green, blue; + unsigned rbits, gbits, bbits; + + do + { + u = *usrc++ - 128; + v = *vsrc++ - 128; + rc = RVFAC * v + ROUNDOFFS; + gc = GVFAC * v + GUFAC * u + ROUNDOFFS; + bc = BUFAC * u + ROUNDOFFS; + + y = *ysrc++; + red = RYFAC * y + rc; + green = GYFAC * y + gc; + blue = BYFAC * y + bc; + + if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) + { + if (red < 0) + red = 0; + else + red = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) + { + if (green < 0) + green = 0; + else + green = (GYFAC*255+ROUNDOFFS); + } + if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) + { + if (blue < 0) + blue = 0; + else + blue = (BYFAC*255+ROUNDOFFS); + } + rbits = ((unsigned)red) >> 16 ; + gbits = ((unsigned)green) >> 16 ; + bbits = ((unsigned)blue) >> 16 ; + + LCD_DATA = (rbits << 11) | (gbits << 5) | bbits; + + y = *ysrc++; + red = RYFAC * y + rc; + green = GYFAC * y + gc; + blue = BYFAC * y + bc; + + if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) + { + if (red < 0) + red = 0; + else + red = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) + { + if (green < 0) + green = 0; + else + green = (GYFAC*255+ROUNDOFFS); + } + if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) + { + if (blue < 0) + blue = 0; + else + blue = (BYFAC*255+ROUNDOFFS); + } + rbits = ((unsigned)red) >> 16 ; + gbits = ((unsigned)green) >> 16 ; + bbits = ((unsigned)blue) >> 16 ; + + LCD_DATA = (rbits << 11) | (gbits << 5) | bbits; + } + while (ysrc < row_end); + + src_y++; + } + } +} /* Update the display. This must be called after all other LCD functions that change the display. */ @@ -324,8 +455,8 @@ void lcd_update(void) void lcd_update_rect(int, int, int, int) ICODE_ATTR; void lcd_update_rect(int x, int y, int width, int height) { - if(display_on) { - int ymax = y + height; + if(display_on) { + int ymax = y + height - 1; if(x + width > LCD_WIDTH) width = LCD_WIDTH - x; diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 32a958af2a..7551a1ab23 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -71,7 +71,8 @@ extern void lcd_puts_scroll_style(int x, int y, const unsigned char* string, int style); extern void lcd_icon(int icon, bool enable); -#if CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO +#if CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO \ + || CONFIG_LCD == LCD_H300 void lcd_yuv_blit(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height); -- cgit v1.2.3