Android: no need to keep RockboxPCM_class around
[maemo-rb.git] / firmware / drivers / lcd-16bit-common.c
blob1e1548e997653ada7814fae1c1752aac49ffa977
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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
29 #endif
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
35 * at top.
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;
53 int row;
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))
59 return;
61 if (x < 0)
63 width += x;
64 src_x -= x;
65 x = 0;
67 if (y < 0)
69 height += y;
70 src_y -= y;
71 y = 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 */
79 x += current_vp->x;
80 y += current_vp->y;
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))
87 return;
89 /* clip image in viewport in screen */
90 if (x < 0)
92 width += x;
93 src_x -= x;
94 x = 0;
96 if (y < 0)
98 height += y;
99 src_y -= y;
100 y = 0;
102 if (x + width > LCD_WIDTH)
103 width = LCD_WIDTH - x;
104 if (y + height > LCD_HEIGHT)
105 height = LCD_HEIGHT - y;
106 #endif
108 src += stride * (src_y >> 3) + src_x; /* move starting point */
109 src_y &= 7;
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;
125 int fg, bg;
126 long bo;
128 dst = dst_col;
129 dst_col += COL_INC;
130 row = height;
132 #define UPDATE_SRC do { \
133 data >>= 1; \
134 if (data == 0x001) { \
135 src_col += stride; \
136 data = *src_col ^ dmask; \
138 } while (0)
140 switch (drmode)
142 case DRMODE_COMPLEMENT:
145 if (data & 0x01)
146 *dst = ~(*dst);
148 dst += ROW_INC;
149 UPDATE_SRC;
151 while (--row);
152 break;
154 case DRMODE_BG:
155 if (lcd_backdrop)
157 bo = lcd_backdrop_offset;
160 if (!(data & 0x01))
161 *dst = *(fb_data *)((long)dst + bo);
163 dst += ROW_INC;
164 UPDATE_SRC;
166 while (--row);
168 else
170 bg = current_vp->bg_pattern;
173 if (!(data & 0x01))
174 *dst = bg;
176 dst += ROW_INC;
177 UPDATE_SRC;
179 while (--row);
181 break;
183 case DRMODE_FG:
184 fg = current_vp->fg_pattern;
187 if (data & 0x01)
188 *dst = fg;
190 dst += ROW_INC;
191 UPDATE_SRC;
193 while (--row);
194 break;
196 case DRMODE_SOLID:
197 fg = current_vp->fg_pattern;
198 if (lcd_backdrop)
200 bo = lcd_backdrop_offset;
203 *dst = (data & 0x01) ? fg
204 : *(fb_data *)((long)dst + bo);
205 dst += ROW_INC;
206 UPDATE_SRC;
208 while (--row);
210 else
212 bg = current_vp->bg_pattern;
215 *dst = (data & 0x01) ? fg : bg;
216 dst += ROW_INC;
217 UPDATE_SRC;
219 while (--row);
221 break;
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)
238 #ifdef CPU_ARM
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))
252 #else
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)
257 #endif
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)
264 c1 = swap16(c1);
265 c2 = swap16(c2);
266 #endif
267 unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f;
268 unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f;
269 unsigned p;
270 BLEND_START(p, c1l, a);
271 BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a);
272 BLEND_OUT(p);
273 p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f;
274 p |= (p >> 16);
275 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
276 return swap16(p);
277 #else
278 return p;
279 #endif
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))
298 return;
299 /* initialize blending */
300 BLEND_INIT;
302 /* clipping */
303 if (x < 0)
305 width += x;
306 src_x -= x;
307 x = 0;
309 if (y < 0)
311 height += y;
312 src_y -= y;
313 y = 0;
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 */
321 x += current_vp->x;
322 y += current_vp->y;
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))
329 return;
331 /* clip image in viewport in screen */
332 if (x < 0)
334 width += x;
335 src_x -= x;
336 x = 0;
338 if (y < 0)
340 height += y;
341 src_y -= y;
342 y = 0;
344 if (x + width > LCD_WIDTH)
345 width = LCD_WIDTH - x;
346 if (y + height > LCD_HEIGHT)
347 height = LCD_HEIGHT - y;
348 #endif
350 if (drmode & DRMODE_INVERSEVID)
352 dmask = 0xffffffff;
353 drmode &= DRMODE_SOLID; /* mask out inversevid */
355 if (drmode == DRMODE_BG)
357 dmask = ~dmask;
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;
373 #else
374 src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
375 data = *src ^ dmask;
376 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE;
377 #endif
378 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
379 #ifdef ALPHA_BITMAP_READ_WORDS
380 pixels = 8 - pixels;
381 #endif
383 /* go through the rows and update each pixel */
386 col = width;
387 dst = dst_row;
388 dst_row += ROW_INC;
389 #ifdef ALPHA_BITMAP_READ_WORDS
390 #define UPDATE_SRC_ALPHA do { \
391 if (--pixels) \
392 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
393 else \
395 data = letoh32(*src_w++) ^ dmask; \
396 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
398 } while (0)
399 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
400 #define UPDATE_SRC_ALPHA do { \
401 if (pixels ^= 1) \
402 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
403 else \
404 data = *(++src) ^ dmask; \
405 } while (0)
406 #else
407 #define UPDATE_SRC_ALPHA do { \
408 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
409 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
410 else \
411 data = *(++src) ^ dmask; \
412 } while (0)
413 #endif
414 /* we don't want to have this in our inner
415 * loop and the codesize increase is minimal */
416 switch (drmode)
418 case DRMODE_COMPLEMENT:
421 *dst = blend_two_colors(*dst, ~(*dst),
422 data & ALPHA_COLOR_LOOKUP_SIZE );
423 dst += COL_INC;
424 UPDATE_SRC_ALPHA;
426 while (--col);
427 break;
428 case DRMODE_BG:
429 if(lcd_backdrop)
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 );
437 dst += COL_INC;
438 UPDATE_SRC_ALPHA;
440 while (--col);
442 else
446 *dst = blend_two_colors(*dst, current_vp->bg_pattern,
447 data & ALPHA_COLOR_LOOKUP_SIZE );
448 dst += COL_INC;
449 UPDATE_SRC_ALPHA;
451 while (--col);
453 break;
454 case DRMODE_FG:
457 *dst = blend_color(*dst, data & ALPHA_COLOR_LOOKUP_SIZE );
458 dst += COL_INC;
459 UPDATE_SRC_ALPHA;
461 while (--col);
462 break;
463 case DRMODE_SOLID:
464 if(lcd_backdrop)
466 uintptr_t bo = lcd_backdrop_offset;
469 *dst = blend_color(*(fb_data *)((uintptr_t)dst + bo),
470 data & ALPHA_COLOR_LOOKUP_SIZE );
471 dst += COL_INC;
472 UPDATE_SRC_ALPHA;
474 while (--col);
476 else
480 *dst = blend_color(current_vp->bg_pattern,
481 data & ALPHA_COLOR_LOOKUP_SIZE );
482 dst += COL_INC;
483 UPDATE_SRC_ALPHA;
485 while (--col);
487 break;
489 #ifdef ALPHA_BITMAP_READ_WORDS
490 if (skip_end < pixels)
492 pixels -= skip_end;
493 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
494 } else {
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;
500 pixels = 8 - pixels;
502 #else
503 if (skip_end)
505 pixels += skip_end;
506 if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
508 src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
509 pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
510 data = *src ^ dmask;
511 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
512 } else
513 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
515 #endif
516 } while (--row);