summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-h100.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-h100.c')
-rw-r--r--firmware/drivers/lcd-h100.c355
1 files changed, 185 insertions, 170 deletions
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 15cb351195..616a8521b0 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -208,19 +208,19 @@ void lcd_init(void)
208/*** update functions ***/ 208/*** update functions ***/
209 209
210/* Performance function that works with an external buffer 210/* Performance function that works with an external buffer
211 note that y and height are in 8-pixel units! */ 211 note that by and bheight are in 8-pixel units! */
212void lcd_blit(const unsigned char* p_data, int x, int y, int width, 212void lcd_blit(const unsigned char* data, int x, int by, int width,
213 int height, int stride) 213 int bheight, int stride)
214{ 214{
215 /* Copy display bitmap to hardware */ 215 /* Copy display bitmap to hardware */
216 while (height--) 216 while (bheight--)
217 { 217 {
218 lcd_write_command_ex(LCD_CNTL_PAGE, y++ & 0xf, -1); 218 lcd_write_command_ex(LCD_CNTL_PAGE, by++ & 0xf, -1);
219 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1); 219 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
220 220
221 lcd_write_command(LCD_CNTL_DATA_WRITE); 221 lcd_write_command(LCD_CNTL_DATA_WRITE);
222 lcd_write_data(p_data, width); 222 lcd_write_data(data, width);
223 p_data += stride; 223 data += stride;
224 } 224 }
225} 225}
226 226
@@ -245,16 +245,16 @@ void lcd_update(void)
245 245
246/* Update a fraction of the display. */ 246/* Update a fraction of the display. */
247void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); 247void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode")));
248void lcd_update_rect(int x_start, int y, int width, int height) 248void lcd_update_rect(int x, int y, int width, int height)
249{ 249{
250 int ymax; 250 int ymax;
251 251
252 /* The Y coordinates have to work on even 8 pixel rows */ 252 /* The Y coordinates have to work on even 8 pixel rows */
253 ymax = (y + height-1)/8; 253 ymax = (y + height-1) >> 3;
254 y /= 8; 254 y >>= 3;
255 255
256 if(x_start + width > LCD_WIDTH) 256 if(x + width > LCD_WIDTH)
257 width = LCD_WIDTH - x_start; 257 width = LCD_WIDTH - x;
258 if (width <= 0) 258 if (width <= 0)
259 return; /* nothing left to do, 0 is harmful to lcd_write_data() */ 259 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
260 if(ymax >= LCD_HEIGHT/8) 260 if(ymax >= LCD_HEIGHT/8)
@@ -264,10 +264,10 @@ void lcd_update_rect(int x_start, int y, int width, int height)
264 for (; y <= ymax; y++) 264 for (; y <= ymax; y++)
265 { 265 {
266 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1); 266 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
267 lcd_write_command_ex(LCD_CNTL_COLUMN, x_start, -1); 267 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
268 268
269 lcd_write_command(LCD_CNTL_DATA_WRITE); 269 lcd_write_command(LCD_CNTL_DATA_WRITE);
270 lcd_write_data (&lcd_framebuffer[y][x_start], width); 270 lcd_write_data (&lcd_framebuffer[y][x], width);
271 } 271 }
272} 272}
273#endif /* !SIMULATOR */ 273#endif /* !SIMULATOR */
@@ -333,8 +333,10 @@ static void nopixel(int x, int y)
333 (void)y; 333 (void)y;
334} 334}
335 335
336lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, 336lcd_pixelfunc_type* pixelfunc[8] = {
337 nopixel, clearpixel, nopixel, clearpixel}; 337 flippixel, nopixel, setpixel, setpixel,
338 nopixel, clearpixel, nopixel, clearpixel
339};
338 340
339static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 341static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
340{ 342{
@@ -356,7 +358,30 @@ static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
356 *address = (*address & ~mask) | (bits & mask); 358 *address = (*address & ~mask) | (bits & mask);
357} 359}
358 360
359lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; 361static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
362{
363 *address ^= (~bits & mask);
364}
365
366static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
367{
368 *address &= ~(bits & mask);
369}
370
371static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
372{
373 *address |= (~bits & mask);
374}
375
376static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
377{
378 *address = (*address & ~mask) | (~bits & mask);
379}
380
381lcd_blockfunc_type* blockfunc[8] = {
382 flipblock, bgblock, fgblock, solidblock,
383 flipinvblock, bginvblock, fginvblock, solidinvblock
384};
360 385
361/*** drawing functions ***/ 386/*** drawing functions ***/
362 387
@@ -452,7 +477,7 @@ void lcd_hline(int x1, int x2, int y)
452{ 477{
453 int x; 478 int x;
454 unsigned char *dst; 479 unsigned char *dst;
455 unsigned char mask, bits; 480 unsigned mask;
456 lcd_blockfunc_type *bfunc; 481 lcd_blockfunc_type *bfunc;
457 482
458 /* direction flip */ 483 /* direction flip */
@@ -473,13 +498,12 @@ void lcd_hline(int x1, int x2, int y)
473 if (x2 >= LCD_WIDTH) 498 if (x2 >= LCD_WIDTH)
474 x2 = LCD_WIDTH-1; 499 x2 = LCD_WIDTH-1;
475 500
476 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 501 bfunc = blockfunc[drawmode];
477 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 502 dst = &lcd_framebuffer[y>>3][x1];
478 dst = &lcd_framebuffer[y/8][x1];
479 mask = 1 << (y & 7); 503 mask = 1 << (y & 7);
480 504
481 for (x = x1; x <= x2; x++) 505 for (x = x1; x <= x2; x++)
482 bfunc(dst++, mask, bits); 506 bfunc(dst++, mask, 0xFFu);
483} 507}
484 508
485/* Draw a vertical line (optimised) */ 509/* Draw a vertical line (optimised) */
@@ -487,7 +511,7 @@ void lcd_vline(int x, int y1, int y2)
487{ 511{
488 int ny; 512 int ny;
489 unsigned char *dst; 513 unsigned char *dst;
490 unsigned char mask_top, mask_bottom, bits; 514 unsigned mask, mask_bottom;
491 lcd_blockfunc_type *bfunc; 515 lcd_blockfunc_type *bfunc;
492 516
493 /* direction flip */ 517 /* direction flip */
@@ -508,28 +532,20 @@ void lcd_vline(int x, int y1, int y2)
508 if (y2 >= LCD_HEIGHT) 532 if (y2 >= LCD_HEIGHT)
509 y2 = LCD_HEIGHT-1; 533 y2 = LCD_HEIGHT-1;
510 534
511 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 535 bfunc = blockfunc[drawmode];
512 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 536 dst = &lcd_framebuffer[y1>>3][x];
513 dst = &lcd_framebuffer[y1/8][x];
514 ny = y2 - (y1 & ~7); 537 ny = y2 - (y1 & ~7);
515 mask_top = 0xFFu << (y1 & 7); 538 mask = 0xFFu << (y1 & 7);
516 mask_bottom = 0xFFu >> (7 - (ny & 7)); 539 mask_bottom = 0xFFu >> (7 - (ny & 7));
517 540
518 if (ny >= 8) 541 for (; ny >= 8; ny -= 8)
519 { 542 {
520 bfunc(dst, mask_top, bits); 543 bfunc(dst, mask, 0xFFu);
521 dst += LCD_WIDTH; 544 dst += LCD_WIDTH;
522 545 mask = 0xFFu;
523 for (; ny > 15; ny -= 8)
524 {
525 bfunc(dst, 0xFFu, bits);
526 dst += LCD_WIDTH;
527 }
528 } 546 }
529 else 547 mask_bottom &= mask;
530 mask_bottom &= mask_top; 548 bfunc(dst, mask_bottom, 0xFFu);
531
532 bfunc(dst, mask_bottom, bits);
533} 549}
534 550
535/* Draw a rectangular box */ 551/* Draw a rectangular box */
@@ -547,29 +563,19 @@ void lcd_drawrect(int x, int y, int width, int height)
547 lcd_hline(x, x2, y2); 563 lcd_hline(x, x2, y2);
548} 564}
549 565
550/* helper function for lcd_fillrect() */
551static void fillrow(lcd_blockfunc_type *bfunc, unsigned char *address,
552 int width, unsigned mask, unsigned bits)
553{
554 int i;
555
556 for (i = 0; i < width; i++)
557 bfunc(address++, mask, bits);
558}
559
560/* Fill a rectangular area */ 566/* Fill a rectangular area */
561void lcd_fillrect(int x, int y, int width, int height) 567void lcd_fillrect(int x, int y, int width, int height)
562{ 568{
563 int ny; 569 int ny, i;
564 unsigned char *dst; 570 unsigned char *dst;
565 unsigned char mask_top, mask_bottom, bits; 571 unsigned mask, mask_bottom;
572 unsigned bits = 0xFFu;
566 lcd_blockfunc_type *bfunc; 573 lcd_blockfunc_type *bfunc;
567 bool fillopt = (drawmode & DRMODE_INVERSEVID) ? 574 bool fillopt;
568 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
569 575
570 /* nothing to draw? */ 576 /* nothing to draw? */
571 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 577 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
572 || (x + width < 0) || (y + height < 0)) 578 || (x + width <= 0) || (y + height <= 0))
573 return; 579 return;
574 580
575 /* clipping */ 581 /* clipping */
@@ -587,38 +593,41 @@ void lcd_fillrect(int x, int y, int width, int height)
587 width = LCD_WIDTH - x; 593 width = LCD_WIDTH - x;
588 if (y + height > LCD_HEIGHT) 594 if (y + height > LCD_HEIGHT)
589 height = LCD_HEIGHT - y; 595 height = LCD_HEIGHT - y;
590 596
591 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 597 fillopt = (drawmode & DRMODE_INVERSEVID) ?
592 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 598 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
593 dst = &lcd_framebuffer[y/8][x]; 599 if (fillopt &&(drawmode & DRMODE_INVERSEVID))
600 bits = 0;
601 bfunc = blockfunc[drawmode];
602 dst = &lcd_framebuffer[y>>3][x];
594 ny = height - 1 + (y & 7); 603 ny = height - 1 + (y & 7);
595 mask_top = 0xFFu << (y & 7); 604 mask = 0xFFu << (y & 7);
596 mask_bottom = 0xFFu >> (7 - (ny & 7)); 605 mask_bottom = 0xFFu >> (7 - (ny & 7));
597 606
598 if (ny >= 8) 607 for (; ny >= 8; ny -= 8)
599 { 608 {
600 if (fillopt && mask_top == 0xFF) 609 if (fillopt && (mask == 0xFFu))
601 memset(dst, bits, width); 610 memset(dst, bits, width);
602 else 611 else
603 fillrow(bfunc, dst, width, mask_top, bits);
604 dst += LCD_WIDTH;
605
606 for (; ny > 15; ny -= 8)
607 { 612 {
608 if (fillopt) 613 unsigned char *dst_row = dst;
609 memset(dst, bits, width); 614
610 else 615 for (i = width; i > 0; i--)
611 fillrow(bfunc, dst, width, 0xFFu, bits); 616 bfunc(dst_row++, mask, 0xFFu);
612 dst += LCD_WIDTH;
613 } 617 }
618
619 dst += LCD_WIDTH;
620 mask = 0xFFu;
614 } 621 }
615 else 622 mask_bottom &= mask;
616 mask_bottom &= mask_top; 623
617 624 if (fillopt && (mask_bottom == 0xFFu))
618 if (fillopt && mask_bottom == 0xFF)
619 memset(dst, bits, width); 625 memset(dst, bits, width);
620 else 626 else
621 fillrow(bfunc, dst, width, mask_bottom, bits); 627 {
628 for (i = width; i > 0; i--)
629 bfunc(dst++, mask_bottom, 0xFFu);
630 }
622} 631}
623 632
624/* About Rockbox' internal bitmap format: 633/* About Rockbox' internal bitmap format:
@@ -632,95 +641,120 @@ void lcd_fillrect(int x, int y, int width, int height)
632 * 641 *
633 * This is the same as the internal lcd hw format. */ 642 * This is the same as the internal lcd hw format. */
634 643
635/* Draw a bitmap at (x, y), size (nx, ny) 644/* Draw a partial bitmap */
636 if 'clear' is true, clear destination area first */ 645void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
637void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 646 int stride, int x, int y, int width, int height)
638 bool clear) __attribute__ ((section (".icode"))); 647 __attribute__ ((section(".icode")));
639void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 648void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
640 bool clear) 649 int stride, int x, int y, int width, int height)
641{ 650{
642 const unsigned char *src_col; 651 int shift, ny, i;
643 unsigned char *dst, *dst_col; 652 unsigned char *dst;
644 unsigned int data, mask1, mask2, mask3, mask4; 653 unsigned mask, mask_bottom;
645 int stride, shift; 654 lcd_blockfunc_type *bfunc;
646 655
647 if (((unsigned) x >= LCD_WIDTH) || ((unsigned) y >= LCD_HEIGHT)) 656 /* nothing to draw? */
657 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
658 || (x + width <= 0) || (y + height <= 0))
648 return; 659 return;
660
661 /* clipping */
662 if (x < 0)
663 {
664 width += x;
665 src_x -= x;
666 x = 0;
667 }
668 if (y < 0)
669 {
670 height += y;
671 src_y -= y;
672 y = 0;
673 }
674 if (x + width > LCD_WIDTH)
675 width = LCD_WIDTH - x;
676 if (y + height > LCD_HEIGHT)
677 height = LCD_HEIGHT - y;
649 678
650 stride = nx; /* otherwise right-clipping will destroy the image */ 679 src += stride * (src_y >> 3) + src_x; /* move starting point */
680 src_y &= 7;
681 y -= src_y;
682 dst = &lcd_framebuffer[y>>3][x];
683 shift = y & 7;
684 ny = height - 1 + shift + src_y;
651 685
652 if (((unsigned) (x + nx)) >= LCD_WIDTH) 686 bfunc = blockfunc[drawmode];
653 nx = LCD_WIDTH - x; 687 mask = 0xFFu << (shift + src_y);
654 if (((unsigned) (y + ny)) >= LCD_HEIGHT) 688 mask_bottom = 0xFFu >> (7 - (ny & 7));
655 ny = LCD_HEIGHT - y;
656
657 dst = &lcd_framebuffer[y >> 3][x];
658 shift = y & 7;
659 689
660 if (!shift && clear) /* shortcut for byte aligned match with clear */ 690 if (shift == 0)
661 { 691 {
662 while (ny >= 8) /* all full rows */ 692 bool copyopt = (drawmode == DRMODE_SOLID);
693
694 for (; ny >= 8; ny -= 8)
663 { 695 {
664 memcpy(dst, src, nx); 696 if (copyopt && (mask == 0xFFu))
697 memcpy(dst, src, width);
698 else
699 {
700 const unsigned char *src_row = src;
701 unsigned char *dst_row = dst;
702
703 for (i = width; i > 0; i--)
704 bfunc(dst_row++, mask, *src_row++);
705 }
706
665 src += stride; 707 src += stride;
666 dst += LCD_WIDTH; 708 dst += LCD_WIDTH;
667 ny -= 8; 709 mask = 0xFFu;
668 } 710 }
669 if (ny == 0) /* nothing left to do? */ 711 mask_bottom &= mask;
670 return;
671 /* last partial row to do by default routine */
672 }
673
674 ny += shift;
675 712
676 /* Calculate bit masks */ 713 if (copyopt && (mask_bottom == 0xFFu))
677 mask4 = ~(0xfe << ((ny-1) & 7)); /* data mask for last partial row */ 714 memcpy(dst, src, width);
678 if (clear) 715 else
679 { 716 {
680 mask1 = ~(0xff << shift); /* clearing of first partial row */ 717 for (i = width; i > 0; i--)
681 mask2 = 0; /* clearing of intermediate (full) rows */ 718 bfunc(dst++, mask_bottom, *src++);
682 mask3 = ~mask4; /* clearing of last partial row */ 719 }
683 if (ny <= 8)
684 mask3 |= mask1;
685 } 720 }
686 else 721 else
687 mask1 = mask2 = mask3 = 0xff;
688
689 /* Loop for each column */
690 for (x = 0; x < nx; x++)
691 { 722 {
692 src_col = src++; 723 for (x = 0; x < width; x++)
693 dst_col = dst++;
694 data = 0;
695 y = 0;
696
697 if (ny > 8)
698 { 724 {
699 /* First partial row */ 725 const unsigned char *src_col = src++;
700 data = *src_col << shift; 726 unsigned char *dst_col = dst++;
701 *dst_col = (*dst_col & mask1) | data; 727 unsigned mask_col = mask;
702 src_col += stride; 728 unsigned data = 0;
703 dst_col += LCD_WIDTH; 729
704 data >>= 8; 730 for (y = ny; y >= 8; y -= 8)
705
706 /* Intermediate rows */
707 for (y = 8; y < ny-8; y += 8)
708 { 731 {
709 data |= *src_col << shift; 732 data |= *src_col << shift;
710 *dst_col = (*dst_col & mask2) | data; 733
734 if (mask_col & 0xFFu)
735 {
736 bfunc(dst_col, mask_col, data);
737 mask_col = 0xFFu;
738 }
739 else
740 mask_col >>= 8;
741
711 src_col += stride; 742 src_col += stride;
712 dst_col += LCD_WIDTH; 743 dst_col += LCD_WIDTH;
713 data >>= 8; 744 data >>= 8;
714 } 745 }
715 }
716
717 /* Last partial row */
718 if (y + shift < ny)
719 data |= *src_col << shift; 746 data |= *src_col << shift;
720 *dst_col = (*dst_col & mask3) | (data & mask4); 747 bfunc(dst_col, mask_col & mask_bottom, data);
748 }
721 } 749 }
722} 750}
723 751
752/* Draw a full bitmap */
753void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
754{
755 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
756}
757
724/* put a string at a given pixel position, skipping first ofs pixel columns */ 758/* put a string at a given pixel position, skipping first ofs pixel columns */
725static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 759static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
726{ 760{
@@ -729,7 +763,8 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
729 763
730 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 764 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
731 { 765 {
732 int gwidth, width; 766 int width;
767 const unsigned char *bits;
733 768
734 /* check input range */ 769 /* check input range */
735 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 770 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
@@ -737,40 +772,20 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
737 ch -= pf->firstchar; 772 ch -= pf->firstchar;
738 773
739 /* get proportional width and glyph bits */ 774 /* get proportional width and glyph bits */
740 gwidth = pf->width ? pf->width[ch] : pf->maxwidth; 775 width = pf->width ? pf->width[ch] : pf->maxwidth;
741 width = MIN (gwidth, LCD_WIDTH - x);
742 776
743 if (ofs != 0) 777 if (ofs > width)
744 { 778 {
745 if (ofs > width) 779 ofs -= width;
746 { 780 continue;
747 ofs -= width;
748 continue;
749 }
750 width -= ofs;
751 } 781 }
782
783 bits = pf->bits + (pf->offset ?
784 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
752 785
753 if (width > 0) 786 lcd_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
754 { 787
755 unsigned int i; 788 x += width - ofs;
756 const unsigned char* bits = pf->bits +
757 (pf->offset ? pf->offset[ch]
758 : ((pf->height + 7) / 8 * pf->maxwidth * ch));
759
760 if (ofs != 0)
761 {
762 for (i = 0; i < pf->height; i += 8)
763 {
764 lcd_bitmap (bits + ofs, x, y + i, width,
765 MIN(8, pf->height - i), true);
766 bits += gwidth;
767 }
768 }
769 else
770 lcd_bitmap ((unsigned char*) bits, x, y, gwidth,
771 pf->height, true);
772 x += width;
773 }
774 ofs = 0; 789 ofs = 0;
775 } 790 }
776} 791}