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
;
90 void lcd_update_viewport(void)
92 lcd_update_rect(current_vp
->x
, current_vp
->y
,
93 current_vp
->width
, current_vp
->height
);
96 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
98 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
101 /*** parameter handling ***/
103 void lcd_set_drawmode(int mode
)
105 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
108 int lcd_get_drawmode(void)
110 return current_vp
->drawmode
;
113 void lcd_set_foreground(unsigned color
)
115 current_vp
->fg_pattern
= color
;
118 unsigned lcd_get_foreground(void)
120 return current_vp
->fg_pattern
;
123 void lcd_set_background(unsigned color
)
125 current_vp
->bg_pattern
= color
;
128 unsigned lcd_get_background(void)
130 return current_vp
->bg_pattern
;
133 void lcd_set_selector_start(unsigned color
)
135 current_vp
->lss_pattern
= color
;
138 void lcd_set_selector_end(unsigned color
)
140 current_vp
->lse_pattern
= color
;
143 void lcd_set_selector_text(unsigned color
)
145 current_vp
->lst_pattern
= color
;
148 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
150 lcd_set_drawmode(mode
);
151 current_vp
->fg_pattern
= fg_color
;
152 current_vp
->bg_pattern
= bg_color
;
155 int lcd_getwidth(void)
157 return current_vp
->width
;
160 int lcd_getheight(void)
162 return current_vp
->height
;
165 void lcd_setfont(int newfont
)
167 current_vp
->font
= newfont
;
170 int lcd_getfont(void)
172 return current_vp
->font
;
175 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
177 return font_getstringsize(str
, w
, h
, current_vp
->font
);
180 /*** low-level drawing functions ***/
182 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
184 static void ICODE_ATTR
setpixel(fb_data
*address
)
186 *address
= current_vp
->fg_pattern
;
189 static void ICODE_ATTR
clearpixel(fb_data
*address
)
191 *address
= current_vp
->bg_pattern
;
194 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
196 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
199 static void ICODE_ATTR
flippixel(fb_data
*address
)
201 *address
= ~(*address
);
204 static void ICODE_ATTR
nopixel(fb_data
*address
)
209 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
210 flippixel
, nopixel
, setpixel
, setpixel
,
211 nopixel
, clearpixel
, nopixel
, clearpixel
214 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
215 flippixel
, nopixel
, setpixel
, setpixel
,
216 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
219 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
221 void lcd_set_backdrop(fb_data
* backdrop
)
223 lcd_backdrop
= backdrop
;
226 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
227 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
231 lcd_backdrop_offset
= 0;
232 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
236 fb_data
* lcd_get_backdrop(void)
241 /*** drawing functions ***/
243 /* Clear the current viewport */
244 void lcd_clear_viewport(void)
246 fb_data
*dst
, *dst_end
;
248 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
249 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
251 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
255 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
258 while (dst
< dst_end
);
266 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
269 while (dst
< dst_end
);
275 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
276 current_vp
->width
* sizeof(fb_data
));
279 while (dst
< dst_end
);
283 if (current_vp
== &default_vp
)
285 lcd_scroll_info
.lines
= 0;
289 lcd_scroll_stop(current_vp
);
293 /* Clear the whole display */
294 void lcd_clear_display(void)
296 struct viewport
* old_vp
= current_vp
;
298 current_vp
= &default_vp
;
300 lcd_clear_viewport();
305 /* Set a single pixel */
306 void lcd_drawpixel(int x
, int y
)
308 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
309 ((unsigned)y
< (unsigned)current_vp
->height
))
310 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
314 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
322 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
324 deltay
= abs(y2
- y1
);
327 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
328 lcd_hline(x1
, x2
, y1
);
331 deltax
= abs(x2
- x1
);
334 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
335 lcd_vline(x1
, y1
, y2
);
341 if (deltax
>= deltay
)
344 d
= 2 * deltay
- deltax
;
346 dinc2
= (deltay
- deltax
) * 2;
353 d
= 2 * deltax
- deltay
;
355 dinc2
= (deltax
- deltay
) * 2;
359 numpixels
++; /* include endpoints */
376 for (i
= 0; i
< numpixels
; i
++)
378 if (((unsigned)x
< (unsigned)current_vp
->width
) && ((unsigned)y
< (unsigned)current_vp
->height
))
379 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
396 /* Draw a horizontal line (optimised) */
397 void lcd_hline(int x1
, int x2
, int y
)
401 enum fill_opt fillopt
= OPT_NONE
;
402 fb_data
*dst
, *dst_end
;
412 /* nothing to draw? */
413 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
414 (x1
>= current_vp
->width
) ||
418 /* drawmode and optimisation */
419 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
421 if (current_vp
->drawmode
& DRMODE_BG
)
426 bits
= current_vp
->bg_pattern
;
434 if (current_vp
->drawmode
& DRMODE_FG
)
437 bits
= current_vp
->fg_pattern
;
440 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
446 if (x2
>= current_vp
->width
)
447 x2
= current_vp
->width
-1;
451 /* Adjust x1 and y to viewport */
455 dst
= LCDADDR(x1
, y
);
460 memset16(dst
, bits
, width
);
464 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
465 width
* sizeof(fb_data
));
468 case OPT_NONE
: /* DRMODE_COMPLEMENT */
469 dst_end
= dst
+ width
;
472 while (++dst
< dst_end
);
477 /* Draw a vertical line (optimised) */
478 void lcd_vline(int x
, int y1
, int y2
)
481 fb_data
*dst
, *dst_end
;
482 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
492 /* nothing to draw? */
493 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
494 (y1
>= current_vp
->height
) ||
501 if (y2
>= current_vp
->height
)
502 y2
= current_vp
->height
-1;
504 dst
= LCDADDR(x
+ current_vp
->x
, y1
+ current_vp
->y
);
505 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
512 while (dst
<= dst_end
);
515 /* Draw a rectangular box */
516 void lcd_drawrect(int x
, int y
, int width
, int height
)
518 if ((width
<= 0) || (height
<= 0))
521 int x2
= x
+ width
- 1;
522 int y2
= y
+ height
- 1;
525 lcd_vline(x2
, y
, y2
);
527 lcd_hline(x
, x2
, y2
);
530 /* Fill a rectangular area */
531 void lcd_fillrect(int x
, int y
, int width
, int height
)
534 enum fill_opt fillopt
= OPT_NONE
;
535 fb_data
*dst
, *dst_end
;
537 /* nothing to draw? */
538 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
539 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
542 /* drawmode and optimisation */
543 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
545 if (current_vp
->drawmode
& DRMODE_BG
)
550 bits
= current_vp
->bg_pattern
;
558 if (current_vp
->drawmode
& DRMODE_FG
)
561 bits
= current_vp
->fg_pattern
;
564 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
578 if (x
+ width
> current_vp
->width
)
579 width
= current_vp
->width
- x
;
580 if (y
+ height
> current_vp
->height
)
581 height
= current_vp
->height
- y
;
583 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
584 dst_end
= dst
+ height
* LCD_WIDTH
;
588 fb_data
*dst_row
, *row_end
;
593 memset16(dst
, bits
, width
);
597 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
598 width
* sizeof(fb_data
));
601 case OPT_NONE
: /* DRMODE_COMPLEMENT */
603 row_end
= dst_row
+ width
;
605 *dst_row
= ~(*dst_row
);
606 while (++dst_row
< row_end
);
611 while (dst
< dst_end
);
614 /* About Rockbox' internal monochrome bitmap format:
616 * A bitmap contains one bit for every pixel that defines if that pixel is
617 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
619 * The bytes are stored in row-major order, with byte 0 being top left,
620 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
621 * 0..7, the second row defines pixel row 8..15 etc.
623 * This is the mono bitmap format used on all other targets so far; the
624 * pixel packing doesn't really matter on a 8bit+ target. */
626 /* Draw a partial monochrome bitmap */
628 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
629 int src_y
, int stride
, int x
, int y
,
630 int width
, int height
)
632 const unsigned char *src_end
;
633 fb_data
*dst
, *dst_end
;
634 unsigned dmask
= 0x100; /* bit 8 == sentinel */
635 int drmode
= current_vp
->drawmode
;
637 /* nothing to draw? */
638 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
639 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
655 if (x
+ width
> current_vp
->width
)
656 width
= current_vp
->width
- x
;
657 if (y
+ height
> current_vp
->height
)
658 height
= current_vp
->height
- y
;
660 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
662 src_end
= src
+ width
;
663 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
664 dst_end
= dst
+ height
* LCD_WIDTH
;
666 if (drmode
& DRMODE_INVERSEVID
)
668 dmask
= 0x1ff; /* bit 8 == sentinel */
669 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
674 const unsigned char *src_col
= src
++;
675 unsigned data
= (*src_col
^ dmask
) >> src_y
;
676 fb_data
*dst_col
= dst
++;
680 #define UPDATE_SRC do { \
682 if (data == 0x001) { \
684 data = *src_col ^ dmask; \
690 case DRMODE_COMPLEMENT
:
694 *dst_col
= ~(*dst_col
);
696 dst_col
+= LCD_WIDTH
;
699 while (dst_col
< dst_end
);
705 bo
= lcd_backdrop_offset
;
709 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
711 dst_col
+= LCD_WIDTH
;
714 while (dst_col
< dst_end
);
718 bg
= current_vp
->bg_pattern
;
724 dst_col
+= LCD_WIDTH
;
727 while (dst_col
< dst_end
);
732 fg
= current_vp
->fg_pattern
;
738 dst_col
+= LCD_WIDTH
;
741 while (dst_col
< dst_end
);
745 fg
= current_vp
->fg_pattern
;
748 bo
= lcd_backdrop_offset
;
751 *dst_col
= (data
& 0x01) ? fg
752 : *(fb_data
*)((long)dst_col
+ bo
);
753 dst_col
+= LCD_WIDTH
;
756 while (dst_col
< dst_end
);
760 bg
= current_vp
->bg_pattern
;
763 *dst_col
= (data
& 0x01) ? fg
: bg
;
764 dst_col
+= LCD_WIDTH
;
767 while (dst_col
< dst_end
);
772 while (src
< src_end
);
774 /* Draw a full monochrome bitmap */
775 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
777 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
780 /* Draw a partial native bitmap */
781 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
782 int stride
, int x
, int y
, int width
,
787 if (x
+ width
> current_vp
->width
)
788 width
= current_vp
->width
- x
; /* Clip right */
790 if (x
< 0) /* Clip left */
798 return; /* nothing left to do */
800 if (y
+ height
> current_vp
->height
)
801 height
= current_vp
->height
- y
; /* Clip bottom */
803 if (y
< 0) /* Clip top */
811 return; /* nothing left to do */
813 src
+= stride
* src_y
+ src_x
; /* move starting point */
814 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
818 memcpy(dst
, src
, width
* sizeof(fb_data
));
822 while (--height
> 0);
825 /* Draw a full native bitmap */
826 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
828 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
831 /* Draw a partial native bitmap with transparency and foreground colors */
832 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
833 int src_y
, int stride
, int x
,
834 int y
, int width
, int height
)
837 unsigned fg
= current_vp
->fg_pattern
;
839 if (x
+ width
> current_vp
->width
)
840 width
= current_vp
->width
- x
; /* Clip right */
842 if (x
< 0) /* Clip left */
850 return; /* nothing left to do */
852 if (y
+ height
> current_vp
->height
)
853 height
= current_vp
->height
- y
; /* Clip bottom */
855 if (y
< 0) /* Clip top */
863 return; /* nothing left to do */
865 src
+= stride
* src_y
+ src_x
; /* move starting point */
866 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
873 "mov %[w], %[width] \n" /* Load width for inner loop */
875 "ldrh %[px], [%[s]], #2 \n" /* Load src pixel */
876 "add %[d], %[d], #2 \n" /* Uncoditionally increment dst */
877 /* done here for better pipelining */
878 "cmp %[px], %[fgcolor] \n" /* Compare to foreground color */
879 "streqh %[fgpat], [%[d], #-2] \n" /* Store foregroud if match */
880 "cmpne %[px], %[transcolor] \n" /* Compare to transparent color */
881 "strneh %[px], [%[d], #-2] \n" /* Store dst if not transparent */
882 "subs %[w], %[w], #1 \n" /* Width counter has run down? */
883 "bgt .nextpixel \n" /* More in this row? */
884 "add %[s], %[s], %[sstp], lsl #1 \n" /* Skip over to start of next line */
885 "add %[d], %[d], %[dstp], lsl #1 \n"
886 "subs %[h], %[h], #1 \n" /* Height counter has run down? */
887 "bgt .rowstart \n" /* More rows? */
888 : [w
]"=&r"(w
), [h
]"+&r"(height
), [px
]"=&r"(px
),
889 [s
]"+&r"(src
), [d
]"+&r"(dst
)
891 [sstp
]"r"(stride
- width
),
892 [dstp
]"r"(LCD_WIDTH
- width
),
893 [transcolor
]"r"(TRANSPARENT_COLOR
),
894 [fgcolor
]"r"(REPLACEWITHFG_COLOR
),
898 #else /* optimized C version */
901 const fb_data
*src_row
= src
;
902 fb_data
*dst_row
= dst
;
903 fb_data
*row_end
= dst_row
+ width
;
906 unsigned data
= *src_row
++;
907 if (data
!= TRANSPARENT_COLOR
)
909 if (data
== REPLACEWITHFG_COLOR
)
915 while (++dst_row
< row_end
);
919 while (--height
> 0);
923 /* Draw a full native bitmap with transparent and foreground colors */
924 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
925 int width
, int height
)
927 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
930 #include "lcd-bitmap-common.c"