diff options
Diffstat (limited to 'firmware/target/arm/iriver/h10/lcd-h10_5gb.c')
-rw-r--r-- | firmware/target/arm/iriver/h10/lcd-h10_5gb.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c index 4386e1670c..5e1ad9ce23 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c @@ -118,6 +118,168 @@ void lcd_init_device(void) /*** update functions ***/ +#define CSUB_X 2 +#define CSUB_Y 2 + +#define RYFAC (31*257) +#define GYFAC (31*257) +#define BYFAC (31*257) +#define RVFAC 11170 /* 31 * 257 * 1.402 */ +#define GVFAC (-5690) /* 31 * 257 * -0.714136 */ +#define GUFAC (-2742) /* 31 * 257 * -0.344136 */ +#define BUFAC 14118 /* 31 * 257 * 1.772 */ + +#define ROUNDOFFS (127*257) +#define ROUNDOFFSG (63*257) + +/* Performance function to blit a YUV bitmap directly to the LCD */ +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + int y0, x0, y1, x1; + int ymax; + + width = (width + 1) & ~1; + + /* calculate the drawing region */ + x0 = x; + x1 = x + width - 1; + y0 = y; + y1 = y + height - 1; + + /* max horiz << 8 | start horiz */ + lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0); + + /* max vert << 8 | start vert */ + lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0); + + /* start vert << 8 | start horiz */ + lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0); + + /* start drawing */ + lcd_send_cmd(R_WRITE_DATA_2_GRAM); + + ymax = y + height - 1 ; + + const int stride_div_csub_x = stride/CSUB_X; + + 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 int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + + (src_x/CSUB_X); + + const unsigned char *usrc = src[1] + uvoffset; + const unsigned char *vsrc = src[2] + uvoffset; + const unsigned char *row_end = ysrc + width; + + int y, u, v; + int red1, green1, blue1; + int red2, green2, blue2; + unsigned rbits, gbits, bbits; + + int rc, gc, bc; + + do + { + u = *usrc++ - 128; + v = *vsrc++ - 128; + rc = RVFAC * v + ROUNDOFFS; + gc = GVFAC * v + GUFAC * u + ROUNDOFFSG; + bc = BUFAC * u + ROUNDOFFS; + + /* Pixel 1 */ + y = *ysrc++; + + red1 = RYFAC * y + rc; + green1 = GYFAC * y + gc; + blue1 = BYFAC * y + bc; + + /* Pixel 2 */ + y = *ysrc++; + red2 = RYFAC * y + rc; + green2 = GYFAC * y + gc; + blue2 = BYFAC * y + bc; + + /* Since out of bounds errors are relatively rare, we check two + pixels at once to see if any components are out of bounds, and + then fix whichever is broken. This works due to high values and + negative values both becoming larger than the cutoff when + casted to unsigned. And ORing them together checks all of them + simultaneously. */ + if (((unsigned)(red1 | green1 | blue1 | + red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) { + if (((unsigned)(red1 | green1 | blue1)) > + (RYFAC*255+ROUNDOFFS)) { + if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS)) + { + if (red1 < 0) + red1 = 0; + else + red1 = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG)) + { + if (green1 < 0) + green1 = 0; + else + green1 = (GYFAC*255+ROUNDOFFSG); + } + if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS)) + { + if (blue1 < 0) + blue1 = 0; + else + blue1 = (BYFAC*255+ROUNDOFFS); + } + } + + if (((unsigned)(red2 | green2 | blue2)) > + (RYFAC*255+ROUNDOFFS)) { + if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS)) + { + if (red2 < 0) + red2 = 0; + else + red2 = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG)) + { + if (green2 < 0) + green2 = 0; + else + green2 = (GYFAC*255+ROUNDOFFSG); + } + if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS)) + { + if (blue2 < 0) + blue2 = 0; + else + blue2 = (BYFAC*255+ROUNDOFFS); + } + } + } + + rbits = red1 >> 16 ; + gbits = green1 >> 15 ; + bbits = blue1 >> 16 ; + lcd_send_data((rbits << 11) | (gbits << 5) | bbits); + + rbits = red2 >> 16 ; + gbits = green2 >> 15 ; + bbits = blue2 >> 16 ; + lcd_send_data((rbits << 11) | (gbits << 5) | bbits); + } + while (ysrc < row_end); + + src_y++; + } +} + + /* Update a fraction of the display. */ void lcd_update_rect(int x0, int y0, int width, int height) { |