diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-01-26 14:24:09 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-01-26 14:24:09 +0000 |
commit | f8709ac7e25386017cee762666c12e2ac6d71a7a (patch) | |
tree | e97c4ff4731ca151e20e55c9953be02a540d3bf0 /firmware/target/arm/iriver/h10/lcd-h10_20gb.c | |
parent | 9542471f7d166458a31220a33e4bd53769a695fc (diff) | |
download | rockbox-f8709ac7e25386017cee762666c12e2ac6d71a7a.tar.gz rockbox-f8709ac7e25386017cee762666c12e2ac6d71a7a.zip |
H10 20GB: Assembly YUV blitting and dithering.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16171 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/iriver/h10/lcd-h10_20gb.c')
-rw-r--r-- | firmware/target/arm/iriver/h10/lcd-h10_20gb.c | 203 |
1 files changed, 58 insertions, 145 deletions
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c index 2c527fa4d9..892adffea9 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c | |||
@@ -34,6 +34,8 @@ static unsigned short disp_control_rev; | |||
34 | /* Contrast setting << 8 */ | 34 | /* Contrast setting << 8 */ |
35 | static int lcd_contrast; | 35 | static int lcd_contrast; |
36 | 36 | ||
37 | static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0; | ||
38 | |||
37 | /* Forward declarations */ | 39 | /* Forward declarations */ |
38 | static void lcd_display_off(void); | 40 | static void lcd_display_off(void); |
39 | 41 | ||
@@ -166,8 +168,6 @@ void lcd_set_flip(bool yesno) | |||
166 | lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000); | 168 | lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000); |
167 | /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */ | 169 | /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */ |
168 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113); | 170 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113); |
169 | /* HEA7-0=0xxx, HSA7-0=0xxx */ | ||
170 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00); | ||
171 | } | 171 | } |
172 | 172 | ||
173 | /* LCD init */ | 173 | /* LCD init */ |
@@ -239,8 +239,8 @@ static void lcd_power_on(void) | |||
239 | lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); | 239 | lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); |
240 | /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */ | 240 | /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */ |
241 | lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00); | 241 | lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00); |
242 | /* HEA7-0=0xxx, HSA7-0=0xxx */ | 242 | /* HEA7-0=7f, HSA7-0=00 */ |
243 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00); | 243 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00); |
244 | /* PKP12-10=0x0, PKP02-00=0x0 */ | 244 | /* PKP12-10=0x0, PKP02-00=0x0 */ |
245 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003); | 245 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003); |
246 | /* PKP32-30=0x4, PKP22-20=0x0 */ | 246 | /* PKP32-30=0x4, PKP22-20=0x0 */ |
@@ -395,177 +395,91 @@ void lcd_blit(const fb_data* data, int x, int by, int width, | |||
395 | (void)stride; | 395 | (void)stride; |
396 | } | 396 | } |
397 | 397 | ||
398 | #define CSUB_X 2 | 398 | void lcd_yuv_set_options(unsigned options) |
399 | #define CSUB_Y 2 | 399 | { |
400 | 400 | lcd_yuv_options = options; | |
401 | #define RYFAC (31*257) | 401 | } |
402 | #define GYFAC (31*257) | ||
403 | #define BYFAC (31*257) | ||
404 | #define RVFAC 11170 /* 31 * 257 * 1.402 */ | ||
405 | #define GVFAC (-5690) /* 31 * 257 * -0.714136 */ | ||
406 | #define GUFAC (-2742) /* 31 * 257 * -0.344136 */ | ||
407 | #define BUFAC 14118 /* 31 * 257 * 1.772 */ | ||
408 | 402 | ||
409 | #define ROUNDOFFS (127*257) | 403 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ |
410 | #define ROUNDOFFSG (63*257) | 404 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], |
405 | int width, | ||
406 | int stride); | ||
407 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
408 | int width, | ||
409 | int stride, | ||
410 | int x_screen, /* To align dither pattern */ | ||
411 | int y_screen); | ||
411 | 412 | ||
412 | /* Performance function to blit a YUV bitmap directly to the LCD */ | 413 | /* Performance function to blit a YUV bitmap directly to the LCD */ |
413 | void lcd_yuv_blit(unsigned char * const src[3], | 414 | void lcd_yuv_blit(unsigned char * const src[3], |
414 | int src_x, int src_y, int stride, | 415 | int src_x, int src_y, int stride, |
415 | int x, int y, int width, int height) | 416 | int x, int y, int width, int height) |
416 | { | 417 | { |
417 | int y0, x0, y1, x1; | 418 | const unsigned char *yuv_src[3]; |
418 | int ymax; | 419 | const unsigned char *ysrc_max; |
420 | int y0; | ||
421 | int options; | ||
419 | 422 | ||
420 | if (!display_on) | 423 | if (!display_on) |
421 | return; | 424 | return; |
422 | 425 | ||
423 | width = (width + 1) & ~1; | 426 | width &= ~1; |
427 | height &= ~1; | ||
424 | 428 | ||
425 | /* calculate the drawing region */ | 429 | /* calculate the drawing region */ |
426 | x0 = x; | ||
427 | x1 = x + width - 1; | ||
428 | y0 = y; | ||
429 | y1 = y + height - 1; | ||
430 | 430 | ||
431 | /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin | 431 | /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin |
432 | * is actually the bottom left and horizontal and vertical are swapped. | 432 | * is actually the bottom left and horizontal and vertical are swapped. |
433 | * Rockbox expects the origin to be the top left so we need to use | 433 | * Rockbox expects the origin to be the top left so we need to use |
434 | * 127 - y instead of just y */ | 434 | * 127 - y instead of just y */ |
435 | |||
436 | /* max horiz << 8 | start horiz */ | ||
437 | lcd_send_cmd(R_HORIZ_RAM_ADDR_POS); | ||
438 | lcd_send_data( (((LCD_HEIGHT-1)-y0+y_offset) << 8) | ((LCD_HEIGHT-1)-y1+y_offset) ); | ||
439 | 435 | ||
440 | /* max vert << 8 | start vert */ | 436 | /* max vert << 8 | start vert */ |
441 | lcd_send_cmd(R_VERT_RAM_ADDR_POS); | 437 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); |
442 | lcd_send_data((x1 << 8) | x0); | ||
443 | |||
444 | /* position cursor (set AD0-AD15) */ | ||
445 | /* start vert << 8 | start horiz */ | ||
446 | lcd_send_cmd(R_RAM_ADDR_SET); | ||
447 | lcd_send_data( (x0 << 8) | ((LCD_HEIGHT-1)-y0+y_offset) ); | ||
448 | |||
449 | /* start drawing */ | ||
450 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
451 | 438 | ||
452 | ymax = y + height - 1 ; | 439 | y0 = LCD_HEIGHT - 1 - y + y_offset; |
453 | 440 | ||
454 | const int stride_div_csub_x = stride/CSUB_X; | 441 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */ |
442 | lcd_write_reg(R_ENTRY_MODE, 0x1020); | ||
455 | 443 | ||
456 | for (; y <= ymax ; y++) | 444 | yuv_src[0] = src[0] + src_y * stride + src_x; |
457 | { | 445 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); |
458 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ | 446 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); |
459 | const unsigned char *ysrc = src[0] + stride * src_y + src_x; | 447 | ysrc_max = yuv_src[0] + height * stride; |
460 | 448 | ||
461 | const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + | 449 | options = lcd_yuv_options; |
462 | (src_x/CSUB_X); | ||
463 | 450 | ||
464 | const unsigned char *usrc = src[1] + uvoffset; | 451 | do |
465 | const unsigned char *vsrc = src[2] + uvoffset; | 452 | { |
466 | const unsigned char *row_end = ysrc + width; | 453 | /* max horiz << 8 | start horiz */ |
454 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1)); | ||
467 | 455 | ||
468 | int y, u, v; | 456 | /* position cursor (set AD0-AD15) */ |
469 | int red1, green1, blue1; | 457 | /* start vert << 8 | start horiz */ |
470 | int red2, green2, blue2; | 458 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0); |
471 | unsigned rbits, gbits, bbits; | ||
472 | 459 | ||
473 | int rc, gc, bc; | 460 | /* start drawing */ |
461 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
474 | 462 | ||
475 | do | 463 | if (options & LCD_YUV_DITHER) |
464 | { | ||
465 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, | ||
466 | x, y); | ||
467 | y -= 2; | ||
468 | } | ||
469 | else | ||
476 | { | 470 | { |
477 | u = *usrc++ - 128; | 471 | lcd_write_yuv420_lines(yuv_src, width, stride); |
478 | v = *vsrc++ - 128; | ||
479 | rc = RVFAC * v + ROUNDOFFS; | ||
480 | gc = GVFAC * v + GUFAC * u + ROUNDOFFSG; | ||
481 | bc = BUFAC * u + ROUNDOFFS; | ||
482 | |||
483 | /* Pixel 1 */ | ||
484 | y = *ysrc++; | ||
485 | |||
486 | red1 = RYFAC * y + rc; | ||
487 | green1 = GYFAC * y + gc; | ||
488 | blue1 = BYFAC * y + bc; | ||
489 | |||
490 | /* Pixel 2 */ | ||
491 | y = *ysrc++; | ||
492 | red2 = RYFAC * y + rc; | ||
493 | green2 = GYFAC * y + gc; | ||
494 | blue2 = BYFAC * y + bc; | ||
495 | |||
496 | /* Since out of bounds errors are relatively rare, we check two | ||
497 | pixels at once to see if any components are out of bounds, and | ||
498 | then fix whichever is broken. This works due to high values and | ||
499 | negative values both becoming larger than the cutoff when | ||
500 | casted to unsigned. And ORing them together checks all of them | ||
501 | simultaneously. */ | ||
502 | if (((unsigned)(red1 | green1 | blue1 | | ||
503 | red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) { | ||
504 | if (((unsigned)(red1 | green1 | blue1)) > | ||
505 | (RYFAC*255+ROUNDOFFS)) { | ||
506 | if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS)) | ||
507 | { | ||
508 | if (red1 < 0) | ||
509 | red1 = 0; | ||
510 | else | ||
511 | red1 = (RYFAC*255+ROUNDOFFS); | ||
512 | } | ||
513 | if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG)) | ||
514 | { | ||
515 | if (green1 < 0) | ||
516 | green1 = 0; | ||
517 | else | ||
518 | green1 = (GYFAC*255+ROUNDOFFSG); | ||
519 | } | ||
520 | if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS)) | ||
521 | { | ||
522 | if (blue1 < 0) | ||
523 | blue1 = 0; | ||
524 | else | ||
525 | blue1 = (BYFAC*255+ROUNDOFFS); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | if (((unsigned)(red2 | green2 | blue2)) > | ||
530 | (RYFAC*255+ROUNDOFFS)) { | ||
531 | if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS)) | ||
532 | { | ||
533 | if (red2 < 0) | ||
534 | red2 = 0; | ||
535 | else | ||
536 | red2 = (RYFAC*255+ROUNDOFFS); | ||
537 | } | ||
538 | if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG)) | ||
539 | { | ||
540 | if (green2 < 0) | ||
541 | green2 = 0; | ||
542 | else | ||
543 | green2 = (GYFAC*255+ROUNDOFFSG); | ||
544 | } | ||
545 | if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS)) | ||
546 | { | ||
547 | if (blue2 < 0) | ||
548 | blue2 = 0; | ||
549 | else | ||
550 | blue2 = (BYFAC*255+ROUNDOFFS); | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
555 | rbits = red1 >> 16 ; | ||
556 | gbits = green1 >> 15 ; | ||
557 | bbits = blue1 >> 16 ; | ||
558 | lcd_send_data((rbits << 11) | (gbits << 5) | bbits); | ||
559 | |||
560 | rbits = red2 >> 16 ; | ||
561 | gbits = green2 >> 15 ; | ||
562 | bbits = blue2 >> 16 ; | ||
563 | lcd_send_data((rbits << 11) | (gbits << 5) | bbits); | ||
564 | } | 472 | } |
565 | while (ysrc < row_end); | ||
566 | 473 | ||
567 | src_y++; | 474 | y0 -= 2; |
475 | yuv_src[0] += stride << 1; | ||
476 | yuv_src[1] += stride >> 1; | ||
477 | yuv_src[2] += stride >> 1; | ||
568 | } | 478 | } |
479 | while (yuv_src[0] < ysrc_max); | ||
480 | |||
481 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */ | ||
482 | lcd_write_reg(R_ENTRY_MODE, 0x1028); | ||
569 | } | 483 | } |
570 | 484 | ||
571 | 485 | ||
@@ -573,8 +487,7 @@ void lcd_yuv_blit(unsigned char * const src[3], | |||
573 | void lcd_update_rect(int x0, int y0, int width, int height) | 487 | void lcd_update_rect(int x0, int y0, int width, int height) |
574 | { | 488 | { |
575 | int x1, y1; | 489 | int x1, y1; |
576 | 490 | unsigned short *addr; | |
577 | unsigned short *addr = (unsigned short *)lcd_framebuffer; | ||
578 | 491 | ||
579 | if (!display_on) | 492 | if (!display_on) |
580 | return; | 493 | return; |