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 ****************************************************************************/
25 /* to be #included by lcd-16bit*.c */
27 #if !defined(ROW_INC) || !defined(COL_INC)
28 #error ROW_INC or COL_INC not defined
31 /* About Rockbox' internal monochrome bitmap format:
33 * A bitmap contains one bit for every pixel that defines if that pixel is
34 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
36 * The bytes are stored in row-major order, with byte 0 being top left,
37 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
38 * 0..7, the second row defines pixel row 8..15 etc.
40 * This is the mono bitmap format used on all other targets so far; the
41 * pixel packing doesn't really matter on a 8bit+ target. */
43 /* Draw a partial monochrome bitmap */
45 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
46 int src_y
, int stride
, int x
, int y
,
47 int width
, int height
)
49 const unsigned char *src_end
;
50 fb_data
*dst
, *dst_col
;
51 unsigned dmask
= 0x100; /* bit 8 == sentinel */
52 int drmode
= current_vp
->drawmode
;
55 /******************** Image in viewport clipping **********************/
56 /* nothing to draw? */
57 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
58 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
73 if (x
+ width
> current_vp
->width
)
74 width
= current_vp
->width
- x
;
75 if (y
+ height
> current_vp
->height
)
76 height
= current_vp
->height
- y
;
78 /* adjust for viewport */
82 #if defined(HAVE_VIEWPORT_CLIP)
83 /********************* Viewport on screen clipping ********************/
84 /* nothing to draw? */
85 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
86 || (x
+ width
<= 0) || (y
+ height
<= 0))
89 /* clip image in viewport in screen */
102 if (x
+ width
> LCD_WIDTH
)
103 width
= LCD_WIDTH
- x
;
104 if (y
+ height
> LCD_HEIGHT
)
105 height
= LCD_HEIGHT
- y
;
108 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
110 src_end
= src
+ width
;
111 dst_col
= LCDADDR(x
, y
);
114 if (drmode
& DRMODE_INVERSEVID
)
116 dmask
= 0x1ff; /* bit 8 == sentinel */
117 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
120 /* go through each column and update each pixel */
123 const unsigned char *src_col
= src
++;
124 unsigned data
= (*src_col
^ dmask
) >> src_y
;
132 #define UPDATE_SRC do { \
134 if (data == 0x001) { \
136 data = *src_col ^ dmask; \
142 case DRMODE_COMPLEMENT
:
157 bo
= lcd_backdrop_offset
;
161 *dst
= *(fb_data
*)((long)dst
+ bo
);
170 bg
= current_vp
->bg_pattern
;
184 fg
= current_vp
->fg_pattern
;
197 fg
= current_vp
->fg_pattern
;
200 bo
= lcd_backdrop_offset
;
203 *dst
= (data
& 0x01) ? fg
204 : *(fb_data
*)((long)dst
+ bo
);
212 bg
= current_vp
->bg_pattern
;
215 *dst
= (data
& 0x01) ? fg
: bg
;
224 while (src
< src_end
);
226 /* Draw a full monochrome bitmap */
227 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
229 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
232 /* draw alpha bitmap for anti-alias font */
233 #define ALPHA_COLOR_FONT_DEPTH 2
234 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
235 #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
236 #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
237 #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
239 #define BLEND_INIT do {} while (0)
240 #define BLEND_START(acc, color, alpha) \
241 asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
242 #define BLEND_CONT(acc, color, alpha) \
243 asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
244 #define BLEND_OUT(acc) do {} while (0)
245 #elif defined(CPU_COLDFIRE)
246 #define ALPHA_BITMAP_READ_WORDS
247 #define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED)
248 #define BLEND_START(acc, color, alpha) \
249 asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
250 #define BLEND_CONT BLEND_START
251 #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
253 #define BLEND_INIT do {} while (0)
254 #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
255 #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
256 #define BLEND_OUT(acc) do {} while (0)
259 /* Blend the given two colors */
260 static inline unsigned blend_two_colors(unsigned c1
, unsigned c2
, unsigned a
)
262 a
+= a
>> (ALPHA_COLOR_LOOKUP_SHIFT
- 1);
263 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
267 unsigned c1l
= (c1
| (c1
<< 16)) & 0x07e0f81f;
268 unsigned c2l
= (c2
| (c2
<< 16)) & 0x07e0f81f;
270 BLEND_START(p
, c1l
, a
);
271 BLEND_CONT(p
, c2l
, ALPHA_COLOR_LOOKUP_SIZE
+ 1 - a
);
273 p
= (p
>> ALPHA_COLOR_LOOKUP_SHIFT
) & 0x07e0f81f;
275 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
282 /* Blend the given color with the value from the alpha_color_lookup table */
283 static inline unsigned blend_color(unsigned c
, unsigned a
)
285 return blend_two_colors(c
, current_vp
->fg_pattern
, a
);
288 void ICODE_ATTR
lcd_alpha_bitmap_part(const unsigned char *src
, int src_x
,
289 int src_y
, int stride
, int x
, int y
,
290 int width
, int height
)
292 fb_data
*dst
, *dst_row
;
293 unsigned dmask
= 0x00000000;
294 int drmode
= current_vp
->drawmode
;
295 /* nothing to draw? */
296 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
297 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
299 /* initialize blending */
315 if (x
+ width
> current_vp
->width
)
316 width
= current_vp
->width
- x
;
317 if (y
+ height
> current_vp
->height
)
318 height
= current_vp
->height
- y
;
320 /* adjust for viewport */
324 #if defined(HAVE_VIEWPORT_CLIP)
325 /********************* Viewport on screen clipping ********************/
326 /* nothing to draw? */
327 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
328 || (x
+ width
<= 0) || (y
+ height
<= 0))
331 /* clip image in viewport in screen */
344 if (x
+ width
> LCD_WIDTH
)
345 width
= LCD_WIDTH
- x
;
346 if (y
+ height
> LCD_HEIGHT
)
347 height
= LCD_HEIGHT
- y
;
350 if (drmode
& DRMODE_INVERSEVID
)
353 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
355 if (drmode
== DRMODE_BG
)
360 dst_row
= LCDADDR(x
, y
);
362 int col
, row
= height
;
363 unsigned data
, pixels
;
364 unsigned skip_end
= (stride
- width
);
365 unsigned skip_start
= src_y
* stride
+ src_x
;
367 #ifdef ALPHA_BITMAP_READ_WORDS
368 uint32_t *src_w
= (uint32_t *)((uintptr_t)src
& ~3);
369 skip_start
+= ALPHA_COLOR_PIXEL_PER_BYTE
* ((uintptr_t)src
& 3);
370 src_w
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_WORD
;
371 data
= letoh32(*src_w
++) ^ dmask
;
372 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_WORD
;
374 src
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
376 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_BYTE
;
378 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
379 #ifdef ALPHA_BITMAP_READ_WORDS
383 /* go through the rows and update each pixel */
389 #ifdef ALPHA_BITMAP_READ_WORDS
390 #define UPDATE_SRC_ALPHA do { \
392 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
395 data = letoh32(*src_w++) ^ dmask; \
396 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
399 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
400 #define UPDATE_SRC_ALPHA do { \
402 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
404 data = *(++src) ^ dmask; \
407 #define UPDATE_SRC_ALPHA do { \
408 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
409 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
411 data = *(++src) ^ dmask; \
414 /* we don't want to have this in our inner
415 * loop and the codesize increase is minimal */
418 case DRMODE_COMPLEMENT
:
421 *dst
= blend_two_colors(*dst
, ~(*dst
),
422 data
& ALPHA_COLOR_LOOKUP_SIZE
);
431 uintptr_t bo
= lcd_backdrop_offset
;
434 *dst
= blend_two_colors(*dst
, *(fb_data
*)((uintptr_t)dst
+ bo
),
435 data
& ALPHA_COLOR_LOOKUP_SIZE
);
446 *dst
= blend_two_colors(*dst
, current_vp
->bg_pattern
,
447 data
& ALPHA_COLOR_LOOKUP_SIZE
);
457 *dst
= blend_color(*dst
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
466 uintptr_t bo
= lcd_backdrop_offset
;
469 *dst
= blend_color(*(fb_data
*)((uintptr_t)dst
+ bo
),
470 data
& ALPHA_COLOR_LOOKUP_SIZE
);
480 *dst
= blend_color(current_vp
->bg_pattern
,
481 data
& ALPHA_COLOR_LOOKUP_SIZE
);
489 #ifdef ALPHA_BITMAP_READ_WORDS
490 if (skip_end
< pixels
)
493 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
495 pixels
= skip_end
- pixels
;
496 src_w
+= pixels
/ ALPHA_COLOR_PIXEL_PER_WORD
;
497 pixels
%= ALPHA_COLOR_PIXEL_PER_WORD
;
498 data
= letoh32(*src_w
++) ^ dmask
;
499 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
506 if (pixels
>= ALPHA_COLOR_PIXEL_PER_BYTE
)
508 src
+= pixels
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
509 pixels
%= ALPHA_COLOR_PIXEL_PER_BYTE
;
511 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
513 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;