summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-16bit-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-16bit-common.c')
-rw-r--r--firmware/drivers/lcd-16bit-common.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
new file mode 100644
index 0000000000..1e1548e997
--- /dev/null
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -0,0 +1,517 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Dave Chapman
11 *
12 * Rockbox driver for 16-bit colour LCDs
13 *
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.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25/* to be #included by lcd-16bit*.c */
26
27#if !defined(ROW_INC) || !defined(COL_INC)
28#error ROW_INC or COL_INC not defined
29#endif
30
31/* About Rockbox' internal monochrome bitmap format:
32 *
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.
39 *
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. */
42
43/* Draw a partial monochrome bitmap */
44
45void 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)
48{
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;
54
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;
60
61 if (x < 0)
62 {
63 width += x;
64 src_x -= x;
65 x = 0;
66 }
67 if (y < 0)
68 {
69 height += y;
70 src_y -= y;
71 y = 0;
72 }
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;
77
78 /* adjust for viewport */
79 x += current_vp->x;
80 y += current_vp->y;
81
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;
88
89 /* clip image in viewport in screen */
90 if (x < 0)
91 {
92 width += x;
93 src_x -= x;
94 x = 0;
95 }
96 if (y < 0)
97 {
98 height += y;
99 src_y -= y;
100 y = 0;
101 }
102 if (x + width > LCD_WIDTH)
103 width = LCD_WIDTH - x;
104 if (y + height > LCD_HEIGHT)
105 height = LCD_HEIGHT - y;
106#endif
107
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);
112
113
114 if (drmode & DRMODE_INVERSEVID)
115 {
116 dmask = 0x1ff; /* bit 8 == sentinel */
117 drmode &= DRMODE_SOLID; /* mask out inversevid */
118 }
119
120 /* go through each column and update each pixel */
121 do
122 {
123 const unsigned char *src_col = src++;
124 unsigned data = (*src_col ^ dmask) >> src_y;
125 int fg, bg;
126 long bo;
127
128 dst = dst_col;
129 dst_col += COL_INC;
130 row = height;
131
132#define UPDATE_SRC do { \
133 data >>= 1; \
134 if (data == 0x001) { \
135 src_col += stride; \
136 data = *src_col ^ dmask; \
137 } \
138 } while (0)
139
140 switch (drmode)
141 {
142 case DRMODE_COMPLEMENT:
143 do
144 {
145 if (data & 0x01)
146 *dst = ~(*dst);
147
148 dst += ROW_INC;
149 UPDATE_SRC;
150 }
151 while (--row);
152 break;
153
154 case DRMODE_BG:
155 if (lcd_backdrop)
156 {
157 bo = lcd_backdrop_offset;
158 do
159 {
160 if (!(data & 0x01))
161 *dst = *(fb_data *)((long)dst + bo);
162
163 dst += ROW_INC;
164 UPDATE_SRC;
165 }
166 while (--row);
167 }
168 else
169 {
170 bg = current_vp->bg_pattern;
171 do
172 {
173 if (!(data & 0x01))
174 *dst = bg;
175
176 dst += ROW_INC;
177 UPDATE_SRC;
178 }
179 while (--row);
180 }
181 break;
182
183 case DRMODE_FG:
184 fg = current_vp->fg_pattern;
185 do
186 {
187 if (data & 0x01)
188 *dst = fg;
189
190 dst += ROW_INC;
191 UPDATE_SRC;
192 }
193 while (--row);
194 break;
195
196 case DRMODE_SOLID:
197 fg = current_vp->fg_pattern;
198 if (lcd_backdrop)
199 {
200 bo = lcd_backdrop_offset;
201 do
202 {
203 *dst = (data & 0x01) ? fg
204 : *(fb_data *)((long)dst + bo);
205 dst += ROW_INC;
206 UPDATE_SRC;
207 }
208 while (--row);
209 }
210 else
211 {
212 bg = current_vp->bg_pattern;
213 do
214 {
215 *dst = (data & 0x01) ? fg : bg;
216 dst += ROW_INC;
217 UPDATE_SRC;
218 }
219 while (--row);
220 }
221 break;
222 }
223 }
224 while (src < src_end);
225}
226/* Draw a full monochrome bitmap */
227void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
228{
229 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
230}
231
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
258
259/* Blend the given two colors */
260static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a)
261{
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
280}
281
282/* Blend the given color with the value from the alpha_color_lookup table */
283static inline unsigned blend_color(unsigned c, unsigned a)
284{
285 return blend_two_colors(c, current_vp->fg_pattern, a);
286}
287
288void 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)
291{
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;
301
302 /* clipping */
303 if (x < 0)
304 {
305 width += x;
306 src_x -= x;
307 x = 0;
308 }
309 if (y < 0)
310 {
311 height += y;
312 src_y -= y;
313 y = 0;
314 }
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;
319
320 /* adjust for viewport */
321 x += current_vp->x;
322 y += current_vp->y;
323
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;
330
331 /* clip image in viewport in screen */
332 if (x < 0)
333 {
334 width += x;
335 src_x -= x;
336 x = 0;
337 }
338 if (y < 0)
339 {
340 height += y;
341 src_y -= y;
342 y = 0;
343 }
344 if (x + width > LCD_WIDTH)
345 width = LCD_WIDTH - x;
346 if (y + height > LCD_HEIGHT)
347 height = LCD_HEIGHT - y;
348#endif
349
350 if (drmode & DRMODE_INVERSEVID)
351 {
352 dmask = 0xffffffff;
353 drmode &= DRMODE_SOLID; /* mask out inversevid */
354 }
355 if (drmode == DRMODE_BG)
356 {
357 dmask = ~dmask;
358 }
359
360 dst_row = LCDADDR(x, y);
361
362 int col, row = height;
363 unsigned data, pixels;
364 unsigned skip_end = (stride - width);
365 unsigned skip_start = src_y * stride + src_x;
366
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
382
383 /* go through the rows and update each pixel */
384 do
385 {
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 \
394 { \
395 data = letoh32(*src_w++) ^ dmask; \
396 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
397 } \
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)
417 {
418 case DRMODE_COMPLEMENT:
419 do
420 {
421 *dst = blend_two_colors(*dst, ~(*dst),
422 data & ALPHA_COLOR_LOOKUP_SIZE );
423 dst += COL_INC;
424 UPDATE_SRC_ALPHA;
425 }
426 while (--col);
427 break;
428 case DRMODE_BG:
429 if(lcd_backdrop)
430 {
431 uintptr_t bo = lcd_backdrop_offset;
432 do
433 {
434 *dst = blend_two_colors(*dst, *(fb_data *)((uintptr_t)dst + bo),
435 data & ALPHA_COLOR_LOOKUP_SIZE );
436
437 dst += COL_INC;
438 UPDATE_SRC_ALPHA;
439 }
440 while (--col);
441 }
442 else
443 {
444 do
445 {
446 *dst = blend_two_colors(*dst, current_vp->bg_pattern,
447 data & ALPHA_COLOR_LOOKUP_SIZE );
448 dst += COL_INC;
449 UPDATE_SRC_ALPHA;
450 }
451 while (--col);
452 }
453 break;
454 case DRMODE_FG:
455 do
456 {
457 *dst = blend_color(*dst, data & ALPHA_COLOR_LOOKUP_SIZE );
458 dst += COL_INC;
459 UPDATE_SRC_ALPHA;
460 }
461 while (--col);
462 break;
463 case DRMODE_SOLID:
464 if(lcd_backdrop)
465 {
466 uintptr_t bo = lcd_backdrop_offset;
467 do
468 {
469 *dst = blend_color(*(fb_data *)((uintptr_t)dst + bo),
470 data & ALPHA_COLOR_LOOKUP_SIZE );
471 dst += COL_INC;
472 UPDATE_SRC_ALPHA;
473 }
474 while (--col);
475 }
476 else
477 {
478 do
479 {
480 *dst = blend_color(current_vp->bg_pattern,
481 data & ALPHA_COLOR_LOOKUP_SIZE );
482 dst += COL_INC;
483 UPDATE_SRC_ALPHA;
484 }
485 while (--col);
486 }
487 break;
488 }
489#ifdef ALPHA_BITMAP_READ_WORDS
490 if (skip_end < pixels)
491 {
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;
501 }
502#else
503 if (skip_end)
504 {
505 pixels += skip_end;
506 if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
507 {
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;
514 }
515#endif
516 } while (--row);
517}