summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c')
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c131
1 files changed, 21 insertions, 110 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
index 071b68fde3..d1c41d652f 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
@@ -400,48 +400,21 @@ void lcd_update_rect(int x, int y, int width, int height)
400 } 400 }
401} 401}
402 402
403/*** update functions ***/ 403/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
404 404extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
405#define CSUB_X 2 405 unsigned lcd_baseadress,
406#define CSUB_Y 2 406 int width,
407 407 int stride);
408/* YUV- > RGB565 conversion
409 * |R| |1.000000 -0.000001 1.402000| |Y'|
410 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
411 * |B| |1.000000 1.772000 0.000000| |Pr|
412 * Scaled, normalized, rounded and tweaked to yield RGB 565:
413 * |R| |74 0 101| |Y' - 16| >> 9
414 * |G| = |74 -24 -51| |Cb - 128| >> 8
415 * |B| |74 128 0| |Cr - 128| >> 9
416*/
417 408
418#define RGBYFAC 74 /* 1.0 */ 409/* Blit a YUV bitmap directly to the LCD */
419#define RVFAC 101 /* 1.402 */
420#define GVFAC (-51) /* -0.714136 */
421#define GUFAC (-24) /* -0.334136 */
422#define BUFAC 128 /* 1.772 */
423
424/* ROUNDOFFS contain constant for correct round-offs as well as
425 constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC
426 -> constant part = -16*RGBYFAC). Through extraction of these
427 constant parts we save at leat 4 substractions in the conversion
428 loop */
429#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC)
430#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC)
431#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC)
432
433#define MAX_5BIT 0x1f
434#define MAX_6BIT 0x3f
435
436/* Performance function to blit a YUV bitmap directly to the LCD */
437void lcd_blit_yuv(unsigned char * const src[3], 410void lcd_blit_yuv(unsigned char * const src[3],
438 int src_x, int src_y, int stride, 411 int src_x, int src_y, int stride,
439 int x, int y, int width, int height) 412 int x, int y, int width, int height)
440{ 413{
441 int h; 414 unsigned int z, y0, x0, y1, x1;;
442 int y0, x0, y1, x1; 415 unsigned char const * yuv_src[3];
443 416
444 width = (width + 1) & ~1; 417 width = (width + 1) & ~1; /* ensure width is even */
445 418
446 x0 = x; /* start horiz */ 419 x0 = x; /* start horiz */
447 y0 = y; /* start vert */ 420 y0 = y; /* start vert */
@@ -471,79 +444,17 @@ void lcd_blit_yuv(unsigned char * const src[3],
471 s5l_lcd_write_cmd(R_MEMORY_WRITE); 444 s5l_lcd_write_cmd(R_MEMORY_WRITE);
472 } 445 }
473 446
474 const int stride_div_csub_x = stride/CSUB_X; 447 z = stride * src_y;
475 448 yuv_src[0] = src[0] + z + src_x;
476 h = height; 449 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
477 while (h > 0) { 450 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
478 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
479 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
480
481 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
482 (src_x/CSUB_X);
483 451
484 const unsigned char *usrc = src[1] + uvoffset; 452 height >>= 1;
485 const unsigned char *vsrc = src[2] + uvoffset;
486 const unsigned char *row_end = ysrc + width;
487 453
488 int yp, up, vp; 454 do {
489 int red1, green1, blue1; 455 lcd_write_yuv420_lines(yuv_src, LCD_BASE, width, stride);
490 int red2, green2, blue2; 456 yuv_src[0] += stride << 1;
491 457 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
492 int rc, gc, bc; 458 yuv_src[2] += stride >> 1;
493 459 } while (--height > 0);
494 do
495 {
496 up = *usrc++;
497 vp = *vsrc++;
498 rc = RVFAC * vp + ROUNDOFFSR;
499 gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG;
500 bc = BUFAC * up + ROUNDOFFSB;
501
502 /* Pixel 1 -> RGB565 */
503 yp = *ysrc++ * RGBYFAC;
504 red1 = (yp + rc) >> 9;
505 green1 = (yp + gc) >> 8;
506 blue1 = (yp + bc) >> 9;
507
508 /* Pixel 2 -> RGB565 */
509 yp = *ysrc++ * RGBYFAC;
510 red2 = (yp + rc) >> 9;
511 green2 = (yp + gc) >> 8;
512 blue2 = (yp + bc) >> 9;
513
514 /* Since out of bounds errors are relatively rare, we check two
515 pixels at once to see if any components are out of bounds, and
516 then fix whichever is broken. This works due to high values and
517 negative values both being !=0 when bitmasking them.
518 We first check for red and blue components (5bit range). */
519 if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT)
520 {
521 if (red1 & ~MAX_5BIT)
522 red1 = (red1 >> 31) ? 0 : MAX_5BIT;
523 if (blue1 & ~MAX_5BIT)
524 blue1 = (blue1 >> 31) ? 0 : MAX_5BIT;
525 if (red2 & ~MAX_5BIT)
526 red2 = (red2 >> 31) ? 0 : MAX_5BIT;
527 if (blue2 & ~MAX_5BIT)
528 blue2 = (blue2 >> 31) ? 0 : MAX_5BIT;
529 }
530 /* We second check for green component (6bit range) */
531 if ((green1 | green2) & ~MAX_6BIT)
532 {
533 if (green1 & ~MAX_6BIT)
534 green1 = (green1 >> 31) ? 0 : MAX_6BIT;
535 if (green2 & ~MAX_6BIT)
536 green2 = (green2 >> 31) ? 0 : MAX_6BIT;
537 }
538
539 /* output 2 pixels */
540 while (LCD_STATUS & 0x08); /* wait while FIFO is half full */
541 lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1);
542 lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2);
543 }
544 while (ysrc < row_end);
545
546 src_y++;
547 h--;
548 }
549} 460}