summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-24bit.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2014-06-18 07:15:00 +0200
committerThomas Martitz <kugel@rockbox.org>2014-06-21 00:15:53 +0200
commita1842c04f9cb73210d4cacde61a9e4b115050765 (patch)
treea37af61ef9285b763a42cd33797e2f3d634fbf9f /firmware/drivers/lcd-24bit.c
parent0250be1d6799db7b5ddc99cb33f31bf9cff01ed2 (diff)
downloadrockbox-a1842c04f9cb73210d4cacde61a9e4b115050765.tar.gz
rockbox-a1842c04f9cb73210d4cacde61a9e4b115050765.zip
lcd-24bit: Introduce a 24-bit mid-level LCD driver
With LCD driver all calculation will be performed on RGB888 and the hardware/OS can display from our 24bit framebuffer. It is not yet as performance optimized as the existing drivers but should be good enough.The vast number of small changes is due to the fact that fb_data can be a struct type now, while most of the code expected a scalar type. lcd-as-memframe ASM code does not work with 24bit currently so the with 24bit it enforces the generic C code. All plugins are ported over. Except for rockpaint. It uses so much memory that it wouldnt fit into the 512k plugin buffer anymore (patches welcome). Change-Id: Ibb1964545028ce0d8ff9833ccc3ab66be3ee0754
Diffstat (limited to 'firmware/drivers/lcd-24bit.c')
-rw-r--r--firmware/drivers/lcd-24bit.c1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-24bit.c b/firmware/drivers/lcd-24bit.c
new file mode 100644
index 0000000000..f87d63aaa3
--- /dev/null
+++ b/firmware/drivers/lcd-24bit.c
@@ -0,0 +1,1129 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Dave Chapman
11 * Copyright (C) 2009 by Karl Kurbjun
12 *
13 * Rockbox driver for 16-bit colour LCDs
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include <stdio.h>
26#include "config.h"
27
28#include "cpu.h"
29#include "lcd.h"
30#include "kernel.h"
31#include "thread.h"
32#include <stdlib.h>
33#include "string-extra.h" /* mem*() */
34#include "file.h"
35#include "debug.h"
36#include "system.h"
37#include "font.h"
38#include "rbunicode.h"
39#include "bidi.h"
40#include "scroll_engine.h"
41
42#define ROW_INC LCD_WIDTH
43#define COL_INC 1
44
45extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[];
46extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[];
47
48static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
49 const unsigned char *src, int src_x,
50 int src_y, int x, int y,
51 int width, int height,
52 int stride_image, int stride_src);
53
54#include "lcd-color-common.c"
55#include "lcd-bitmap-common.c"
56
57
58/* Clear the current viewport */
59void lcd_clear_viewport(void)
60{
61 fb_data *dst, *dst_end;
62 int x, y, width, height;
63 int len, step;
64
65 x = current_vp->x;
66 y = current_vp->y;
67 width = current_vp->width;
68 height = current_vp->height;
69
70#if defined(HAVE_VIEWPORT_CLIP)
71 /********************* Viewport on screen clipping ********************/
72 /* nothing to draw? */
73 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
74 || (x + width <= 0) || (y + height <= 0))
75 return;
76
77 /* clip image in viewport in screen */
78 if (x < 0)
79 {
80 width += x;
81 x = 0;
82 }
83 if (y < 0)
84 {
85 height += y;
86 y = 0;
87 }
88 if (x + width > LCD_WIDTH)
89 width = LCD_WIDTH - x;
90 if (y + height > LCD_HEIGHT)
91 height = LCD_HEIGHT - y;
92#endif
93
94 len = STRIDE_MAIN(width, height);
95 step = STRIDE_MAIN(ROW_INC, COL_INC);
96
97 dst = FBADDR(x, y);
98 dst_end = FBADDR(x + width - 1 , y + height - 1);
99
100 if (current_vp->drawmode & DRMODE_INVERSEVID)
101 {
102 fb_data px = FB_SCALARPACK(current_vp->fg_pattern);
103 do
104 {
105 fb_data *end = dst + len;
106 do {
107 *dst++ = px;
108 } while (dst < end);
109 dst += step - len;
110 }
111 while (dst <= dst_end);
112 }
113 else
114 {
115 if (!lcd_backdrop)
116 {
117 fb_data px = FB_SCALARPACK(current_vp->bg_pattern);
118 do
119 {
120 fb_data *end = dst + len;
121 do {
122 *dst++ = px;
123 } while (dst < end);
124 dst += step - len;
125 }
126 while (dst <= dst_end);
127 }
128 else
129 {
130 do
131 {
132 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
133 len * sizeof(fb_data));
134 dst += step;
135 }
136 while (dst <= dst_end);
137 }
138 }
139
140 if (current_vp == &default_vp)
141 lcd_scroll_stop();
142 else
143 lcd_scroll_stop_viewport(current_vp);
144}
145
146/*** low-level drawing functions ***/
147
148static void ICODE_ATTR setpixel(fb_data *address)
149{
150 *address = FB_SCALARPACK(current_vp->fg_pattern);
151}
152
153static void ICODE_ATTR clearpixel(fb_data *address)
154{
155 *address = FB_SCALARPACK(current_vp->bg_pattern);
156}
157
158static void ICODE_ATTR clearimgpixel(fb_data *address)
159{
160 *address = *(fb_data *)((long)address + lcd_backdrop_offset);
161}
162
163static void ICODE_ATTR flippixel(fb_data *address)
164{
165 unsigned px = FB_UNPACK_SCALAR_LCD(*address);
166 *address = FB_SCALARPACK(~px);
167}
168
169static void ICODE_ATTR nopixel(fb_data *address)
170{
171 (void)address;
172}
173
174lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[8] = {
175 flippixel, nopixel, setpixel, setpixel,
176 nopixel, clearpixel, nopixel, clearpixel
177};
178
179lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = {
180 flippixel, nopixel, setpixel, setpixel,
181 nopixel, clearimgpixel, nopixel, clearimgpixel
182};
183
184lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
185
186/* Fill a rectangular area */
187void lcd_fillrect(int x, int y, int width, int height)
188{
189 enum fill_opt fillopt = OPT_NONE;
190 fb_data *dst, *dst_end;
191 int len, step;
192 fb_data bits = { 0 };
193
194 /******************** In viewport clipping **********************/
195 /* nothing to draw? */
196 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
197 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
198 return;
199
200 if (x < 0)
201 {
202 width += x;
203 x = 0;
204 }
205 if (y < 0)
206 {
207 height += y;
208 y = 0;
209 }
210 if (x + width > current_vp->width)
211 width = current_vp->width - x;
212 if (y + height > current_vp->height)
213 height = current_vp->height - y;
214
215 /* adjust for viewport */
216 x += current_vp->x;
217 y += current_vp->y;
218
219#if defined(HAVE_VIEWPORT_CLIP)
220 /********************* Viewport on screen clipping ********************/
221 /* nothing to draw? */
222 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
223 || (x + width <= 0) || (y + height <= 0))
224 return;
225
226 /* clip image in viewport in screen */
227 if (x < 0)
228 {
229 width += x;
230 x = 0;
231 }
232 if (y < 0)
233 {
234 height += y;
235 y = 0;
236 }
237 if (x + width > LCD_WIDTH)
238 width = LCD_WIDTH - x;
239 if (y + height > LCD_HEIGHT)
240 height = LCD_HEIGHT - y;
241#endif
242
243 /* drawmode and optimisation */
244 if (current_vp->drawmode & DRMODE_INVERSEVID)
245 {
246 if (current_vp->drawmode & DRMODE_BG)
247 {
248 if (!lcd_backdrop)
249 {
250 fillopt = OPT_SET;
251 bits = FB_SCALARPACK(current_vp->bg_pattern);
252 }
253 else
254 fillopt = OPT_COPY;
255 }
256 }
257 else
258 {
259 if (current_vp->drawmode & DRMODE_FG)
260 {
261 fillopt = OPT_SET;
262 bits = FB_SCALARPACK(current_vp->fg_pattern);
263 }
264 }
265 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
266 return;
267
268 dst = FBADDR(x, y);
269 dst_end = FBADDR(x + width - 1, y + height - 1);
270
271 len = STRIDE_MAIN(width, height);
272 step = STRIDE_MAIN(ROW_INC, COL_INC);
273
274 do
275 {
276 switch (fillopt)
277 {
278 case OPT_SET:
279 {
280 fb_data *start = dst;
281 fb_data *end = start + len;
282 do {
283 *start = bits;
284 } while (++start < end);
285 break;
286 }
287
288 case OPT_COPY:
289 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
290 len * sizeof(fb_data));
291 break;
292
293 case OPT_NONE: /* DRMODE_COMPLEMENT */
294 {
295 fb_data *start = dst;
296 fb_data *end = start + len;
297 do {
298 flippixel(start);
299 } while (++start < end);
300 break;
301 }
302 }
303 dst += step;
304 }
305 while (dst <= dst_end);
306}
307
308/* About Rockbox' internal monochrome bitmap format:
309 *
310 * A bitmap contains one bit for every pixel that defines if that pixel is
311 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
312 * at top.
313 * The bytes are stored in row-major order, with byte 0 being top left,
314 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
315 * 0..7, the second row defines pixel row 8..15 etc.
316 *
317 * This is the mono bitmap format used on all other targets so far; the
318 * pixel packing doesn't really matter on a 8bit+ target. */
319
320/* Draw a partial monochrome bitmap */
321
322void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
323 int src_y, int stride, int x, int y,
324 int width, int height)
325{
326 const unsigned char *src_end;
327 fb_data *dst, *dst_col;
328 unsigned dmask = 0x100; /* bit 8 == sentinel */
329 int drmode = current_vp->drawmode;
330 int row;
331
332 /******************** Image in viewport clipping **********************/
333 /* nothing to draw? */
334 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
335 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
336 return;
337
338 if (x < 0)
339 {
340 width += x;
341 src_x -= x;
342 x = 0;
343 }
344 if (y < 0)
345 {
346 height += y;
347 src_y -= y;
348 y = 0;
349 }
350 if (x + width > current_vp->width)
351 width = current_vp->width - x;
352 if (y + height > current_vp->height)
353 height = current_vp->height - y;
354
355 /* adjust for viewport */
356 x += current_vp->x;
357 y += current_vp->y;
358
359#if defined(HAVE_VIEWPORT_CLIP)
360 /********************* Viewport on screen clipping ********************/
361 /* nothing to draw? */
362 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
363 || (x + width <= 0) || (y + height <= 0))
364 return;
365
366 /* clip image in viewport in screen */
367 if (x < 0)
368 {
369 width += x;
370 src_x -= x;
371 x = 0;
372 }
373 if (y < 0)
374 {
375 height += y;
376 src_y -= y;
377 y = 0;
378 }
379 if (x + width > LCD_WIDTH)
380 width = LCD_WIDTH - x;
381 if (y + height > LCD_HEIGHT)
382 height = LCD_HEIGHT - y;
383#endif
384
385 src += stride * (src_y >> 3) + src_x; /* move starting point */
386 src_y &= 7;
387 src_end = src + width;
388 dst_col = FBADDR(x, y);
389
390
391 if (drmode & DRMODE_INVERSEVID)
392 {
393 dmask = 0x1ff; /* bit 8 == sentinel */
394 drmode &= DRMODE_SOLID; /* mask out inversevid */
395 }
396
397 /* Use extra bit to avoid if () in the switch-cases below */
398 if ((drmode & DRMODE_BG) && lcd_backdrop)
399 drmode |= DRMODE_INT_BD;
400
401 /* go through each column and update each pixel */
402 do
403 {
404 const unsigned char *src_col = src++;
405 unsigned data = (*src_col ^ dmask) >> src_y;
406 fb_data fg, bg;
407 uintptr_t bo;
408
409 dst = dst_col;
410 dst_col += COL_INC;
411 row = height;
412
413#define UPDATE_SRC do { \
414 data >>= 1; \
415 if (data == 0x001) { \
416 src_col += stride; \
417 data = *src_col ^ dmask; \
418 } \
419 } while (0)
420
421 switch (drmode)
422 {
423 case DRMODE_COMPLEMENT:
424 do
425 {
426 if (data & 0x01)
427 flippixel(dst);
428
429 dst += ROW_INC;
430 UPDATE_SRC;
431 }
432 while (--row);
433 break;
434
435 case DRMODE_BG|DRMODE_INT_BD:
436 bo = lcd_backdrop_offset;
437 do
438 {
439 if (!(data & 0x01))
440 *dst = *(fb_data *)((long)dst + bo);
441
442 dst += ROW_INC;
443 UPDATE_SRC;
444 }
445 while (--row);
446 break;
447
448 case DRMODE_BG:
449 bg = FB_SCALARPACK(current_vp->bg_pattern);
450 do
451 {
452 if (!(data & 0x01))
453 *dst = bg;
454
455 dst += ROW_INC;
456 UPDATE_SRC;
457 }
458 while (--row);
459 break;
460
461 case DRMODE_FG:
462 fg = FB_SCALARPACK(current_vp->fg_pattern);
463 do
464 {
465 if (data & 0x01)
466 *dst = fg;
467
468 dst += ROW_INC;
469 UPDATE_SRC;
470 }
471 while (--row);
472 break;
473
474 case DRMODE_SOLID|DRMODE_INT_BD:
475 fg = FB_SCALARPACK(current_vp->fg_pattern);
476 bo = lcd_backdrop_offset;
477 do
478 {
479 *dst = (data & 0x01) ? fg
480 : *(fb_data *)((long)dst + bo);
481 dst += ROW_INC;
482 UPDATE_SRC;
483 }
484 while (--row);
485 break;
486
487 case DRMODE_SOLID:
488 fg = FB_SCALARPACK(current_vp->fg_pattern);
489 bg = FB_SCALARPACK(current_vp->bg_pattern);
490 do
491 {
492 *dst = (data & 0x01) ? fg : bg;
493 dst += ROW_INC;
494 UPDATE_SRC;
495 }
496 while (--row);
497 break;
498 }
499 }
500 while (src < src_end);
501}
502/* Draw a full monochrome bitmap */
503void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
504{
505 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
506}
507
508
509/* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2)
510 *
511 * For each pixel, 4bit of alpha information is stored in a byte-stream,
512 * so two pixels are packed into one byte.
513 * The lower nibble is the first pixel, the upper one the second. The stride is
514 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],...
515 * The format is independant of the internal display orientation and color
516 * representation, as to support the same font files on all displays.
517 * The values go linear from 0 (fully opaque) to 15 (fully transparent)
518 * (note how this is the opposite of the alpha channel in the ARGB format).
519 *
520 * This might suggest that rows need to have an even number of pixels.
521 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal
522 * with uneven colums (i.e. two rows can share one byte). And font files do
523 * exploit this.
524 * However, this is difficult to do for image files, especially bottom-up bitmaps,
525 * so lcd_bmp() do expect even rows.
526 */
527
528#define ALPHA_COLOR_FONT_DEPTH 2
529#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
530#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
531#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
532#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
533
534/* This is based on SDL (src/video/SDL_RLEaccel.c) ALPHA_BLIT32_888() macro */
535static inline fb_data blend_two_colors(unsigned c1, unsigned c2, unsigned a)
536{
537 unsigned s = c1;
538 unsigned d = c2;
539 unsigned s1 = s & 0xff00ff;
540 unsigned d1 = d & 0xff00ff;
541 a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1);
542 d1 = (d1 + ((s1 - d1) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00ff;
543 s &= 0xff00;
544 d &= 0xff00;
545 d = (d + ((s - d) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00;
546
547 return FB_SCALARPACK(d1 | d);
548}
549
550/* Blend an image with an alpha channel
551 * if image is NULL, drawing will happen according to the drawmode
552 * src is the alpha channel (4bit per pixel) */
553static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
554 const unsigned char *src, int src_x,
555 int src_y, int x, int y,
556 int width, int height,
557 int stride_image, int stride_src)
558{
559 fb_data *dst, *dst_row;
560 unsigned dmask = 0x00000000;
561 int drmode = current_vp->drawmode;
562 /* nothing to draw? */
563 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
564 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
565 return;
566
567 /* clipping */
568 if (x < 0)
569 {
570 width += x;
571 src_x -= x;
572 x = 0;
573 }
574 if (y < 0)
575 {
576 height += y;
577 src_y -= y;
578 y = 0;
579 }
580 if (x + width > current_vp->width)
581 width = current_vp->width - x;
582 if (y + height > current_vp->height)
583 height = current_vp->height - y;
584
585 /* adjust for viewport */
586 x += current_vp->x;
587 y += current_vp->y;
588
589#if defined(HAVE_VIEWPORT_CLIP)
590 /********************* Viewport on screen clipping ********************/
591 /* nothing to draw? */
592 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
593 || (x + width <= 0) || (y + height <= 0))
594 return;
595
596 /* clip image in viewport in screen */
597 if (x < 0)
598 {
599 width += x;
600 src_x -= x;
601 x = 0;
602 }
603 if (y < 0)
604 {
605 height += y;
606 src_y -= y;
607 y = 0;
608 }
609 if (x + width > LCD_WIDTH)
610 width = LCD_WIDTH - x;
611 if (y + height > LCD_HEIGHT)
612 height = LCD_HEIGHT - y;
613#endif
614
615 /* the following drawmode combinations are possible:
616 * 1) COMPLEMENT: just negates the framebuffer contents
617 * 2) BG and BG+backdrop: draws _only_ background pixels with either
618 * the background color or the backdrop (if any). The backdrop
619 * is an image in native lcd format
620 * 3) FG and FG+image: draws _only_ foreground pixels with either
621 * the foreground color or an image buffer. The image is in
622 * native lcd format
623 * 4) SOLID, SOLID+backdrop, SOLID+image, SOLID+backdrop+image, i.e. all
624 * possible combinations of 2) and 3). Draws both, fore- and background,
625 * pixels. The rules of 2) and 3) apply.
626 *
627 * INVERSEVID swaps fore- and background pixels, i.e. background pixels
628 * become foreground ones and vice versa.
629 */
630 if (drmode & DRMODE_INVERSEVID)
631 {
632 dmask = 0xffffffff;
633 drmode &= DRMODE_SOLID; /* mask out inversevid */
634 }
635
636 /* Use extra bits to avoid if () in the switch-cases below */
637 if (image != NULL)
638 drmode |= DRMODE_INT_IMG;
639
640 if ((drmode & DRMODE_BG) && lcd_backdrop)
641 drmode |= DRMODE_INT_BD;
642
643 dst_row = FBADDR(x, y);
644
645 int col, row = height;
646 unsigned data, pixels;
647 unsigned skip_end = (stride_src - width);
648 unsigned skip_start = src_y * stride_src + src_x;
649 unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x,
650 src_x * stride_image + src_y);
651
652#ifdef ALPHA_BITMAP_READ_WORDS
653 uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3);
654 skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3);
655 src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD;
656 data = letoh32(*src_w++) ^ dmask;
657 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD;
658#else
659 src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
660 data = *src ^ dmask;
661 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE;
662#endif
663 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
664#ifdef ALPHA_BITMAP_READ_WORDS
665 pixels = 8 - pixels;
666#endif
667
668 /* image is only accessed in DRMODE_INT_IMG cases, i.e. when non-NULL.
669 * Therefore NULL accesses are impossible and we can increment
670 * unconditionally (applies for stride at the end of the loop as well) */
671 image += skip_start_image;
672 /* go through the rows and update each pixel */
673 do
674 {
675 /* saving current_vp->fg/bg_pattern and lcd_backdrop_offset into these
676 * temp vars just before the loop helps gcc to opimize the loop better
677 * (testing showed ~15% speedup) */
678 unsigned fg, bg;
679 ptrdiff_t bo, img_offset;
680 col = width;
681 dst = dst_row;
682 dst_row += ROW_INC;
683#ifdef ALPHA_BITMAP_READ_WORDS
684#define UPDATE_SRC_ALPHA do { \
685 if (--pixels) \
686 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
687 else \
688 { \
689 data = letoh32(*src_w++) ^ dmask; \
690 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
691 } \
692 } while (0)
693#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
694#define UPDATE_SRC_ALPHA do { \
695 if (pixels ^= 1) \
696 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
697 else \
698 data = *(++src) ^ dmask; \
699 } while (0)
700#else
701#define UPDATE_SRC_ALPHA do { \
702 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
703 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
704 else \
705 data = *(++src) ^ dmask; \
706 } while (0)
707#endif
708
709 switch (drmode)
710 {
711 case DRMODE_COMPLEMENT:
712 do
713 {
714 unsigned px = FB_UNPACK_SCALAR_LCD(*dst);
715 *dst = blend_two_colors(px, ~px,
716 data & ALPHA_COLOR_LOOKUP_SIZE );
717 dst += COL_INC;
718 UPDATE_SRC_ALPHA;
719 }
720 while (--col);
721 break;
722 case DRMODE_BG|DRMODE_INT_BD:
723 bo = lcd_backdrop_offset;
724 do
725 {
726 unsigned px = FB_UNPACK_SCALAR_LCD(*dst);
727 unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo));
728 *dst = blend_two_colors(c, px, data & ALPHA_COLOR_LOOKUP_SIZE );
729 dst += COL_INC;
730 image += STRIDE_MAIN(1, stride_image);
731 UPDATE_SRC_ALPHA;
732 }
733 while (--col);
734 break;
735 case DRMODE_BG:
736 bg = current_vp->bg_pattern;
737 do
738 {
739 unsigned px = FB_UNPACK_SCALAR_LCD(*dst);
740 *dst = blend_two_colors(bg, px, data & ALPHA_COLOR_LOOKUP_SIZE );
741 dst += COL_INC;
742 UPDATE_SRC_ALPHA;
743 }
744 while (--col);
745 break;
746 case DRMODE_FG|DRMODE_INT_IMG:
747 img_offset = image - dst;
748 do
749 {
750 unsigned px1 = FB_UNPACK_SCALAR_LCD(*dst);
751 unsigned px2 = FB_UNPACK_SCALAR_LCD(*(dst + img_offset));
752 *dst = blend_two_colors(px1, px2, data & ALPHA_COLOR_LOOKUP_SIZE );
753 dst += COL_INC;
754 UPDATE_SRC_ALPHA;
755 }
756 while (--col);
757 break;
758 case DRMODE_FG:
759 fg = current_vp->fg_pattern;
760 do
761 {
762 unsigned px = FB_UNPACK_SCALAR_LCD(*dst);
763 *dst = blend_two_colors(px, fg, data & ALPHA_COLOR_LOOKUP_SIZE );
764 dst += COL_INC;
765 UPDATE_SRC_ALPHA;
766 }
767 while (--col);
768 break;
769 case DRMODE_SOLID|DRMODE_INT_BD:
770 bo = lcd_backdrop_offset;
771 fg = current_vp->fg_pattern;
772 do
773 {
774 unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo));
775 *dst = blend_two_colors(c, fg, data & ALPHA_COLOR_LOOKUP_SIZE );
776 dst += COL_INC;
777 UPDATE_SRC_ALPHA;
778 }
779 while (--col);
780 break;
781 case DRMODE_SOLID|DRMODE_INT_IMG:
782 bg = current_vp->bg_pattern;
783 img_offset = image - dst;
784 do
785 {
786 unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset));
787 *dst = blend_two_colors(bg, c, data & ALPHA_COLOR_LOOKUP_SIZE );
788 dst += COL_INC;
789 UPDATE_SRC_ALPHA;
790 }
791 while (--col);
792 break;
793 case DRMODE_SOLID|DRMODE_INT_BD|DRMODE_INT_IMG:
794 bo = lcd_backdrop_offset;
795 img_offset = image - dst;
796 do
797 {
798 unsigned px = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo));
799 unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset));
800 *dst = blend_two_colors(px, c, data & ALPHA_COLOR_LOOKUP_SIZE );
801 dst += COL_INC;
802 UPDATE_SRC_ALPHA;
803 }
804 while (--col);
805 break;
806 case DRMODE_SOLID:
807 bg = current_vp->bg_pattern;
808 fg = current_vp->fg_pattern;
809 do
810 {
811 *dst = blend_two_colors(bg, fg, data & ALPHA_COLOR_LOOKUP_SIZE );
812 dst += COL_INC;
813 UPDATE_SRC_ALPHA;
814 }
815 while (--col);
816 break;
817 }
818#ifdef ALPHA_BITMAP_READ_WORDS
819 if (skip_end < pixels)
820 {
821 pixels -= skip_end;
822 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
823 } else {
824 pixels = skip_end - pixels;
825 src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD;
826 pixels %= ALPHA_COLOR_PIXEL_PER_WORD;
827 data = letoh32(*src_w++) ^ dmask;
828 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
829 pixels = 8 - pixels;
830 }
831#else
832 if (skip_end)
833 {
834 pixels += skip_end;
835 if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
836 {
837 src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
838 pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
839 data = *src ^ dmask;
840 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
841 } else
842 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
843 }
844#endif
845
846 image += STRIDE_MAIN(stride_image,1);
847 } while (--row);
848}
849
850/*** drawing functions ***/
851
852/* Draw a horizontal line (optimised) */
853void lcd_hline(int x1, int x2, int y)
854{
855 int x, width;
856 fb_data *dst, *dst_end;
857 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
858
859 /* direction flip */
860 if (x2 < x1)
861 {
862 x = x1;
863 x1 = x2;
864 x2 = x;
865 }
866
867 /******************** In viewport clipping **********************/
868 /* nothing to draw? */
869 if (((unsigned)y >= (unsigned)current_vp->height) ||
870 (x1 >= current_vp->width) ||
871 (x2 < 0))
872 return;
873
874 if (x1 < 0)
875 x1 = 0;
876 if (x2 >= current_vp->width)
877 x2 = current_vp->width-1;
878
879 /* Adjust x1 and y to viewport */
880 x1 += current_vp->x;
881 x2 += current_vp->x;
882 y += current_vp->y;
883
884#if defined(HAVE_VIEWPORT_CLIP)
885 /********************* Viewport on screen clipping ********************/
886 /* nothing to draw? */
887 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
888 || (x2 < 0))
889 return;
890
891 /* clipping */
892 if (x1 < 0)
893 x1 = 0;
894 if (x2 >= LCD_WIDTH)
895 x2 = LCD_WIDTH-1;
896#endif
897
898 width = x2 - x1 + 1;
899
900 dst = FBADDR(x1 , y);
901 dst_end = dst + width;
902 do
903 {
904 pfunc(dst);
905 }
906 while (++dst < dst_end);
907}
908
909/* Draw a vertical line (optimised) */
910void lcd_vline(int x, int y1, int y2)
911{
912 int y;
913 fb_data *dst, *dst_end;
914 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
915
916 /* direction flip */
917 if (y2 < y1)
918 {
919 y = y1;
920 y1 = y2;
921 y2 = y;
922 }
923
924 /******************** In viewport clipping **********************/
925 /* nothing to draw? */
926 if (((unsigned)x >= (unsigned)current_vp->width) ||
927 (y1 >= current_vp->height) ||
928 (y2 < 0))
929 return;
930
931 if (y1 < 0)
932 y1 = 0;
933 if (y2 >= current_vp->height)
934 y2 = current_vp->height-1;
935
936 /* adjust for viewport */
937 x += current_vp->x;
938 y1 += current_vp->y;
939 y2 += current_vp->y;
940
941#if defined(HAVE_VIEWPORT_CLIP)
942 /********************* Viewport on screen clipping ********************/
943 /* nothing to draw? */
944 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
945 || (y2 < 0))
946 return;
947
948 /* clipping */
949 if (y1 < 0)
950 y1 = 0;
951 if (y2 >= LCD_HEIGHT)
952 y2 = LCD_HEIGHT-1;
953#endif
954
955 dst = FBADDR(x , y1);
956 dst_end = dst + (y2 - y1) * LCD_WIDTH;
957
958 do
959 {
960 pfunc(dst);
961 dst += LCD_WIDTH;
962 }
963 while (dst <= dst_end);
964}
965
966/* Draw a partial native bitmap */
967void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
968 int stride, int x, int y, int width,
969 int height)
970{
971 fb_data *dst;
972
973 /******************** Image in viewport clipping **********************/
974 /* nothing to draw? */
975 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
976 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
977 return;
978
979 if (x < 0)
980 {
981 width += x;
982 src_x -= x;
983 x = 0;
984 }
985 if (y < 0)
986 {
987 height += y;
988 src_y -= y;
989 y = 0;
990 }
991
992 if (x + width > current_vp->width)
993 width = current_vp->width - x;
994 if (y + height > current_vp->height)
995 height = current_vp->height - y;
996
997 /* adjust for viewport */
998 x += current_vp->x;
999 y += current_vp->y;
1000
1001#if defined(HAVE_VIEWPORT_CLIP)
1002 /********************* Viewport on screen clipping ********************/
1003 /* nothing to draw? */
1004 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1005 || (x + width <= 0) || (y + height <= 0))
1006 return;
1007
1008 /* clip image in viewport in screen */
1009 if (x < 0)
1010 {
1011 width += x;
1012 src_x -= x;
1013 x = 0;
1014 }
1015 if (y < 0)
1016 {
1017 height += y;
1018 src_y -= y;
1019 y = 0;
1020 }
1021 if (x + width > LCD_WIDTH)
1022 width = LCD_WIDTH - x;
1023 if (y + height > LCD_HEIGHT)
1024 height = LCD_HEIGHT - y;
1025#endif
1026
1027 src += stride * src_y + src_x; /* move starting point */
1028 dst = FBADDR(x, y);
1029
1030 do
1031 {
1032 memcpy(dst, src, width * sizeof(fb_data));
1033 src += stride;
1034 dst += LCD_WIDTH;
1035 }
1036 while (--height > 0);
1037}
1038
1039/* Draw a partial native bitmap with transparency and foreground colors */
1040void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
1041 int src_y, int stride, int x,
1042 int y, int width, int height)
1043{
1044 fb_data *dst;
1045 fb_data fg, transparent, replacewithfg;
1046
1047 /******************** Image in viewport clipping **********************/
1048 /* nothing to draw? */
1049 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
1050 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
1051 return;
1052
1053 if (x < 0)
1054 {
1055 width += x;
1056 src_x -= x;
1057 x = 0;
1058 }
1059 if (y < 0)
1060 {
1061 height += y;
1062 src_y -= y;
1063 y = 0;
1064 }
1065
1066 if (x + width > current_vp->width)
1067 width = current_vp->width - x;
1068 if (y + height > current_vp->height)
1069 height = current_vp->height - y;
1070
1071 /* adjust for viewport */
1072 x += current_vp->x;
1073 y += current_vp->y;
1074
1075#if defined(HAVE_VIEWPORT_CLIP)
1076 /********************* Viewport on screen clipping ********************/
1077 /* nothing to draw? */
1078 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1079 || (x + width <= 0) || (y + height <= 0))
1080 return;
1081
1082 /* clip image in viewport in screen */
1083 if (x < 0)
1084 {
1085 width += x;
1086 src_x -= x;
1087 x = 0;
1088 }
1089 if (y < 0)
1090 {
1091 height += y;
1092 src_y -= y;
1093 y = 0;
1094 }
1095 if (x + width > LCD_WIDTH)
1096 width = LCD_WIDTH - x;
1097 if (y + height > LCD_HEIGHT)
1098 height = LCD_HEIGHT - y;
1099#endif
1100
1101 src += stride * src_y + src_x; /* move starting point */
1102 dst = FBADDR(x, y);
1103
1104 transparent = FB_SCALARPACK(TRANSPARENT_COLOR);
1105 replacewithfg = FB_SCALARPACK(REPLACEWITHFG_COLOR);
1106 fg = FB_SCALARPACK(current_vp->fg_pattern);
1107#define CMP(c1, c2) (c1.r == c2.r && c1.g == c2.g && c1.b == c2.b)
1108
1109 do
1110 {
1111 const fb_data *src_row = src;
1112 fb_data *dst_row = dst;
1113 fb_data *row_end = dst_row + width;
1114 do
1115 {
1116 fb_data data = *src_row++;
1117 if (!CMP(data, transparent))
1118 {
1119 if (CMP(data, replacewithfg))
1120 data = fg;
1121 *dst_row = data;
1122 }
1123 }
1124 while (++dst_row < row_end);
1125 src += stride;
1126 dst += LCD_WIDTH;
1127 }
1128 while (--height > 0);
1129}