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 ****************************************************************************/
36 #include "rbunicode.h"
38 #include "scroll_engine.h"
47 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
48 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
51 static fb_data
* lcd_backdrop
= NULL
;
52 static long lcd_backdrop_offset IDATA_ATTR
= 0;
54 static struct viewport default_vp
=
60 .font
= FONT_SYSFIXED
,
61 .drawmode
= DRMODE_SOLID
,
62 .fg_pattern
= LCD_DEFAULT_FG
,
63 .bg_pattern
= LCD_DEFAULT_BG
,
64 .lss_pattern
= LCD_DEFAULT_BG
,
65 .lse_pattern
= LCD_DEFAULT_BG
,
66 .lst_pattern
= LCD_DEFAULT_BG
,
69 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
76 /* Call device specific init */
82 void lcd_set_viewport(struct viewport
* vp
)
85 current_vp
= &default_vp
;
89 #if defined(SIMULATOR)
90 /* Force the viewport to be within bounds. If this happens it should
91 * be considered an error - the viewport will not draw as it might be
94 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
95 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
96 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
97 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
99 #if !defined(HAVE_VIEWPORT_CLIP)
104 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
105 current_vp
->x
, current_vp
->y
,
106 current_vp
->width
, current_vp
->height
);
112 void lcd_update_viewport(void)
114 lcd_update_rect(current_vp
->x
, current_vp
->y
,
115 current_vp
->width
, current_vp
->height
);
118 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
120 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
123 /*** parameter handling ***/
125 void lcd_set_drawmode(int mode
)
127 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
130 int lcd_get_drawmode(void)
132 return current_vp
->drawmode
;
135 void lcd_set_foreground(unsigned color
)
137 current_vp
->fg_pattern
= color
;
140 unsigned lcd_get_foreground(void)
142 return current_vp
->fg_pattern
;
145 void lcd_set_background(unsigned color
)
147 current_vp
->bg_pattern
= color
;
150 unsigned lcd_get_background(void)
152 return current_vp
->bg_pattern
;
155 void lcd_set_selector_start(unsigned color
)
157 current_vp
->lss_pattern
= color
;
160 void lcd_set_selector_end(unsigned color
)
162 current_vp
->lse_pattern
= color
;
165 void lcd_set_selector_text(unsigned color
)
167 current_vp
->lst_pattern
= color
;
170 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
172 lcd_set_drawmode(mode
);
173 current_vp
->fg_pattern
= fg_color
;
174 current_vp
->bg_pattern
= bg_color
;
177 int lcd_getwidth(void)
179 return current_vp
->width
;
182 int lcd_getheight(void)
184 return current_vp
->height
;
187 void lcd_setfont(int newfont
)
189 current_vp
->font
= newfont
;
192 int lcd_getfont(void)
194 return current_vp
->font
;
197 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
199 return font_getstringsize(str
, w
, h
, current_vp
->font
);
202 /*** low-level drawing functions ***/
204 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
206 static void ICODE_ATTR
setpixel(fb_data
*address
)
208 *address
= current_vp
->fg_pattern
;
211 static void ICODE_ATTR
clearpixel(fb_data
*address
)
213 *address
= current_vp
->bg_pattern
;
216 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
218 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
221 static void ICODE_ATTR
flippixel(fb_data
*address
)
223 *address
= ~(*address
);
226 static void ICODE_ATTR
nopixel(fb_data
*address
)
231 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
232 flippixel
, nopixel
, setpixel
, setpixel
,
233 nopixel
, clearpixel
, nopixel
, clearpixel
236 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
237 flippixel
, nopixel
, setpixel
, setpixel
,
238 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
241 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
243 void lcd_set_backdrop(fb_data
* backdrop
)
245 lcd_backdrop
= backdrop
;
248 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
249 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
253 lcd_backdrop_offset
= 0;
254 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
258 fb_data
* lcd_get_backdrop(void)
263 /*** drawing functions ***/
265 /* Clear the current viewport */
266 void lcd_clear_viewport(void)
268 fb_data
*dst
, *dst_end
;
270 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
271 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
273 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
277 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
280 while (dst
< dst_end
);
288 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
291 while (dst
< dst_end
);
297 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
298 current_vp
->width
* sizeof(fb_data
));
301 while (dst
< dst_end
);
305 if (current_vp
== &default_vp
)
307 lcd_scroll_info
.lines
= 0;
311 lcd_scroll_stop(current_vp
);
315 /* Clear the whole display */
316 void lcd_clear_display(void)
318 struct viewport
* old_vp
= current_vp
;
320 current_vp
= &default_vp
;
322 lcd_clear_viewport();
327 /* Set a single pixel */
328 void lcd_drawpixel(int x
, int y
)
330 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
331 && ((unsigned)y
< (unsigned)current_vp
->height
)
332 #if defined(HAVE_VIEWPORT_CLIP)
333 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
334 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
337 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
341 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
349 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
351 deltay
= abs(y2
- y1
);
354 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
355 lcd_hline(x1
, x2
, y1
);
358 deltax
= abs(x2
- x1
);
361 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
362 lcd_vline(x1
, y1
, y2
);
368 if (deltax
>= deltay
)
371 d
= 2 * deltay
- deltax
;
373 dinc2
= (deltay
- deltax
) * 2;
380 d
= 2 * deltax
- deltay
;
382 dinc2
= (deltax
- deltay
) * 2;
386 numpixels
++; /* include endpoints */
403 for (i
= 0; i
< numpixels
; i
++)
405 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
406 && ((unsigned)y
< (unsigned)current_vp
->height
)
407 #if defined(HAVE_VIEWPORT_CLIP)
408 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
409 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
412 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
429 /* Draw a horizontal line (optimised) */
430 void lcd_hline(int x1
, int x2
, int y
)
434 enum fill_opt fillopt
= OPT_NONE
;
435 fb_data
*dst
, *dst_end
;
445 /******************** In viewport clipping **********************/
446 /* nothing to draw? */
447 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
448 (x1
>= current_vp
->width
) ||
454 if (x2
>= current_vp
->width
)
455 x2
= current_vp
->width
-1;
457 /* Adjust x1 and y to viewport */
462 #if defined(HAVE_VIEWPORT_CLIP)
463 /********************* Viewport on screen clipping ********************/
464 /* nothing to draw? */
465 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
478 /* drawmode and optimisation */
479 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
481 if (current_vp
->drawmode
& DRMODE_BG
)
486 bits
= current_vp
->bg_pattern
;
494 if (current_vp
->drawmode
& DRMODE_FG
)
497 bits
= current_vp
->fg_pattern
;
500 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
503 dst
= LCDADDR(x1
, y
);
508 memset16(dst
, bits
, width
);
512 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
513 width
* sizeof(fb_data
));
516 case OPT_NONE
: /* DRMODE_COMPLEMENT */
517 dst_end
= dst
+ width
;
520 while (++dst
< dst_end
);
525 /* Draw a vertical line (optimised) */
526 void lcd_vline(int x
, int y1
, int y2
)
529 fb_data
*dst
, *dst_end
;
530 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
540 /******************** In viewport clipping **********************/
541 /* nothing to draw? */
542 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
543 (y1
>= current_vp
->height
) ||
549 if (y2
>= current_vp
->height
)
550 y2
= current_vp
->height
-1;
552 /* adjust for viewport */
557 #if defined(HAVE_VIEWPORT_CLIP)
558 /********************* Viewport on screen clipping ********************/
559 /* nothing to draw? */
560 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
567 if (y2
>= LCD_HEIGHT
)
571 dst
= LCDADDR(x
, y1
);
572 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
579 while (dst
<= dst_end
);
582 /* Draw a rectangular box */
583 void lcd_drawrect(int x
, int y
, int width
, int height
)
585 if ((width
<= 0) || (height
<= 0))
588 int x2
= x
+ width
- 1;
589 int y2
= y
+ height
- 1;
592 lcd_vline(x2
, y
, y2
);
594 lcd_hline(x
, x2
, y2
);
597 /* Fill a rectangular area */
598 void lcd_fillrect(int x
, int y
, int width
, int height
)
601 enum fill_opt fillopt
= OPT_NONE
;
602 fb_data
*dst
, *dst_end
;
604 /******************** In viewport clipping **********************/
605 /* nothing to draw? */
606 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
607 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
620 if (x
+ width
> current_vp
->width
)
621 width
= current_vp
->width
- x
;
622 if (y
+ height
> current_vp
->height
)
623 height
= current_vp
->height
- y
;
625 /* adjust for viewport */
629 #if defined(HAVE_VIEWPORT_CLIP)
630 /********************* Viewport on screen clipping ********************/
631 /* nothing to draw? */
632 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
633 || (x
+ width
<= 0) || (y
+ height
<= 0))
636 /* clip image in viewport in screen */
647 if (x
+ width
> LCD_WIDTH
)
648 width
= LCD_WIDTH
- x
;
649 if (y
+ height
> LCD_HEIGHT
)
650 height
= LCD_HEIGHT
- y
;
653 /* drawmode and optimisation */
654 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
656 if (current_vp
->drawmode
& DRMODE_BG
)
661 bits
= current_vp
->bg_pattern
;
669 if (current_vp
->drawmode
& DRMODE_FG
)
672 bits
= current_vp
->fg_pattern
;
675 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
679 dst_end
= dst
+ height
* LCD_WIDTH
;
683 fb_data
*dst_row
, *row_end
;
688 memset16(dst
, bits
, width
);
692 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
693 width
* sizeof(fb_data
));
696 case OPT_NONE
: /* DRMODE_COMPLEMENT */
698 row_end
= dst_row
+ width
;
700 *dst_row
= ~(*dst_row
);
701 while (++dst_row
< row_end
);
706 while (dst
< dst_end
);
709 /* About Rockbox' internal monochrome bitmap format:
711 * A bitmap contains one bit for every pixel that defines if that pixel is
712 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
714 * The bytes are stored in row-major order, with byte 0 being top left,
715 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
716 * 0..7, the second row defines pixel row 8..15 etc.
718 * This is the mono bitmap format used on all other targets so far; the
719 * pixel packing doesn't really matter on a 8bit+ target. */
721 /* Draw a partial monochrome bitmap */
723 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
724 int src_y
, int stride
, int x
, int y
,
725 int width
, int height
)
727 const unsigned char *src_end
;
728 fb_data
*dst
, *dst_end
;
729 unsigned dmask
= 0x100; /* bit 8 == sentinel */
730 int drmode
= current_vp
->drawmode
;
732 /******************** Image in viewport clipping **********************/
733 /* nothing to draw? */
734 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
735 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
750 if (x
+ width
> current_vp
->width
)
751 width
= current_vp
->width
- x
;
752 if (y
+ height
> current_vp
->height
)
753 height
= current_vp
->height
- y
;
755 /* adjust for viewport */
759 #if defined(HAVE_VIEWPORT_CLIP)
760 /********************* Viewport on screen clipping ********************/
761 /* nothing to draw? */
762 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
763 || (x
+ width
<= 0) || (y
+ height
<= 0))
766 /* clip image in viewport in screen */
779 if (x
+ width
> LCD_WIDTH
)
780 width
= LCD_WIDTH
- x
;
781 if (y
+ height
> LCD_HEIGHT
)
782 height
= LCD_HEIGHT
- y
;
785 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
787 src_end
= src
+ width
;
789 dst_end
= dst
+ height
* LCD_WIDTH
;
791 if (drmode
& DRMODE_INVERSEVID
)
793 dmask
= 0x1ff; /* bit 8 == sentinel */
794 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
799 const unsigned char *src_col
= src
++;
800 unsigned data
= (*src_col
^ dmask
) >> src_y
;
801 fb_data
*dst_col
= dst
++;
805 #define UPDATE_SRC do { \
807 if (data == 0x001) { \
809 data = *src_col ^ dmask; \
815 case DRMODE_COMPLEMENT
:
819 *dst_col
= ~(*dst_col
);
821 dst_col
+= LCD_WIDTH
;
824 while (dst_col
< dst_end
);
830 bo
= lcd_backdrop_offset
;
834 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
836 dst_col
+= LCD_WIDTH
;
839 while (dst_col
< dst_end
);
843 bg
= current_vp
->bg_pattern
;
849 dst_col
+= LCD_WIDTH
;
852 while (dst_col
< dst_end
);
857 fg
= current_vp
->fg_pattern
;
863 dst_col
+= LCD_WIDTH
;
866 while (dst_col
< dst_end
);
870 fg
= current_vp
->fg_pattern
;
873 bo
= lcd_backdrop_offset
;
876 *dst_col
= (data
& 0x01) ? fg
877 : *(fb_data
*)((long)dst_col
+ bo
);
878 dst_col
+= LCD_WIDTH
;
881 while (dst_col
< dst_end
);
885 bg
= current_vp
->bg_pattern
;
888 *dst_col
= (data
& 0x01) ? fg
: bg
;
889 dst_col
+= LCD_WIDTH
;
892 while (dst_col
< dst_end
);
897 while (src
< src_end
);
899 /* Draw a full monochrome bitmap */
900 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
902 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
905 /* Draw a partial native bitmap */
906 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
907 int stride
, int x
, int y
, int width
,
912 /******************** Image in viewport clipping **********************/
913 /* nothing to draw? */
914 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
915 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
931 if (x
+ width
> current_vp
->width
)
932 width
= current_vp
->width
- x
;
933 if (y
+ height
> current_vp
->height
)
934 height
= current_vp
->height
- y
;
936 /* adjust for viewport */
940 #if defined(HAVE_VIEWPORT_CLIP)
941 /********************* Viewport on screen clipping ********************/
942 /* nothing to draw? */
943 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
944 || (x
+ width
<= 0) || (y
+ height
<= 0))
947 /* clip image in viewport in screen */
960 if (x
+ width
> LCD_WIDTH
)
961 width
= LCD_WIDTH
- x
;
962 if (y
+ height
> LCD_HEIGHT
)
963 height
= LCD_HEIGHT
- y
;
966 src
+= stride
* src_y
+ src_x
; /* move starting point */
971 memcpy(dst
, src
, width
* sizeof(fb_data
));
975 while (--height
> 0);
978 /* Draw a full native bitmap */
979 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
981 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
984 /* Draw a partial native bitmap with transparency and foreground colors */
985 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
986 int src_y
, int stride
, int x
,
987 int y
, int width
, int height
)
990 unsigned fg
= current_vp
->fg_pattern
;
992 /******************** Image in viewport clipping **********************/
993 /* nothing to draw? */
994 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
995 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1011 if (x
+ width
> current_vp
->width
)
1012 width
= current_vp
->width
- x
;
1013 if (y
+ height
> current_vp
->height
)
1014 height
= current_vp
->height
- y
;
1016 /* adjust for viewport */
1020 #if defined(HAVE_VIEWPORT_CLIP)
1021 /********************* Viewport on screen clipping ********************/
1022 /* nothing to draw? */
1023 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1024 || (x
+ width
<= 0) || (y
+ height
<= 0))
1027 /* clip image in viewport in screen */
1040 if (x
+ width
> LCD_WIDTH
)
1041 width
= LCD_WIDTH
- x
;
1042 if (y
+ height
> LCD_HEIGHT
)
1043 height
= LCD_HEIGHT
- y
;
1046 src
+= stride
* src_y
+ src_x
; /* move starting point */
1047 dst
= LCDADDR(x
, y
);
1054 "mov %[w], %[width] \n" /* Load width for inner loop */
1056 "ldrh %[px], [%[s]], #2 \n" /* Load src pixel */
1057 "add %[d], %[d], #2 \n" /* Uncoditionally increment dst */
1058 /* done here for better pipelining */
1059 "cmp %[px], %[fgcolor] \n" /* Compare to foreground color */
1060 "streqh %[fgpat], [%[d], #-2] \n" /* Store foregroud if match */
1061 "cmpne %[px], %[transcolor] \n" /* Compare to transparent color */
1062 "strneh %[px], [%[d], #-2] \n" /* Store dst if not transparent */
1063 "subs %[w], %[w], #1 \n" /* Width counter has run down? */
1064 "bgt .nextpixel \n" /* More in this row? */
1065 "add %[s], %[s], %[sstp], lsl #1 \n" /* Skip over to start of next line */
1066 "add %[d], %[d], %[dstp], lsl #1 \n"
1067 "subs %[h], %[h], #1 \n" /* Height counter has run down? */
1068 "bgt .rowstart \n" /* More rows? */
1069 : [w
]"=&r"(w
), [h
]"+&r"(height
), [px
]"=&r"(px
),
1070 [s
]"+&r"(src
), [d
]"+&r"(dst
)
1071 : [width
]"r"(width
),
1072 [sstp
]"r"(stride
- width
),
1073 [dstp
]"r"(LCD_WIDTH
- width
),
1074 [transcolor
]"r"(TRANSPARENT_COLOR
),
1075 [fgcolor
]"r"(REPLACEWITHFG_COLOR
),
1079 #else /* optimized C version */
1082 const fb_data
*src_row
= src
;
1083 fb_data
*dst_row
= dst
;
1084 fb_data
*row_end
= dst_row
+ width
;
1087 unsigned data
= *src_row
++;
1088 if (data
!= TRANSPARENT_COLOR
)
1090 if (data
== REPLACEWITHFG_COLOR
)
1095 while (++dst_row
< row_end
);
1099 while (--height
> 0);
1103 /* Draw a full native bitmap with transparent and foreground colors */
1104 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
1105 int width
, int height
)
1107 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
1110 #include "lcd-bitmap-common.c"