summaryrefslogtreecommitdiff
path: root/apps/plugins/grayscale.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/grayscale.c')
-rw-r--r--apps/plugins/grayscale.c395
1 files changed, 314 insertions, 81 deletions
diff --git a/apps/plugins/grayscale.c b/apps/plugins/grayscale.c
index fe50a5226e..c429485f93 100644
--- a/apps/plugins/grayscale.c
+++ b/apps/plugins/grayscale.c
@@ -63,6 +63,9 @@ static unsigned int gbuf_size = 0;
63#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */ 63#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
64#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */ 64#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
65 65
66/* unsigned 16 bit multiplication (a single instruction on the SH) */
67#define MULU16(a, b) (((unsigned short) (a)) * ((unsigned short) (b)))
68
66typedef struct 69typedef struct
67{ 70{
68 int x; 71 int x;
@@ -80,19 +83,21 @@ typedef struct
80} tGraybuf; 83} tGraybuf;
81 84
82static tGraybuf *graybuf = NULL; 85static tGraybuf *graybuf = NULL;
86static short gray_random_buffer;
83 87
84/** prototypes **/ 88/** prototypes **/
85 89
86void timer_isr(void); 90void gray_timer_isr(void);
87void graypixel(int x, int y, unsigned long pattern); 91void graypixel(int x, int y, unsigned long pattern);
88void grayinvertmasked(int x, int yb, unsigned char mask); 92void grayblock(int x, int by, unsigned char* src, int stride);
93void grayinvertmasked(int x, int by, unsigned char mask);
89 94
90/** implementation **/ 95/** implementation **/
91 96
92/* timer interrupt handler: display next bitplane */ 97/* timer interrupt handler: display next bitplane */
93void timer_isr(void) 98void gray_timer_isr(void)
94{ 99{
95 rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane), 100 rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
96 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight, 101 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
97 graybuf->width); 102 graybuf->width);
98 103
@@ -126,7 +131,6 @@ void timer_isr(void)
126 * This is the fundamental graphics primitive, asm optimized */ 131 * This is the fundamental graphics primitive, asm optimized */
127void graypixel(int x, int y, unsigned long pattern) 132void graypixel(int x, int y, unsigned long pattern)
128{ 133{
129 static short random_buffer;
130 register long address, mask, random; 134 register long address, mask, random;
131 135
132 /* Some (pseudo-)random function must be used here to shift the bit 136 /* Some (pseudo-)random function must be used here to shift the bit
@@ -149,7 +153,7 @@ void graypixel(int x, int y, unsigned long pattern)
149 : /* outputs */ 153 : /* outputs */
150 /* %0 */ "=&r"(random) 154 /* %0 */ "=&r"(random)
151 : /* inputs */ 155 : /* inputs */
152 /* %1 */ "r"(&random_buffer), 156 /* %1 */ "r"(&gray_random_buffer),
153 /* %2 */ "r"(graybuf->randmask) 157 /* %2 */ "r"(graybuf->randmask)
154 : /* clobbers */ 158 : /* clobbers */
155 "r1","macl" 159 "r1","macl"
@@ -258,6 +262,141 @@ void graypixel(int x, int y, unsigned long pattern)
258 ); 262 );
259} 263}
260 264
265/* Set 8 pixels to specific gray values at once, asm optimized
266 * This greatly enhances performance of gray_fillrect() and gray_drawgraymap()
267 * for larger rectangles and graymaps */
268void grayblock(int x, int by, unsigned char* src, int stride)
269{
270 /* precalculate the bit patterns with random shifts (same RNG as graypixel,
271 * see there for an explanation) for all 8 pixels and put them on the
272 * stack (!) */
273 asm(
274 "mova .gb_reload,r0 \n" /* set default loopback address */
275 "tst %1,%1 \n" /* stride == 0 ? */
276 "bf .gb_needreload \n" /* no: keep that address */
277 "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
278 ".gb_needreload: \n"
279 "mov r0,r2 \n" /* loopback address to r2 */
280 "mov #7,r3 \n" /* loop count in r3: 8 pixels */
281
282 ".align 2 \n" /** load pattern for pixel **/
283 ".gb_reload: \n"
284 "mov.b @%0,r0 \n" /* load src byte */
285 "extu.b r0,r0 \n" /* extend unsigned */
286 "mulu %2,r0 \n" /* macl = byte * depth; */
287 "add %1,%0 \n" /* src += stride; */
288 "sts macl,r4 \n" /* r4 = macl; */
289 "add r4,r0 \n" /* byte += r4; */
290 "shlr8 r0 \n" /* byte >>= 8; */
291 "shll2 r0 \n"
292 "mov.l @(r0,%3),r4 \n" /* r4 = bitpattern[byte]; */
293
294 ".align 2 \n" /** RNG **/
295 ".gb_reuse: \n"
296 "mov.w @%4,r1 \n" /* load last value */
297 "mov #75,r0 \n"
298 "mulu r0,r1 \n" /* multiply by 75 */
299 "sts macl,r1 \n"
300 "add #74,r1 \n" /* add another 74 */
301 "mov.w r1,@%4 \n" /* store new value */
302 /* Since the lower bits are not very random: */
303 "shlr8 r1 \n" /* get bits 8..15 (need max. 5) */
304 "and %5,r1 \n" /* mask out unneeded bits */
305
306 "cmp/hs %2,r1 \n" /* random >= depth ? */
307 "bf .gb_ntrim \n"
308 "sub %2,r1 \n" /* yes: random -= depth; */
309 ".gb_ntrim: \n"
310
311 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
312 "jsr @r0 \n" /* shift r4 left by r1 */
313 "mov r1,r5 \n"
314
315 "mov %2,r5 \n"
316 "sub r1,r5 \n" /* r5 = depth - r1 */
317 "mov r0,r1 \n" /* last result stored in r1 */
318 "mov.l .lshrsi3,r0 \n"
319 "jsr @r0 \n" /* shift r4 right by r5 */
320 "nop \n"
321
322 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
323 "mov.l r0,@-r15 \n" /* push pattern */
324
325 "cmp/pl r3 \n" /* loop count > 0? */
326 "bf .gb_patdone \n" /* no: done */
327
328 "jmp @r2 \n" /* yes: loop */
329 "add #-1,r3 \n" /* decrease loop count */
330
331 ".align 2 \n"
332 ".ashlsi3: \n" /* C library routine: */
333 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
334 ".lshrsi3: \n" /* C library routine: */
335 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
336 /* both routines preserve r4, destroy r5 and take ~16 cycles */
337
338 ".gb_patdone: \n"
339 : /* outputs */
340 : /* inputs */
341 /* %0 */ "r"(src),
342 /* %1 */ "r"(stride),
343 /* %2 */ "r"(graybuf->depth),
344 /* %3 */ "r"(graybuf->bitpattern),
345 /* %4 */ "r"(&gray_random_buffer),
346 /* %5 */ "r"(graybuf->randmask)
347 : /* clobbers */
348 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
349 );
350
351 /* calculate start address in first bitplane and end address */
352 register unsigned char *address = graybuf->data + x
353 + MULU16(graybuf->width, by);
354 register unsigned char *end_addr = address
355 + MULU16(graybuf->depth, graybuf->plane_size);
356
357 /* set the bits for all 8 pixels in all bytes according to the
358 * precalculated patterns on the stack */
359 asm (
360 "mov.l @r15+,r1 \n" /* pop all 8 patterns */
361 "mov.l @r15+,r2 \n"
362 "mov.l @r15+,r3 \n"
363 "mov.l @r15+,r4 \n"
364 "mov.l @r15+,r5 \n"
365 "mov.l @r15+,r6 \n"
366 "mov.l @r15+,r7 \n"
367 "mov.l @r15+,r8 \n"
368
369 ".gb_loop: \n" /* loop for all bitplanes */
370 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
371 "rotcl r0 \n" /* rotate t bit into r0 */
372 "shlr r2 \n"
373 "rotcl r0 \n"
374 "shlr r3 \n"
375 "rotcl r0 \n"
376 "shlr r4 \n"
377 "rotcl r0 \n"
378 "shlr r5 \n"
379 "rotcl r0 \n"
380 "shlr r6 \n"
381 "rotcl r0 \n"
382 "shlr r7 \n"
383 "rotcl r0 \n"
384 "shlr r8 \n"
385 "rotcl r0 \n"
386 "mov.b r0,@%0 \n" /* store byte to bitplane */
387 "add %2,%0 \n" /* advance to next bitplane */
388 "cmp/hi %0,%1 \n" /* last bitplane done? */
389 "bt .gb_loop \n" /* no: loop */
390 : /* outputs */
391 : /* inputs */
392 /* %0 */ "r"(address),
393 /* %1 */ "r"(end_addr),
394 /* %2 */ "r"(graybuf->plane_size)
395 : /* clobbers */
396 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
397 );
398}
399
261/* Invert the bits for 1-8 pixels within the buffer */ 400/* Invert the bits for 1-8 pixels within the buffer */
262void grayinvertmasked(int x, int by, unsigned char mask) 401void grayinvertmasked(int x, int by, unsigned char mask)
263{ 402{
@@ -473,7 +612,7 @@ void gray_show_display(bool enable)
473 if (enable) 612 if (enable)
474 { 613 {
475 graybuf->flags |= GRAY_RUNNING; 614 graybuf->flags |= GRAY_RUNNING;
476 rb->plugin_register_timer(FREQ / 67, 1, timer_isr); 615 rb->plugin_register_timer(FREQ / 67, 1, gray_timer_isr);
477 } 616 }
478 else 617 else
479 { 618 {
@@ -533,7 +672,7 @@ void gray_clear_display(void)
533 if (graybuf == NULL) 672 if (graybuf == NULL)
534 return; 673 return;
535 674
536 rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size); 675 rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
537} 676}
538 677
539/* Set the grayscale display to all black 678/* Set the grayscale display to all black
@@ -543,7 +682,7 @@ void gray_black_display(void)
543 if (graybuf == NULL) 682 if (graybuf == NULL)
544 return; 683 return;
545 684
546 rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size); 685 rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
547} 686}
548 687
549/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas 688/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
@@ -567,8 +706,8 @@ void gray_deferred_update(void)
567 */ 706 */
568void gray_scroll_left(int count, bool black_border) 707void gray_scroll_left(int count, bool black_border)
569{ 708{
570 int x, by, d; 709 int by, d;
571 unsigned char *src, *dest; 710 unsigned char *ptr;
572 unsigned char filler; 711 unsigned char filler;
573 712
574 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width) 713 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
@@ -582,17 +721,42 @@ void gray_scroll_left(int count, bool black_border)
582 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 721 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
583 for (by = 0; by < graybuf->bheight; by++) 722 for (by = 0; by < graybuf->bheight; by++)
584 { 723 {
724 ptr = graybuf->data + MULU16(graybuf->width, by);
585 for (d = 0; d < graybuf->depth; d++) 725 for (d = 0; d < graybuf->depth; d++)
586 { 726 {
587 dest = graybuf->data + graybuf->plane_size * d 727 if (count & 1) /* odd count: scroll byte-wise */
588 + graybuf->width * by; 728 asm volatile (
589 src = dest + count; 729 ".sl_loop1: \n"
590 730 "mov.b @%0+,r1 \n"
591 for (x = count; x < graybuf->width; x++) 731 "mov.b r1,@(%2,%0) \n"
592 *dest++ = *src++; 732 "cmp/hi %0,%1 \n"
593 733 "bt .sl_loop1 \n"
594 for (x = 0; x < count; x++) 734 : /* outputs */
595 *dest++ = filler; 735 : /* inputs */
736 /* %0 */ "r"(ptr + count),
737 /* %1 */ "r"(ptr + graybuf->width),
738 /* %2 */ "z"(-count - 1)
739 : /* clobbers */
740 "r1"
741 );
742 else /* even count: scroll word-wise */
743 asm volatile (
744 ".sl_loop2: \n"
745 "mov.w @%0+,r1 \n"
746 "mov.w r1,@(%2,%0) \n"
747 "cmp/hi %0,%1 \n"
748 "bt .sl_loop2 \n"
749 : /* outputs */
750 : /* inputs */
751 /* %0 */ "r"(ptr + count),
752 /* %1 */ "r"(ptr + graybuf->width),
753 /* %2 */ "z"(-count - 2)
754 : /* clobbers */
755 "r1"
756 );
757
758 rb->memset(ptr + graybuf->width - count, filler, count);
759 ptr += graybuf->plane_size;
596 } 760 }
597 } 761 }
598} 762}
@@ -604,8 +768,8 @@ void gray_scroll_left(int count, bool black_border)
604 */ 768 */
605void gray_scroll_right(int count, bool black_border) 769void gray_scroll_right(int count, bool black_border)
606{ 770{
607 int x, by, d; 771 int by, d;
608 unsigned char *src, *dest; 772 unsigned char *ptr;
609 unsigned char filler; 773 unsigned char filler;
610 774
611 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width) 775 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
@@ -619,17 +783,42 @@ void gray_scroll_right(int count, bool black_border)
619 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 783 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
620 for (by = 0; by < graybuf->bheight; by++) 784 for (by = 0; by < graybuf->bheight; by++)
621 { 785 {
786 ptr = graybuf->data + MULU16(graybuf->width, by);
622 for (d = 0; d < graybuf->depth; d++) 787 for (d = 0; d < graybuf->depth; d++)
623 { 788 {
624 dest = graybuf->data + graybuf->plane_size * d 789 if (count & 1) /* odd count: scroll byte-wise */
625 + graybuf->width * (by + 1) - 1; 790 asm volatile (
626 src = dest - count; 791 ".sr_loop1: \n"
627 792 "mov.b @(%2,%0),r1 \n"
628 for (x = count; x < graybuf->width; x++) 793 "mov.b r1,@-%0 \n"
629 *dest-- = *src--; 794 "cmp/hs %1,%0 \n"
630 795 "bt .sr_loop1 \n"
631 for (x = 0; x < count; x++) 796 : /* outputs */
632 *dest-- = filler; 797 : /* inputs */
798 /* %0 */ "r"(ptr + graybuf->width),
799 /* %1 */ "r"(ptr + count),
800 /* %2 */ "z"(-count - 1)
801 : /* clobbers */
802 "r1"
803 );
804 else /* even count: scroll word-wise */
805 asm volatile (
806 ".sr_loop2: \n"
807 "mov.w @(%2,%0),r1 \n"
808 "mov.w r1,@-%0 \n"
809 "cmp/hs %1,%0 \n"
810 "bt .sr_loop2 \n"
811 : /* outputs */
812 : /* inputs */
813 /* %0 */ "r"(ptr + graybuf->width),
814 /* %1 */ "r"(ptr + count),
815 /* %2 */ "z"(-count - 2)
816 : /* clobbers */
817 "r1"
818 );
819
820 rb->memset(ptr, filler, count);
821 ptr += graybuf->plane_size;
633 } 822 }
634 } 823 }
635} 824}
@@ -642,7 +831,7 @@ void gray_scroll_right(int count, bool black_border)
642void gray_scroll_up8(bool black_border) 831void gray_scroll_up8(bool black_border)
643{ 832{
644 int by, d; 833 int by, d;
645 unsigned char *src; 834 unsigned char *ptr;
646 unsigned char filler; 835 unsigned char filler;
647 836
648 if (graybuf == NULL) 837 if (graybuf == NULL)
@@ -656,18 +845,19 @@ void gray_scroll_up8(bool black_border)
656 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 845 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
657 for (by = 1; by < graybuf->bheight; by++) 846 for (by = 1; by < graybuf->bheight; by++)
658 { 847 {
848 ptr = graybuf->data + MULU16(graybuf->width, by);
659 for (d = 0; d < graybuf->depth; d++) 849 for (d = 0; d < graybuf->depth; d++)
660 { 850 {
661 src = graybuf->data + graybuf->plane_size * d 851 rb->memcpy(ptr - graybuf->width, ptr, graybuf->width);
662 + graybuf->width * by; 852 ptr += graybuf->plane_size;
663
664 rb->memcpy(src - graybuf->width, src, graybuf->width);
665 } 853 }
666 } 854 }
667 for (d = 0; d < graybuf->depth; d++) /* fill last row */ 855 /* fill last row */
856 ptr = graybuf->data + graybuf->plane_size - graybuf->width;
857 for (d = 0; d < graybuf->depth; d++)
668 { 858 {
669 rb->memset(graybuf->data + graybuf->plane_size * (d + 1) 859 rb->memset(ptr, filler, graybuf->width);
670 - graybuf->width, filler, graybuf->width); 860 ptr += graybuf->plane_size;
671 } 861 }
672} 862}
673 863
@@ -679,7 +869,7 @@ void gray_scroll_up8(bool black_border)
679void gray_scroll_down8(bool black_border) 869void gray_scroll_down8(bool black_border)
680{ 870{
681 int by, d; 871 int by, d;
682 unsigned char *dest; 872 unsigned char *ptr;
683 unsigned char filler; 873 unsigned char filler;
684 874
685 if (graybuf == NULL) 875 if (graybuf == NULL)
@@ -693,18 +883,19 @@ void gray_scroll_down8(bool black_border)
693 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 883 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
694 for (by = graybuf->bheight - 1; by > 0; by--) 884 for (by = graybuf->bheight - 1; by > 0; by--)
695 { 885 {
886 ptr = graybuf->data + MULU16(graybuf->width, by);
696 for (d = 0; d < graybuf->depth; d++) 887 for (d = 0; d < graybuf->depth; d++)
697 { 888 {
698 dest = graybuf->data + graybuf->plane_size * d 889 rb->memcpy(ptr, ptr - graybuf->width, graybuf->width);
699 + graybuf->width * by; 890 ptr += graybuf->plane_size;
700
701 rb->memcpy(dest, dest - graybuf->width, graybuf->width);
702 } 891 }
703 } 892 }
704 for (d = 0; d < graybuf->depth; d++) /* fill first row */ 893 /* fill first row */
894 ptr = graybuf->data;
895 for (d = 0; d < graybuf->depth; d++)
705 { 896 {
706 rb->memset(graybuf->data + graybuf->plane_size * d, filler, 897 rb->memset(ptr, filler, graybuf->width);
707 graybuf->width); 898 ptr += graybuf->plane_size;
708 } 899 }
709} 900}
710 901
@@ -858,8 +1049,8 @@ void gray_drawpixel(int x, int y, int brightness)
858 || (unsigned) brightness > 255) 1049 || (unsigned) brightness > 255)
859 return; 1050 return;
860 1051
861 graypixel(x, y, graybuf->bitpattern[(brightness 1052 graypixel(x, y, graybuf->bitpattern[MULU16(brightness,
862 * (graybuf->depth + 1)) >> 8]); 1053 graybuf->depth + 1) >> 8]);
863} 1054}
864 1055
865/* Invert a pixel 1056/* Invert a pixel
@@ -899,10 +1090,12 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
899 || (unsigned) brightness > 255) 1090 || (unsigned) brightness > 255)
900 return; 1091 return;
901 1092
902 pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8]; 1093 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
903 1094
904 deltax = abs(x2 - x1); 1095 deltax = abs(x2 - x1);
905 deltay = abs(y2 - y1); 1096 deltay = abs(y2 - y1);
1097 xinc2 = 1;
1098 yinc2 = 1;
906 1099
907 if (deltax >= deltay) 1100 if (deltax >= deltay)
908 { 1101 {
@@ -911,9 +1104,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
911 dinc1 = deltay * 2; 1104 dinc1 = deltay * 2;
912 dinc2 = (deltay - deltax) * 2; 1105 dinc2 = (deltay - deltax) * 2;
913 xinc1 = 1; 1106 xinc1 = 1;
914 xinc2 = 1;
915 yinc1 = 0; 1107 yinc1 = 0;
916 yinc2 = 1;
917 } 1108 }
918 else 1109 else
919 { 1110 {
@@ -922,9 +1113,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
922 dinc1 = deltax * 2; 1113 dinc1 = deltax * 2;
923 dinc2 = (deltax - deltay) * 2; 1114 dinc2 = (deltax - deltay) * 2;
924 xinc1 = 0; 1115 xinc1 = 0;
925 xinc2 = 1;
926 yinc1 = 1; 1116 yinc1 = 1;
927 yinc2 = 1;
928 } 1117 }
929 numpixels++; /* include endpoints */ 1118 numpixels++; /* include endpoints */
930 1119
@@ -985,6 +1174,8 @@ void gray_invertline(int x1, int y1, int x2, int y2)
985 1174
986 deltax = abs(x2 - x1); 1175 deltax = abs(x2 - x1);
987 deltay = abs(y2 - y1); 1176 deltay = abs(y2 - y1);
1177 xinc2 = 1;
1178 yinc2 = 1;
988 1179
989 if (deltax >= deltay) 1180 if (deltax >= deltay)
990 { 1181 {
@@ -993,9 +1184,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
993 dinc1 = deltay * 2; 1184 dinc1 = deltay * 2;
994 dinc2 = (deltay - deltax) * 2; 1185 dinc2 = (deltay - deltax) * 2;
995 xinc1 = 1; 1186 xinc1 = 1;
996 xinc2 = 1;
997 yinc1 = 0; 1187 yinc1 = 0;
998 yinc2 = 1;
999 } 1188 }
1000 else 1189 else
1001 { 1190 {
@@ -1004,9 +1193,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
1004 dinc1 = deltax * 2; 1193 dinc1 = deltax * 2;
1005 dinc2 = (deltax - deltay) * 2; 1194 dinc2 = (deltax - deltay) * 2;
1006 xinc1 = 0; 1195 xinc1 = 0;
1007 xinc2 = 1;
1008 yinc1 = 1; 1196 yinc1 = 1;
1009 yinc2 = 1;
1010 } 1197 }
1011 numpixels++; /* include endpoints */ 1198 numpixels++; /* include endpoints */
1012 1199
@@ -1053,6 +1240,7 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
1053{ 1240{
1054 int x, y; 1241 int x, y;
1055 unsigned long pattern; 1242 unsigned long pattern;
1243 unsigned char srcpixel;
1056 1244
1057 if (graybuf == NULL 1245 if (graybuf == NULL
1058 || (unsigned) x1 >= (unsigned) graybuf->width 1246 || (unsigned) x1 >= (unsigned) graybuf->width
@@ -1062,8 +1250,6 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
1062 || (unsigned) brightness > 255) 1250 || (unsigned) brightness > 255)
1063 return; 1251 return;
1064 1252
1065 pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
1066
1067 if (y1 > y2) 1253 if (y1 > y2)
1068 { 1254 {
1069 y = y1; 1255 y = y1;
@@ -1077,15 +1263,30 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
1077 x2 = x; 1263 x2 = x;
1078 } 1264 }
1079 1265
1080 for (x = x1; x <= x2; x++) 1266 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1267 srcpixel = brightness;
1268
1269 for (x = x1 + 1; x < x2; x++)
1081 { 1270 {
1082 graypixel(x, y1, pattern); 1271 graypixel(x, y1, pattern);
1083 graypixel(x, y2, pattern); 1272 graypixel(x, y2, pattern);
1084 } 1273 }
1085 for (y = y1; y <= y2; y++) 1274 for (y = y1; y <= y2; )
1086 { 1275 {
1087 graypixel(x1, y, pattern); 1276 if (!(y & 7) && (y2 - y >= 7))
1088 graypixel(x2, y, pattern); 1277 /* current row byte aligned in fb & at least 8 rows left */
1278 {
1279 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1280 grayblock(x1, y >> 3, &srcpixel, 0);
1281 grayblock(x2, y >> 3, &srcpixel, 0);
1282 y += 8;
1283 }
1284 else
1285 {
1286 graypixel(x1, y, pattern);
1287 graypixel(x2, y, pattern);
1288 y++;
1289 }
1089 } 1290 }
1090} 1291}
1091 1292
@@ -1098,6 +1299,7 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
1098{ 1299{
1099 int x, y; 1300 int x, y;
1100 unsigned long pattern; 1301 unsigned long pattern;
1302 unsigned char srcpixel;
1101 1303
1102 if (graybuf == NULL 1304 if (graybuf == NULL
1103 || (unsigned) x1 >= (unsigned) graybuf->width 1305 || (unsigned) x1 >= (unsigned) graybuf->width
@@ -1120,13 +1322,28 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
1120 x2 = x; 1322 x2 = x;
1121 } 1323 }
1122 1324
1123 pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8]; 1325 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1326 srcpixel = brightness;
1124 1327
1125 for (y = y1; y <= y2; y++) 1328 for (y = y1; y <= y2; )
1126 { 1329 {
1127 for (x = x1; x <= x2; x++) 1330 if (!(y & 7) && (y2 - y >= 7))
1331 /* current row byte aligned in fb & at least 8 rows left */
1332 {
1333 for (x = x1; x <= x2; x++)
1334 {
1335 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1336 grayblock(x, y >> 3, &srcpixel, 0);
1337 }
1338 y += 8;
1339 }
1340 else
1128 { 1341 {
1129 graypixel(x, y, pattern); 1342 for (x = x1; x <= x2; x++)
1343 {
1344 graypixel(x, y, pattern);
1345 }
1346 y++;
1130 } 1347 }
1131 } 1348 }
1132} 1349}
@@ -1218,14 +1435,30 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
1218 if ((x + nx) >= graybuf->width) /* clip right */ 1435 if ((x + nx) >= graybuf->width) /* clip right */
1219 nx = graybuf->width - x; 1436 nx = graybuf->width - x;
1220 1437
1221 for (yi = y; yi < y + ny; yi++) 1438 for (yi = y; yi < y + ny; )
1222 { 1439 {
1223 row = src; 1440 row = src;
1224 src += stride; 1441
1225 for (xi = x; xi < x + nx; xi++) 1442 if (!(yi & 7) && (y + ny - yi > 7))
1443 /* current row byte aligned in fb & at least 8 rows left */
1444 {
1445 for (xi = x; xi < x + nx; xi++)
1446 {
1447 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1448 grayblock(xi, yi >> 3, row++, stride);
1449 }
1450 yi += 8;
1451 src += stride << 3;
1452 }
1453 else
1226 { 1454 {
1227 graypixel(xi, yi, graybuf->bitpattern[((int)(*row++) 1455 for (xi = x; xi < x + nx; xi++)
1228 * (graybuf->depth + 1)) >> 8]); 1456 {
1457 graypixel(xi, yi, graybuf->bitpattern[MULU16(*row++,
1458 graybuf->depth + 1) >> 8]);
1459 }
1460 yi++;
1461 src += stride;
1229 } 1462 }
1230 } 1463 }
1231} 1464}
@@ -1258,7 +1491,7 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1258 unsigned long fg_pattern, bg_pattern; 1491 unsigned long fg_pattern, bg_pattern;
1259 unsigned char *col; 1492 unsigned char *col;
1260 1493
1261 if (graybuf == NULL 1494 if (graybuf == NULL
1262 || (unsigned) x >= (unsigned) graybuf->width 1495 || (unsigned) x >= (unsigned) graybuf->width
1263 || (unsigned) y >= (unsigned) graybuf->height 1496 || (unsigned) y >= (unsigned) graybuf->height
1264 || (unsigned) fg_brightness > 255 1497 || (unsigned) fg_brightness > 255
@@ -1271,11 +1504,11 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1271 if ((x + nx) >= graybuf->width) /* clip right */ 1504 if ((x + nx) >= graybuf->width) /* clip right */
1272 nx = graybuf->width - x; 1505 nx = graybuf->width - x;
1273 1506
1274 fg_pattern = graybuf->bitpattern[(fg_brightness 1507 fg_pattern = graybuf->bitpattern[MULU16(fg_brightness,
1275 * (graybuf->depth + 1)) >> 8]; 1508 graybuf->depth + 1) >> 8];
1276 1509
1277 bg_pattern = graybuf->bitpattern[(bg_brightness 1510 bg_pattern = graybuf->bitpattern[MULU16(bg_brightness,
1278 * (graybuf->depth + 1)) >> 8]; 1511 graybuf->depth + 1) >> 8];
1279 1512
1280 for (xi = x; xi < x + nx; xi++) 1513 for (xi = x; xi < x + nx; xi++)
1281 { 1514 {
@@ -1410,7 +1643,7 @@ int main(void)
1410 1643
1411 gray_fillrect(0, 0, 111, 55, 150); /* fill everything with gray 150 */ 1644 gray_fillrect(0, 0, 111, 55, 150); /* fill everything with gray 150 */
1412 1645
1413 /* draw a dark gray star background */ 1646 /* draw a dark gray line star background */
1414 for (y = 0; y < 56; y += 8) /* horizontal part */ 1647 for (y = 0; y < 56; y += 8) /* horizontal part */
1415 { 1648 {
1416 gray_drawline(0, y, 111, 55 - y, 80); /* gray lines */ 1649 gray_drawline(0, y, 111, 55 - y, 80); /* gray lines */
@@ -1466,7 +1699,7 @@ int main(void)
1466 black_border = true; 1699 black_border = true;
1467 1700
1468 if (button & BUTTON_REPEAT) 1701 if (button & BUTTON_REPEAT)
1469 scroll_amount = 3; 1702 scroll_amount = 4;
1470 1703
1471 switch(button & ~(BUTTON_ON | BUTTON_REPEAT)) 1704 switch(button & ~(BUTTON_ON | BUTTON_REPEAT))
1472 { 1705 {