summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-recorder.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-recorder.c')
-rw-r--r--firmware/drivers/lcd-recorder.c360
1 files changed, 188 insertions, 172 deletions
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index d464e30f0a..9513c26380 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -265,20 +265,20 @@ void lcd_init(void)
265/*** Update functions ***/ 265/*** Update functions ***/
266 266
267/* Performance function that works with an external buffer 267/* Performance function that works with an external buffer
268 note that y and height are in 8-pixel units! */ 268 note that by and bheight are in 8-pixel units! */
269void lcd_blit(const unsigned char* p_data, int x, int y, int width, 269void lcd_blit(const unsigned char* data, int x, int by, int width,
270 int height, int stride) 270 int bheight, int stride)
271{ 271{
272 /* Copy display bitmap to hardware */ 272 /* Copy display bitmap to hardware */
273 while (height--) 273 while (bheight--)
274 { 274 {
275 lcd_write_command (LCD_CNTL_PAGE | (y++ & 0xf)); 275 lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
276 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf)); 276 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf));
277 lcd_write_command (LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf)); 277 lcd_write_command (LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf));
278 278
279 lcd_write_data(p_data, width); 279 lcd_write_data(data, width);
280 p_data += stride; 280 data += stride;
281 } 281 }
282} 282}
283 283
284 284
@@ -302,29 +302,31 @@ void lcd_update(void)
302 302
303/* Update a fraction of the display. */ 303/* Update a fraction of the display. */
304void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); 304void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode")));
305void lcd_update_rect(int x_start, int y, int width, int height) 305void lcd_update_rect(int x, int y, int width, int height)
306{ 306{
307 int ymax; 307 int ymax;
308 308
309 /* The Y coordinates have to work on even 8 pixel rows */ 309 /* The Y coordinates have to work on even 8 pixel rows */
310 ymax = (y + height-1)/8; 310 ymax = (y + height-1) >> 3;
311 y /= 8; 311 y >>= 3;
312 312
313 if(x_start + width > LCD_WIDTH) 313 if(x + width > LCD_WIDTH)
314 width = LCD_WIDTH - x_start; 314 width = LCD_WIDTH - x;
315 if (width <= 0) 315 if (width <= 0)
316 return; /* nothing left to do, 0 is harmful to lcd_write_data() */ 316 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
317 if(ymax >= LCD_HEIGHT/8) 317 if(ymax >= LCD_HEIGHT/8)
318 ymax = LCD_HEIGHT/8-1; 318 ymax = LCD_HEIGHT/8-1;
319
320 x += xoffset;
319 321
320 /* Copy specified rectange bitmap to hardware */ 322 /* Copy specified rectange bitmap to hardware */
321 for (; y <= ymax; y++) 323 for (; y <= ymax; y++)
322 { 324 {
323 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf)); 325 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
324 lcd_write_command (LCD_CNTL_HIGHCOL | (((x_start+xoffset)>>4) & 0xf)); 326 lcd_write_command (LCD_CNTL_HIGHCOL | ((x >> 4) & 0xf));
325 lcd_write_command (LCD_CNTL_LOWCOL | ((x_start+xoffset) & 0xf)); 327 lcd_write_command (LCD_CNTL_LOWCOL | (x & 0xf));
326 328
327 lcd_write_data (&lcd_framebuffer[y][x_start], width); 329 lcd_write_data (&lcd_framebuffer[y][x], width);
328 } 330 }
329} 331}
330#endif /* !SIMULATOR */ 332#endif /* !SIMULATOR */
@@ -390,8 +392,10 @@ static void nopixel(int x, int y)
390 (void)y; 392 (void)y;
391} 393}
392 394
393lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, 395lcd_pixelfunc_type* pixelfunc[8] = {
394 nopixel, clearpixel, nopixel, clearpixel}; 396 flippixel, nopixel, setpixel, setpixel,
397 nopixel, clearpixel, nopixel, clearpixel
398};
395 399
396static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 400static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
397{ 401{
@@ -413,7 +417,30 @@ static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
413 *address = (*address & ~mask) | (bits & mask); 417 *address = (*address & ~mask) | (bits & mask);
414} 418}
415 419
416lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; 420static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
421{
422 *address ^= (~bits & mask);
423}
424
425static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
426{
427 *address &= ~(bits & mask);
428}
429
430static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
431{
432 *address |= (~bits & mask);
433}
434
435static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
436{
437 *address = (*address & ~mask) | (~bits & mask);
438}
439
440lcd_blockfunc_type* blockfunc[8] = {
441 flipblock, bgblock, fgblock, solidblock,
442 flipinvblock, bginvblock, fginvblock, solidinvblock
443};
417 444
418/*** drawing functions ***/ 445/*** drawing functions ***/
419 446
@@ -509,7 +536,7 @@ void lcd_hline(int x1, int x2, int y)
509{ 536{
510 int x; 537 int x;
511 unsigned char *dst; 538 unsigned char *dst;
512 unsigned char mask, bits; 539 unsigned mask;
513 lcd_blockfunc_type *bfunc; 540 lcd_blockfunc_type *bfunc;
514 541
515 /* direction flip */ 542 /* direction flip */
@@ -530,13 +557,12 @@ void lcd_hline(int x1, int x2, int y)
530 if (x2 >= LCD_WIDTH) 557 if (x2 >= LCD_WIDTH)
531 x2 = LCD_WIDTH-1; 558 x2 = LCD_WIDTH-1;
532 559
533 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 560 bfunc = blockfunc[drawmode];
534 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 561 dst = &lcd_framebuffer[y>>3][x1];
535 dst = &lcd_framebuffer[y/8][x1];
536 mask = 1 << (y & 7); 562 mask = 1 << (y & 7);
537 563
538 for (x = x1; x <= x2; x++) 564 for (x = x1; x <= x2; x++)
539 bfunc(dst++, mask, bits); 565 bfunc(dst++, mask, 0xFFu);
540} 566}
541 567
542/* Draw a vertical line (optimised) */ 568/* Draw a vertical line (optimised) */
@@ -544,7 +570,7 @@ void lcd_vline(int x, int y1, int y2)
544{ 570{
545 int ny; 571 int ny;
546 unsigned char *dst; 572 unsigned char *dst;
547 unsigned char mask_top, mask_bottom, bits; 573 unsigned mask, mask_bottom;
548 lcd_blockfunc_type *bfunc; 574 lcd_blockfunc_type *bfunc;
549 575
550 /* direction flip */ 576 /* direction flip */
@@ -565,28 +591,20 @@ void lcd_vline(int x, int y1, int y2)
565 if (y2 >= LCD_HEIGHT) 591 if (y2 >= LCD_HEIGHT)
566 y2 = LCD_HEIGHT-1; 592 y2 = LCD_HEIGHT-1;
567 593
568 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 594 bfunc = blockfunc[drawmode];
569 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 595 dst = &lcd_framebuffer[y1>>3][x];
570 dst = &lcd_framebuffer[y1/8][x];
571 ny = y2 - (y1 & ~7); 596 ny = y2 - (y1 & ~7);
572 mask_top = 0xFFu << (y1 & 7); 597 mask = 0xFFu << (y1 & 7);
573 mask_bottom = 0xFFu >> (7 - (ny & 7)); 598 mask_bottom = 0xFFu >> (7 - (ny & 7));
574 599
575 if (ny >= 8) 600 for (; ny >= 8; ny -= 8)
576 { 601 {
577 bfunc(dst, mask_top, bits); 602 bfunc(dst, mask, 0xFFu);
578 dst += LCD_WIDTH; 603 dst += LCD_WIDTH;
579 604 mask = 0xFFu;
580 for (; ny > 15; ny -= 8)
581 {
582 bfunc(dst, 0xFFu, bits);
583 dst += LCD_WIDTH;
584 }
585 } 605 }
586 else 606 mask_bottom &= mask;
587 mask_bottom &= mask_top; 607 bfunc(dst, mask_bottom, 0xFFu);
588
589 bfunc(dst, mask_bottom, bits);
590} 608}
591 609
592/* Draw a rectangular box */ 610/* Draw a rectangular box */
@@ -604,29 +622,19 @@ void lcd_drawrect(int x, int y, int width, int height)
604 lcd_hline(x, x2, y2); 622 lcd_hline(x, x2, y2);
605} 623}
606 624
607/* helper function for lcd_fillrect() */
608static void fillrow(lcd_blockfunc_type *bfunc, unsigned char *address,
609 int width, unsigned mask, unsigned bits)
610{
611 int i;
612
613 for (i = 0; i < width; i++)
614 bfunc(address++, mask, bits);
615}
616
617/* Fill a rectangular area */ 625/* Fill a rectangular area */
618void lcd_fillrect(int x, int y, int width, int height) 626void lcd_fillrect(int x, int y, int width, int height)
619{ 627{
620 int ny; 628 int ny, i;
621 unsigned char *dst; 629 unsigned char *dst;
622 unsigned char mask_top, mask_bottom, bits; 630 unsigned mask, mask_bottom;
631 unsigned bits = 0xFFu;
623 lcd_blockfunc_type *bfunc; 632 lcd_blockfunc_type *bfunc;
624 bool fillopt = (drawmode & DRMODE_INVERSEVID) ? 633 bool fillopt;
625 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
626 634
627 /* nothing to draw? */ 635 /* nothing to draw? */
628 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 636 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
629 || (x + width < 0) || (y + height < 0)) 637 || (x + width <= 0) || (y + height <= 0))
630 return; 638 return;
631 639
632 /* clipping */ 640 /* clipping */
@@ -644,38 +652,41 @@ void lcd_fillrect(int x, int y, int width, int height)
644 width = LCD_WIDTH - x; 652 width = LCD_WIDTH - x;
645 if (y + height > LCD_HEIGHT) 653 if (y + height > LCD_HEIGHT)
646 height = LCD_HEIGHT - y; 654 height = LCD_HEIGHT - y;
647 655
648 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 656 fillopt = (drawmode & DRMODE_INVERSEVID) ?
649 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 657 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
650 dst = &lcd_framebuffer[y/8][x]; 658 if (fillopt &&(drawmode & DRMODE_INVERSEVID))
659 bits = 0;
660 bfunc = blockfunc[drawmode];
661 dst = &lcd_framebuffer[y>>3][x];
651 ny = height - 1 + (y & 7); 662 ny = height - 1 + (y & 7);
652 mask_top = 0xFFu << (y & 7); 663 mask = 0xFFu << (y & 7);
653 mask_bottom = 0xFFu >> (7 - (ny & 7)); 664 mask_bottom = 0xFFu >> (7 - (ny & 7));
654 665
655 if (ny >= 8) 666 for (; ny >= 8; ny -= 8)
656 { 667 {
657 if (fillopt && mask_top == 0xFF) 668 if (fillopt && (mask == 0xFFu))
658 memset(dst, bits, width); 669 memset(dst, bits, width);
659 else 670 else
660 fillrow(bfunc, dst, width, mask_top, bits);
661 dst += LCD_WIDTH;
662
663 for (; ny > 15; ny -= 8)
664 { 671 {
665 if (fillopt) 672 unsigned char *dst_row = dst;
666 memset(dst, bits, width); 673
667 else 674 for (i = width; i > 0; i--)
668 fillrow(bfunc, dst, width, 0xFFu, bits); 675 bfunc(dst_row++, mask, 0xFFu);
669 dst += LCD_WIDTH;
670 } 676 }
677
678 dst += LCD_WIDTH;
679 mask = 0xFFu;
671 } 680 }
672 else 681 mask_bottom &= mask;
673 mask_bottom &= mask_top; 682
674 683 if (fillopt && (mask_bottom == 0xFFu))
675 if (fillopt && mask_bottom == 0xFF)
676 memset(dst, bits, width); 684 memset(dst, bits, width);
677 else 685 else
678 fillrow(bfunc, dst, width, mask_bottom, bits); 686 {
687 for (i = width; i > 0; i--)
688 bfunc(dst++, mask_bottom, 0xFFu);
689 }
679} 690}
680 691
681/* About Rockbox' internal bitmap format: 692/* About Rockbox' internal bitmap format:
@@ -689,95 +700,120 @@ void lcd_fillrect(int x, int y, int width, int height)
689 * 700 *
690 * This is the same as the internal lcd hw format. */ 701 * This is the same as the internal lcd hw format. */
691 702
692/* Draw a bitmap at (x, y), size (nx, ny) 703/* Draw a partial bitmap */
693 if 'clear' is true, clear destination area first */ 704void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
694void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 705 int stride, int x, int y, int width, int height)
695 bool clear) __attribute__ ((section (".icode"))); 706 __attribute__ ((section(".icode")));
696void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 707void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
697 bool clear) 708 int stride, int x, int y, int width, int height)
698{ 709{
699 const unsigned char *src_col; 710 int shift, ny, i;
700 unsigned char *dst, *dst_col; 711 unsigned char *dst;
701 unsigned int data, mask1, mask2, mask3, mask4; 712 unsigned mask, mask_bottom;
702 int stride, shift; 713 lcd_blockfunc_type *bfunc;
703 714
704 if (((unsigned) x >= LCD_WIDTH) || ((unsigned) y >= LCD_HEIGHT)) 715 /* nothing to draw? */
716 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
717 || (x + width <= 0) || (y + height <= 0))
705 return; 718 return;
719
720 /* clipping */
721 if (x < 0)
722 {
723 width += x;
724 src_x -= x;
725 x = 0;
726 }
727 if (y < 0)
728 {
729 height += y;
730 src_y -= y;
731 y = 0;
732 }
733 if (x + width > LCD_WIDTH)
734 width = LCD_WIDTH - x;
735 if (y + height > LCD_HEIGHT)
736 height = LCD_HEIGHT - y;
706 737
707 stride = nx; /* otherwise right-clipping will destroy the image */ 738 src += stride * (src_y >> 3) + src_x; /* move starting point */
739 src_y &= 7;
740 y -= src_y;
741 dst = &lcd_framebuffer[y>>3][x];
742 shift = y & 7;
743 ny = height - 1 + shift + src_y;
708 744
709 if (((unsigned) (x + nx)) >= LCD_WIDTH) 745 bfunc = blockfunc[drawmode];
710 nx = LCD_WIDTH - x; 746 mask = 0xFFu << (shift + src_y);
711 if (((unsigned) (y + ny)) >= LCD_HEIGHT) 747 mask_bottom = 0xFFu >> (7 - (ny & 7));
712 ny = LCD_HEIGHT - y;
713
714 dst = &lcd_framebuffer[y >> 3][x];
715 shift = y & 7;
716 748
717 if (!shift && clear) /* shortcut for byte aligned match with clear */ 749 if (shift == 0)
718 { 750 {
719 while (ny >= 8) /* all full rows */ 751 bool copyopt = (drawmode == DRMODE_SOLID);
752
753 for (; ny >= 8; ny -= 8)
720 { 754 {
721 memcpy(dst, src, nx); 755 if (copyopt && (mask == 0xFFu))
756 memcpy(dst, src, width);
757 else
758 {
759 const unsigned char *src_row = src;
760 unsigned char *dst_row = dst;
761
762 for (i = width; i > 0; i--)
763 bfunc(dst_row++, mask, *src_row++);
764 }
765
722 src += stride; 766 src += stride;
723 dst += LCD_WIDTH; 767 dst += LCD_WIDTH;
724 ny -= 8; 768 mask = 0xFFu;
725 } 769 }
726 if (ny == 0) /* nothing left to do? */ 770 mask_bottom &= mask;
727 return;
728 /* last partial row to do by default routine */
729 }
730
731 ny += shift;
732 771
733 /* Calculate bit masks */ 772 if (copyopt && (mask_bottom == 0xFFu))
734 mask4 = ~(0xfe << ((ny-1) & 7)); /* data mask for last partial row */ 773 memcpy(dst, src, width);
735 if (clear) 774 else
736 { 775 {
737 mask1 = ~(0xff << shift); /* clearing of first partial row */ 776 for (i = width; i > 0; i--)
738 mask2 = 0; /* clearing of intermediate (full) rows */ 777 bfunc(dst++, mask_bottom, *src++);
739 mask3 = ~mask4; /* clearing of last partial row */ 778 }
740 if (ny <= 8)
741 mask3 |= mask1;
742 } 779 }
743 else 780 else
744 mask1 = mask2 = mask3 = 0xff;
745
746 /* Loop for each column */
747 for (x = 0; x < nx; x++)
748 { 781 {
749 src_col = src++; 782 for (x = 0; x < width; x++)
750 dst_col = dst++;
751 data = 0;
752 y = 0;
753
754 if (ny > 8)
755 { 783 {
756 /* First partial row */ 784 const unsigned char *src_col = src++;
757 data = *src_col << shift; 785 unsigned char *dst_col = dst++;
758 *dst_col = (*dst_col & mask1) | data; 786 unsigned mask_col = mask;
759 src_col += stride; 787 unsigned data = 0;
760 dst_col += LCD_WIDTH; 788
761 data >>= 8; 789 for (y = ny; y >= 8; y -= 8)
762
763 /* Intermediate rows */
764 for (y = 8; y < ny-8; y += 8)
765 { 790 {
766 data |= *src_col << shift; 791 data |= *src_col << shift;
767 *dst_col = (*dst_col & mask2) | data; 792
793 if (mask_col & 0xFFu)
794 {
795 bfunc(dst_col, mask_col, data);
796 mask_col = 0xFFu;
797 }
798 else
799 mask_col >>= 8;
800
768 src_col += stride; 801 src_col += stride;
769 dst_col += LCD_WIDTH; 802 dst_col += LCD_WIDTH;
770 data >>= 8; 803 data >>= 8;
771 } 804 }
772 }
773
774 /* Last partial row */
775 if (y + shift < ny)
776 data |= *src_col << shift; 805 data |= *src_col << shift;
777 *dst_col = (*dst_col & mask3) | (data & mask4); 806 bfunc(dst_col, mask_col & mask_bottom, data);
807 }
778 } 808 }
779} 809}
780 810
811/* Draw a full bitmap */
812void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
813{
814 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
815}
816
781/* put a string at a given pixel position, skipping first ofs pixel columns */ 817/* put a string at a given pixel position, skipping first ofs pixel columns */
782static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 818static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
783{ 819{
@@ -786,7 +822,8 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
786 822
787 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 823 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
788 { 824 {
789 int gwidth, width; 825 int width;
826 const unsigned char *bits;
790 827
791 /* check input range */ 828 /* check input range */
792 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 829 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
@@ -794,44 +831,23 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
794 ch -= pf->firstchar; 831 ch -= pf->firstchar;
795 832
796 /* get proportional width and glyph bits */ 833 /* get proportional width and glyph bits */
797 gwidth = pf->width ? pf->width[ch] : pf->maxwidth; 834 width = pf->width ? pf->width[ch] : pf->maxwidth;
798 width = MIN (gwidth, LCD_WIDTH - x);
799 835
800 if (ofs != 0) 836 if (ofs > width)
801 { 837 {
802 if (ofs > width) 838 ofs -= width;
803 { 839 continue;
804 ofs -= width;
805 continue;
806 }
807 width -= ofs;
808 } 840 }
809 841
810 if (width > 0) 842 bits = pf->bits + (pf->offset ?
811 { 843 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
812 unsigned int i;
813 const unsigned char* bits = pf->bits +
814 (pf->offset ? pf->offset[ch]
815 : ((pf->height + 7) / 8 * pf->maxwidth * ch));
816 844
817 if (ofs != 0) 845 lcd_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
818 { 846
819 for (i = 0; i < pf->height; i += 8) 847 x += width - ofs;
820 {
821 lcd_bitmap (bits + ofs, x, y + i, width,
822 MIN(8, pf->height - i), true);
823 bits += gwidth;
824 }
825 }
826 else
827 lcd_bitmap ((unsigned char*) bits, x, y, gwidth,
828 pf->height, true);
829 x += width;
830 }
831 ofs = 0; 848 ofs = 0;
832 } 849 }
833} 850}
834
835/* put a string at a given pixel position */ 851/* put a string at a given pixel position */
836void lcd_putsxy(int x, int y, const unsigned char *str) 852void lcd_putsxy(int x, int y, const unsigned char *str)
837{ 853{