1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Dave Chapman
12 * Rockbox driver for 16-bit colour LCDs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
30 #include "string-extra.h" /* mem*() */
35 #include "rbunicode.h"
37 #include "scroll_engine.h"
46 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
47 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
50 static fb_data
* lcd_backdrop
= NULL
;
51 static long lcd_backdrop_offset IDATA_ATTR
= 0;
53 static struct viewport default_vp
=
59 .font
= FONT_SYSFIXED
,
60 .drawmode
= DRMODE_SOLID
,
61 .fg_pattern
= LCD_DEFAULT_FG
,
62 .bg_pattern
= LCD_DEFAULT_BG
,
63 .lss_pattern
= LCD_DEFAULT_BG
,
64 .lse_pattern
= LCD_DEFAULT_BG
,
65 .lst_pattern
= LCD_DEFAULT_BG
,
68 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
75 /* Call device specific init */
81 void lcd_set_viewport(struct viewport
* vp
)
84 current_vp
= &default_vp
;
88 #if defined(SIMULATOR)
89 /* Force the viewport to be within bounds. If this happens it should
90 * be considered an error - the viewport will not draw as it might be
93 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
94 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
95 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
96 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
98 #if !defined(HAVE_VIEWPORT_CLIP)
103 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
104 current_vp
->x
, current_vp
->y
,
105 current_vp
->width
, current_vp
->height
);
111 void lcd_update_viewport(void)
113 lcd_update_rect(current_vp
->x
, current_vp
->y
,
114 current_vp
->width
, current_vp
->height
);
117 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
119 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
122 /*** parameter handling ***/
124 void lcd_set_drawmode(int mode
)
126 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
129 int lcd_get_drawmode(void)
131 return current_vp
->drawmode
;
134 void lcd_set_foreground(unsigned color
)
136 current_vp
->fg_pattern
= color
;
139 unsigned lcd_get_foreground(void)
141 return current_vp
->fg_pattern
;
144 void lcd_set_background(unsigned color
)
146 current_vp
->bg_pattern
= color
;
149 unsigned lcd_get_background(void)
151 return current_vp
->bg_pattern
;
154 void lcd_set_selector_start(unsigned color
)
156 current_vp
->lss_pattern
= color
;
159 void lcd_set_selector_end(unsigned color
)
161 current_vp
->lse_pattern
= color
;
164 void lcd_set_selector_text(unsigned color
)
166 current_vp
->lst_pattern
= color
;
169 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
171 lcd_set_drawmode(mode
);
172 current_vp
->fg_pattern
= fg_color
;
173 current_vp
->bg_pattern
= bg_color
;
176 int lcd_getwidth(void)
178 return current_vp
->width
;
181 int lcd_getheight(void)
183 return current_vp
->height
;
186 void lcd_setfont(int newfont
)
188 current_vp
->font
= newfont
;
191 int lcd_getfont(void)
193 return current_vp
->font
;
196 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
198 return font_getstringsize(str
, w
, h
, current_vp
->font
);
201 /*** low-level drawing functions ***/
203 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
205 static void ICODE_ATTR
setpixel(fb_data
*address
)
207 *address
= current_vp
->fg_pattern
;
210 static void ICODE_ATTR
clearpixel(fb_data
*address
)
212 *address
= current_vp
->bg_pattern
;
215 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
217 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
220 static void ICODE_ATTR
flippixel(fb_data
*address
)
222 *address
= ~(*address
);
225 static void ICODE_ATTR
nopixel(fb_data
*address
)
230 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
231 flippixel
, nopixel
, setpixel
, setpixel
,
232 nopixel
, clearpixel
, nopixel
, clearpixel
235 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
236 flippixel
, nopixel
, setpixel
, setpixel
,
237 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
240 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
242 void lcd_set_backdrop(fb_data
* backdrop
)
244 lcd_backdrop
= backdrop
;
247 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
248 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
252 lcd_backdrop_offset
= 0;
253 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
257 fb_data
* lcd_get_backdrop(void)
262 /*** drawing functions ***/
264 /* Clear the current viewport */
265 void lcd_clear_viewport(void)
267 fb_data
*dst
, *dst_end
;
269 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
270 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
272 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
276 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
279 while (dst
< dst_end
);
287 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
290 while (dst
< dst_end
);
296 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
297 current_vp
->width
* sizeof(fb_data
));
300 while (dst
< dst_end
);
304 if (current_vp
== &default_vp
)
306 lcd_scroll_info
.lines
= 0;
310 lcd_scroll_stop(current_vp
);
314 /* Clear the whole display */
315 void lcd_clear_display(void)
317 struct viewport
* old_vp
= current_vp
;
319 current_vp
= &default_vp
;
321 lcd_clear_viewport();
326 /* Set a single pixel */
327 void lcd_drawpixel(int x
, int y
)
329 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
330 && ((unsigned)y
< (unsigned)current_vp
->height
)
331 #if defined(HAVE_VIEWPORT_CLIP)
332 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
333 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
336 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
340 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
348 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
350 deltay
= abs(y2
- y1
);
353 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
354 lcd_hline(x1
, x2
, y1
);
357 deltax
= abs(x2
- x1
);
360 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
361 lcd_vline(x1
, y1
, y2
);
367 if (deltax
>= deltay
)
370 d
= 2 * deltay
- deltax
;
372 dinc2
= (deltay
- deltax
) * 2;
379 d
= 2 * deltax
- deltay
;
381 dinc2
= (deltax
- deltay
) * 2;
385 numpixels
++; /* include endpoints */
402 for (i
= 0; i
< numpixels
; i
++)
404 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
405 && ((unsigned)y
< (unsigned)current_vp
->height
)
406 #if defined(HAVE_VIEWPORT_CLIP)
407 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
408 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
411 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
428 /* Draw a horizontal line (optimised) */
429 void lcd_hline(int x1
, int x2
, int y
)
433 enum fill_opt fillopt
= OPT_NONE
;
434 fb_data
*dst
, *dst_end
;
444 /******************** In viewport clipping **********************/
445 /* nothing to draw? */
446 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
447 (x1
>= current_vp
->width
) ||
453 if (x2
>= current_vp
->width
)
454 x2
= current_vp
->width
-1;
456 /* Adjust x1 and y to viewport */
461 #if defined(HAVE_VIEWPORT_CLIP)
462 /********************* Viewport on screen clipping ********************/
463 /* nothing to draw? */
464 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
477 /* drawmode and optimisation */
478 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
480 if (current_vp
->drawmode
& DRMODE_BG
)
485 bits
= current_vp
->bg_pattern
;
493 if (current_vp
->drawmode
& DRMODE_FG
)
496 bits
= current_vp
->fg_pattern
;
499 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
502 dst
= LCDADDR(x1
, y
);
507 memset16(dst
, bits
, width
);
511 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
512 width
* sizeof(fb_data
));
515 case OPT_NONE
: /* DRMODE_COMPLEMENT */
516 dst_end
= dst
+ width
;
519 while (++dst
< dst_end
);
524 /* Draw a vertical line (optimised) */
525 void lcd_vline(int x
, int y1
, int y2
)
528 fb_data
*dst
, *dst_end
;
529 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
539 /******************** In viewport clipping **********************/
540 /* nothing to draw? */
541 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
542 (y1
>= current_vp
->height
) ||
548 if (y2
>= current_vp
->height
)
549 y2
= current_vp
->height
-1;
551 /* adjust for viewport */
556 #if defined(HAVE_VIEWPORT_CLIP)
557 /********************* Viewport on screen clipping ********************/
558 /* nothing to draw? */
559 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
566 if (y2
>= LCD_HEIGHT
)
570 dst
= LCDADDR(x
, y1
);
571 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
578 while (dst
<= dst_end
);
581 /* Draw a rectangular box */
582 void lcd_drawrect(int x
, int y
, int width
, int height
)
584 if ((width
<= 0) || (height
<= 0))
587 int x2
= x
+ width
- 1;
588 int y2
= y
+ height
- 1;
591 lcd_vline(x2
, y
, y2
);
593 lcd_hline(x
, x2
, y2
);
596 /* Fill a rectangular area */
597 void lcd_fillrect(int x
, int y
, int width
, int height
)
600 enum fill_opt fillopt
= OPT_NONE
;
601 fb_data
*dst
, *dst_end
;
603 /******************** In viewport clipping **********************/
604 /* nothing to draw? */
605 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
606 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
619 if (x
+ width
> current_vp
->width
)
620 width
= current_vp
->width
- x
;
621 if (y
+ height
> current_vp
->height
)
622 height
= current_vp
->height
- y
;
624 /* adjust for viewport */
628 #if defined(HAVE_VIEWPORT_CLIP)
629 /********************* Viewport on screen clipping ********************/
630 /* nothing to draw? */
631 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
632 || (x
+ width
<= 0) || (y
+ height
<= 0))
635 /* clip image in viewport in screen */
646 if (x
+ width
> LCD_WIDTH
)
647 width
= LCD_WIDTH
- x
;
648 if (y
+ height
> LCD_HEIGHT
)
649 height
= LCD_HEIGHT
- y
;
652 /* drawmode and optimisation */
653 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
655 if (current_vp
->drawmode
& DRMODE_BG
)
660 bits
= current_vp
->bg_pattern
;
668 if (current_vp
->drawmode
& DRMODE_FG
)
671 bits
= current_vp
->fg_pattern
;
674 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
678 dst_end
= dst
+ height
* LCD_WIDTH
;
682 fb_data
*dst_row
, *row_end
;
687 memset16(dst
, bits
, width
);
691 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
692 width
* sizeof(fb_data
));
695 case OPT_NONE
: /* DRMODE_COMPLEMENT */
697 row_end
= dst_row
+ width
;
699 *dst_row
= ~(*dst_row
);
700 while (++dst_row
< row_end
);
705 while (dst
< dst_end
);
708 /* About Rockbox' internal monochrome bitmap format:
710 * A bitmap contains one bit for every pixel that defines if that pixel is
711 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
713 * The bytes are stored in row-major order, with byte 0 being top left,
714 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
715 * 0..7, the second row defines pixel row 8..15 etc.
717 * This is the mono bitmap format used on all other targets so far; the
718 * pixel packing doesn't really matter on a 8bit+ target. */
720 /* Draw a partial monochrome bitmap */
722 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
723 int src_y
, int stride
, int x
, int y
,
724 int width
, int height
)
726 const unsigned char *src_end
;
727 fb_data
*dst
, *dst_end
;
728 unsigned dmask
= 0x100; /* bit 8 == sentinel */
729 int drmode
= current_vp
->drawmode
;
731 /******************** Image in viewport clipping **********************/
732 /* nothing to draw? */
733 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
734 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
749 if (x
+ width
> current_vp
->width
)
750 width
= current_vp
->width
- x
;
751 if (y
+ height
> current_vp
->height
)
752 height
= current_vp
->height
- y
;
754 /* adjust for viewport */
758 #if defined(HAVE_VIEWPORT_CLIP)
759 /********************* Viewport on screen clipping ********************/
760 /* nothing to draw? */
761 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
762 || (x
+ width
<= 0) || (y
+ height
<= 0))
765 /* clip image in viewport in screen */
778 if (x
+ width
> LCD_WIDTH
)
779 width
= LCD_WIDTH
- x
;
780 if (y
+ height
> LCD_HEIGHT
)
781 height
= LCD_HEIGHT
- y
;
784 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
786 src_end
= src
+ width
;
788 dst_end
= dst
+ height
* LCD_WIDTH
;
790 if (drmode
& DRMODE_INVERSEVID
)
792 dmask
= 0x1ff; /* bit 8 == sentinel */
793 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
798 const unsigned char *src_col
= src
++;
799 unsigned data
= (*src_col
^ dmask
) >> src_y
;
800 fb_data
*dst_col
= dst
++;
804 #define UPDATE_SRC do { \
806 if (data == 0x001) { \
808 data = *src_col ^ dmask; \
814 case DRMODE_COMPLEMENT
:
818 *dst_col
= ~(*dst_col
);
820 dst_col
+= LCD_WIDTH
;
823 while (dst_col
< dst_end
);
829 bo
= lcd_backdrop_offset
;
833 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
835 dst_col
+= LCD_WIDTH
;
838 while (dst_col
< dst_end
);
842 bg
= current_vp
->bg_pattern
;
848 dst_col
+= LCD_WIDTH
;
851 while (dst_col
< dst_end
);
856 fg
= current_vp
->fg_pattern
;
862 dst_col
+= LCD_WIDTH
;
865 while (dst_col
< dst_end
);
869 fg
= current_vp
->fg_pattern
;
872 bo
= lcd_backdrop_offset
;
875 *dst_col
= (data
& 0x01) ? fg
876 : *(fb_data
*)((long)dst_col
+ bo
);
877 dst_col
+= LCD_WIDTH
;
880 while (dst_col
< dst_end
);
884 bg
= current_vp
->bg_pattern
;
887 *dst_col
= (data
& 0x01) ? fg
: bg
;
888 dst_col
+= LCD_WIDTH
;
891 while (dst_col
< dst_end
);
896 while (src
< src_end
);
898 /* Draw a full monochrome bitmap */
899 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
901 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
904 /* draw alpha bitmap for anti-alias font */
905 #define ALPHA_COLOR_FONT_DEPTH 2
906 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
907 #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
908 #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
909 #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
911 #define BLEND_INIT do {} while (0)
912 #define BLEND_START(acc, color, alpha) \
913 asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
914 #define BLEND_CONT(acc, color, alpha) \
915 asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
916 #define BLEND_OUT(acc) do {} while (0)
917 #elif defined(CPU_COLDFIRE)
918 #define ALPHA_BITMAP_READ_WORDS
919 #define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED)
920 #define BLEND_START(acc, color, alpha) \
921 asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
922 #define BLEND_CONT BLEND_START
923 #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
925 #define BLEND_INIT do {} while (0)
926 #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
927 #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
928 #define BLEND_OUT(acc) do {} while (0)
931 /* Blend the given two colors */
932 static inline unsigned blend_two_colors(unsigned c1
, unsigned c2
, unsigned a
)
934 a
+= a
>> (ALPHA_COLOR_LOOKUP_SHIFT
- 1);
935 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
939 unsigned c1l
= (c1
| (c1
<< 16)) & 0x07e0f81f;
940 unsigned c2l
= (c2
| (c2
<< 16)) & 0x07e0f81f;
942 BLEND_START(p
, c1l
, a
);
943 BLEND_CONT(p
, c2l
, ALPHA_COLOR_LOOKUP_SIZE
+ 1 - a
);
945 p
= (p
>> ALPHA_COLOR_LOOKUP_SHIFT
) & 0x07e0f81f;
947 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
954 /* Blend the given color with the value from the alpha_color_lookup table */
955 static inline unsigned blend_color(unsigned c
, unsigned a
)
957 return blend_two_colors(c
, current_vp
->fg_pattern
, a
);
960 void ICODE_ATTR
lcd_alpha_bitmap_part(const unsigned char *src
, int src_x
,
961 int src_y
, int stride
, int x
, int y
,
962 int width
, int height
)
964 fb_data
*dst
, *backdrop
;
965 unsigned dmask
= 0x00000000;
966 int drmode
= current_vp
->drawmode
;
967 /* nothing to draw? */
968 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
969 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
971 /* initialize blending */
987 if (x
+ width
> current_vp
->width
)
988 width
= current_vp
->width
- x
;
989 if (y
+ height
> current_vp
->height
)
990 height
= current_vp
->height
- y
;
992 if (drmode
& DRMODE_INVERSEVID
)
995 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
997 if (drmode
== DRMODE_BG
)
1002 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
1004 int col
, row
= height
;
1005 unsigned data
, pixels
;
1006 unsigned skip_end
= (stride
- width
);
1007 unsigned skip_start
= src_y
* stride
+ src_x
;
1009 #ifdef ALPHA_BITMAP_READ_WORDS
1010 uint32_t *src_w
= (uint32_t *)((uintptr_t)src
& ~3);
1011 skip_start
+= ALPHA_COLOR_PIXEL_PER_BYTE
* ((uintptr_t)src
& 3);
1012 src_w
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_WORD
;
1013 data
= letoh32(*src_w
++) ^ dmask
;
1014 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_WORD
;
1016 src
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
1017 data
= *src
^ dmask
;
1018 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_BYTE
;
1020 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
1021 #ifdef ALPHA_BITMAP_READ_WORDS
1022 pixels
= 8 - pixels
;
1028 #ifdef ALPHA_BITMAP_READ_WORDS
1029 #define UPDATE_SRC_ALPHA do { \
1031 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
1034 data = letoh32(*src_w++) ^ dmask; \
1035 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
1038 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
1039 #define UPDATE_SRC_ALPHA do { \
1041 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
1043 data = *(++src) ^ dmask; \
1046 #define UPDATE_SRC_ALPHA do { \
1047 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
1048 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
1050 data = *(++src) ^ dmask; \
1053 /* we don't want to have this in our inner
1054 * loop and the codesize increase is minimal */
1057 case DRMODE_COMPLEMENT
:
1060 *dst
=blend_two_colors(*dst
, ~(*dst
),
1061 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1070 backdrop
= (fb_data
*)((long)dst
+lcd_backdrop_offset
);
1073 *dst
=blend_two_colors(*dst
, *(backdrop
++),
1074 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1084 *dst
=blend_two_colors(*dst
, current_vp
->bg_pattern
,
1085 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1095 *dst
=blend_color(*dst
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
1104 backdrop
= (fb_data
*)((long)dst
+lcd_backdrop_offset
);
1107 *(dst
++)=blend_color(*(backdrop
++),
1108 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1117 *(dst
++)=blend_color(current_vp
->bg_pattern
,
1118 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1125 #ifdef ALPHA_BITMAP_READ_WORDS
1126 if (skip_end
< pixels
)
1129 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
1131 pixels
= skip_end
- pixels
;
1132 src_w
+= pixels
/ ALPHA_COLOR_PIXEL_PER_WORD
;
1133 pixels
%= ALPHA_COLOR_PIXEL_PER_WORD
;
1134 data
= letoh32(*src_w
++) ^ dmask
;
1135 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
1136 pixels
= 8 - pixels
;
1142 if (pixels
>= ALPHA_COLOR_PIXEL_PER_BYTE
)
1144 src
+= pixels
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
1145 pixels
%= ALPHA_COLOR_PIXEL_PER_BYTE
;
1146 data
= *src
^ dmask
;
1147 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
1149 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
1152 dst
+= LCD_WIDTH
- width
;
1156 /* Draw a partial native bitmap */
1157 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
1158 int stride
, int x
, int y
, int width
,
1163 /******************** Image in viewport clipping **********************/
1164 /* nothing to draw? */
1165 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
1166 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1182 if (x
+ width
> current_vp
->width
)
1183 width
= current_vp
->width
- x
;
1184 if (y
+ height
> current_vp
->height
)
1185 height
= current_vp
->height
- y
;
1187 /* adjust for viewport */
1191 #if defined(HAVE_VIEWPORT_CLIP)
1192 /********************* Viewport on screen clipping ********************/
1193 /* nothing to draw? */
1194 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1195 || (x
+ width
<= 0) || (y
+ height
<= 0))
1198 /* clip image in viewport in screen */
1211 if (x
+ width
> LCD_WIDTH
)
1212 width
= LCD_WIDTH
- x
;
1213 if (y
+ height
> LCD_HEIGHT
)
1214 height
= LCD_HEIGHT
- y
;
1217 src
+= stride
* src_y
+ src_x
; /* move starting point */
1218 dst
= LCDADDR(x
, y
);
1222 memcpy(dst
, src
, width
* sizeof(fb_data
));
1226 while (--height
> 0);
1229 /* Draw a full native bitmap */
1230 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
1232 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1235 /* Draw a partial native bitmap with transparency and foreground colors */
1236 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
1237 int src_y
, int stride
, int x
,
1238 int y
, int width
, int height
)
1241 unsigned fg
= current_vp
->fg_pattern
;
1243 /******************** Image in viewport clipping **********************/
1244 /* nothing to draw? */
1245 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
1246 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1262 if (x
+ width
> current_vp
->width
)
1263 width
= current_vp
->width
- x
;
1264 if (y
+ height
> current_vp
->height
)
1265 height
= current_vp
->height
- y
;
1267 /* adjust for viewport */
1271 #if defined(HAVE_VIEWPORT_CLIP)
1272 /********************* Viewport on screen clipping ********************/
1273 /* nothing to draw? */
1274 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1275 || (x
+ width
<= 0) || (y
+ height
<= 0))
1278 /* clip image in viewport in screen */
1291 if (x
+ width
> LCD_WIDTH
)
1292 width
= LCD_WIDTH
- x
;
1293 if (y
+ height
> LCD_HEIGHT
)
1294 height
= LCD_HEIGHT
- y
;
1297 src
+= stride
* src_y
+ src_x
; /* move starting point */
1298 dst
= LCDADDR(x
, y
);
1305 "mov %[w], %[width] \n" /* Load width for inner loop */
1307 "ldrh %[px], [%[s]], #2 \n" /* Load src pixel */
1308 "add %[d], %[d], #2 \n" /* Uncoditionally increment dst */
1309 /* done here for better pipelining */
1310 "cmp %[px], %[fgcolor] \n" /* Compare to foreground color */
1311 "streqh %[fgpat], [%[d], #-2] \n" /* Store foregroud if match */
1312 "cmpne %[px], %[transcolor] \n" /* Compare to transparent color */
1313 "strneh %[px], [%[d], #-2] \n" /* Store dst if not transparent */
1314 "subs %[w], %[w], #1 \n" /* Width counter has run down? */
1315 "bgt .nextpixel \n" /* More in this row? */
1316 "add %[s], %[s], %[sstp], lsl #1 \n" /* Skip over to start of next line */
1317 "add %[d], %[d], %[dstp], lsl #1 \n"
1318 "subs %[h], %[h], #1 \n" /* Height counter has run down? */
1319 "bgt .rowstart \n" /* More rows? */
1320 : [w
]"=&r"(w
), [h
]"+&r"(height
), [px
]"=&r"(px
),
1321 [s
]"+&r"(src
), [d
]"+&r"(dst
)
1322 : [width
]"r"(width
),
1323 [sstp
]"r"(stride
- width
),
1324 [dstp
]"r"(LCD_WIDTH
- width
),
1325 [transcolor
]"r"(TRANSPARENT_COLOR
),
1326 [fgcolor
]"r"(REPLACEWITHFG_COLOR
),
1330 #else /* optimized C version */
1333 const fb_data
*src_row
= src
;
1334 fb_data
*dst_row
= dst
;
1335 fb_data
*row_end
= dst_row
+ width
;
1338 unsigned data
= *src_row
++;
1339 if (data
!= TRANSPARENT_COLOR
)
1341 if (data
== REPLACEWITHFG_COLOR
)
1346 while (++dst_row
< row_end
);
1350 while (--height
> 0);
1354 /* Draw a full native bitmap with transparent and foreground colors */
1355 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
1356 int width
, int height
)
1358 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
1361 #include "lcd-bitmap-common.c"