summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/iriver/h10/lcd-h10_5gb.c')
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_5gb.c162
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)
{