lcd drivers: Convert lcd_[remote_]framebuffer to a pointer
[maemo-rb.git] / firmware / drivers / lcd-16bit-common.c
blobc9e88b2137cf17c9829de990d43b82faa99348aa
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 enum fill_opt {
32 OPT_NONE = 0,
33 OPT_SET,
34 OPT_COPY
37 /*** globals ***/
38 fb_data lcd_static_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
39 IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16);
40 fb_data *lcd_framebuffer = &lcd_static_framebuffer[0][0];
42 static fb_data* lcd_backdrop = NULL;
43 static long lcd_backdrop_offset IDATA_ATTR = 0;
45 static struct viewport default_vp =
47 .x = 0,
48 .y = 0,
49 .width = LCD_WIDTH,
50 .height = LCD_HEIGHT,
51 .font = FONT_SYSFIXED,
52 .drawmode = DRMODE_SOLID,
53 .fg_pattern = LCD_DEFAULT_FG,
54 .bg_pattern = LCD_DEFAULT_BG,
55 .lss_pattern = LCD_DEFAULT_BG,
56 .lse_pattern = LCD_DEFAULT_BG,
57 .lst_pattern = LCD_DEFAULT_BG,
60 static struct viewport* current_vp IDATA_ATTR = &default_vp;
62 /* LCD init */
63 void lcd_init(void)
65 lcd_clear_display();
67 /* Call device specific init */
68 lcd_init_device();
69 scroll_init();
71 /*** Viewports ***/
73 void lcd_set_viewport(struct viewport* vp)
75 if (vp == NULL)
76 current_vp = &default_vp;
77 else
78 current_vp = vp;
80 #if defined(SIMULATOR)
81 /* Force the viewport to be within bounds. If this happens it should
82 * be considered an error - the viewport will not draw as it might be
83 * expected.
85 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
86 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
87 || current_vp->x + current_vp->width > LCD_WIDTH
88 || current_vp->y + current_vp->height > LCD_HEIGHT)
90 #if !defined(HAVE_VIEWPORT_CLIP)
91 DEBUGF("ERROR: "
92 #else
93 DEBUGF("NOTE: "
94 #endif
95 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
96 current_vp->x, current_vp->y,
97 current_vp->width, current_vp->height);
100 #endif
103 void lcd_update_viewport(void)
105 lcd_update_rect(current_vp->x, current_vp->y,
106 current_vp->width, current_vp->height);
109 void lcd_update_viewport_rect(int x, int y, int width, int height)
111 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
114 /*** parameter handling ***/
116 void lcd_set_drawmode(int mode)
118 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
121 int lcd_get_drawmode(void)
123 return current_vp->drawmode;
126 void lcd_set_foreground(unsigned color)
128 current_vp->fg_pattern = color;
131 unsigned lcd_get_foreground(void)
133 return current_vp->fg_pattern;
136 void lcd_set_background(unsigned color)
138 current_vp->bg_pattern = color;
141 unsigned lcd_get_background(void)
143 return current_vp->bg_pattern;
146 void lcd_set_selector_start(unsigned color)
148 current_vp->lss_pattern = color;
151 void lcd_set_selector_end(unsigned color)
153 current_vp->lse_pattern = color;
156 void lcd_set_selector_text(unsigned color)
158 current_vp->lst_pattern = color;
161 void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
163 lcd_set_drawmode(mode);
164 current_vp->fg_pattern = fg_color;
165 current_vp->bg_pattern = bg_color;
168 int lcd_getwidth(void)
170 return current_vp->width;
173 int lcd_getheight(void)
175 return current_vp->height;
178 void lcd_setfont(int newfont)
180 current_vp->font = newfont;
183 int lcd_getfont(void)
185 return current_vp->font;
188 int lcd_getstringsize(const unsigned char *str, int *w, int *h)
190 return font_getstringsize(str, w, h, current_vp->font);
193 /*** low-level drawing functions ***/
195 static void ICODE_ATTR setpixel(fb_data *address)
197 *address = current_vp->fg_pattern;
200 static void ICODE_ATTR clearpixel(fb_data *address)
202 *address = current_vp->bg_pattern;
205 static void ICODE_ATTR clearimgpixel(fb_data *address)
207 *address = *(fb_data *)((long)address + lcd_backdrop_offset);
210 static void ICODE_ATTR flippixel(fb_data *address)
212 *address = ~(*address);
215 static void ICODE_ATTR nopixel(fb_data *address)
217 (void)address;
220 lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[8] = {
221 flippixel, nopixel, setpixel, setpixel,
222 nopixel, clearpixel, nopixel, clearpixel
225 lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = {
226 flippixel, nopixel, setpixel, setpixel,
227 nopixel, clearimgpixel, nopixel, clearimgpixel
230 lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
232 void lcd_set_backdrop(fb_data* backdrop)
234 lcd_backdrop = backdrop;
235 if (backdrop)
237 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
238 lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop;
240 else
242 lcd_backdrop_offset = 0;
243 lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
247 fb_data* lcd_get_backdrop(void)
249 return lcd_backdrop;
252 /* Clear the whole display */
253 void lcd_clear_display(void)
255 struct viewport* old_vp = current_vp;
257 current_vp = &default_vp;
259 lcd_clear_viewport();
261 current_vp = old_vp;
264 /* Set a single pixel */
265 void lcd_drawpixel(int x, int y)
267 if ( ((unsigned)x < (unsigned)current_vp->width)
268 && ((unsigned)y < (unsigned)current_vp->height)
269 #if defined(HAVE_VIEWPORT_CLIP)
270 && ((unsigned)x < (unsigned)LCD_WIDTH)
271 && ((unsigned)y < (unsigned)LCD_HEIGHT)
272 #endif
274 lcd_fastpixelfuncs[current_vp->drawmode](FBADDR(current_vp->x+x, current_vp->y+y));
277 /* Draw a line */
278 void lcd_drawline(int x1, int y1, int x2, int y2)
280 int numpixels;
281 int i;
282 int deltax, deltay;
283 int d, dinc1, dinc2;
284 int x, xinc1, xinc2;
285 int y, yinc1, yinc2;
286 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
288 deltay = abs(y2 - y1);
289 if (deltay == 0)
291 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
292 lcd_hline(x1, x2, y1);
293 return;
295 deltax = abs(x2 - x1);
296 if (deltax == 0)
298 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
299 lcd_vline(x1, y1, y2);
300 return;
302 xinc2 = 1;
303 yinc2 = 1;
305 if (deltax >= deltay)
307 numpixels = deltax;
308 d = 2 * deltay - deltax;
309 dinc1 = deltay * 2;
310 dinc2 = (deltay - deltax) * 2;
311 xinc1 = 1;
312 yinc1 = 0;
314 else
316 numpixels = deltay;
317 d = 2 * deltax - deltay;
318 dinc1 = deltax * 2;
319 dinc2 = (deltax - deltay) * 2;
320 xinc1 = 0;
321 yinc1 = 1;
323 numpixels++; /* include endpoints */
325 if (x1 > x2)
327 xinc1 = -xinc1;
328 xinc2 = -xinc2;
331 if (y1 > y2)
333 yinc1 = -yinc1;
334 yinc2 = -yinc2;
337 x = x1;
338 y = y1;
340 for (i = 0; i < numpixels; i++)
342 if ( ((unsigned)x < (unsigned)current_vp->width)
343 && ((unsigned)y < (unsigned)current_vp->height)
344 #if defined(HAVE_VIEWPORT_CLIP)
345 && ((unsigned)x < (unsigned)LCD_WIDTH)
346 && ((unsigned)y < (unsigned)LCD_HEIGHT)
347 #endif
349 pfunc(FBADDR(x + current_vp->x, y + current_vp->y));
351 if (d < 0)
353 d += dinc1;
354 x += xinc1;
355 y += yinc1;
357 else
359 d += dinc2;
360 x += xinc2;
361 y += yinc2;
366 /* Draw a rectangular box */
367 void lcd_drawrect(int x, int y, int width, int height)
369 if ((width <= 0) || (height <= 0))
370 return;
372 int x2 = x + width - 1;
373 int y2 = y + height - 1;
375 lcd_vline(x, y, y2);
376 lcd_vline(x2, y, y2);
377 lcd_hline(x, x2, y);
378 lcd_hline(x, x2, y2);
382 /* About Rockbox' internal monochrome bitmap format:
384 * A bitmap contains one bit for every pixel that defines if that pixel is
385 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
386 * at top.
387 * The bytes are stored in row-major order, with byte 0 being top left,
388 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
389 * 0..7, the second row defines pixel row 8..15 etc.
391 * This is the mono bitmap format used on all other targets so far; the
392 * pixel packing doesn't really matter on a 8bit+ target. */
394 /* Draw a partial monochrome bitmap */
396 void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
397 int src_y, int stride, int x, int y,
398 int width, int height)
400 const unsigned char *src_end;
401 fb_data *dst, *dst_col;
402 unsigned dmask = 0x100; /* bit 8 == sentinel */
403 int drmode = current_vp->drawmode;
404 int row;
406 /******************** Image in viewport clipping **********************/
407 /* nothing to draw? */
408 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
409 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
410 return;
412 if (x < 0)
414 width += x;
415 src_x -= x;
416 x = 0;
418 if (y < 0)
420 height += y;
421 src_y -= y;
422 y = 0;
424 if (x + width > current_vp->width)
425 width = current_vp->width - x;
426 if (y + height > current_vp->height)
427 height = current_vp->height - y;
429 /* adjust for viewport */
430 x += current_vp->x;
431 y += current_vp->y;
433 #if defined(HAVE_VIEWPORT_CLIP)
434 /********************* Viewport on screen clipping ********************/
435 /* nothing to draw? */
436 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
437 || (x + width <= 0) || (y + height <= 0))
438 return;
440 /* clip image in viewport in screen */
441 if (x < 0)
443 width += x;
444 src_x -= x;
445 x = 0;
447 if (y < 0)
449 height += y;
450 src_y -= y;
451 y = 0;
453 if (x + width > LCD_WIDTH)
454 width = LCD_WIDTH - x;
455 if (y + height > LCD_HEIGHT)
456 height = LCD_HEIGHT - y;
457 #endif
459 src += stride * (src_y >> 3) + src_x; /* move starting point */
460 src_y &= 7;
461 src_end = src + width;
462 dst_col = FBADDR(x, y);
465 if (drmode & DRMODE_INVERSEVID)
467 dmask = 0x1ff; /* bit 8 == sentinel */
468 drmode &= DRMODE_SOLID; /* mask out inversevid */
471 /* go through each column and update each pixel */
474 const unsigned char *src_col = src++;
475 unsigned data = (*src_col ^ dmask) >> src_y;
476 int fg, bg;
477 long bo;
479 dst = dst_col;
480 dst_col += COL_INC;
481 row = height;
483 #define UPDATE_SRC do { \
484 data >>= 1; \
485 if (data == 0x001) { \
486 src_col += stride; \
487 data = *src_col ^ dmask; \
489 } while (0)
491 switch (drmode)
493 case DRMODE_COMPLEMENT:
496 if (data & 0x01)
497 *dst = ~(*dst);
499 dst += ROW_INC;
500 UPDATE_SRC;
502 while (--row);
503 break;
505 case DRMODE_BG:
506 if (lcd_backdrop)
508 bo = lcd_backdrop_offset;
511 if (!(data & 0x01))
512 *dst = *(fb_data *)((long)dst + bo);
514 dst += ROW_INC;
515 UPDATE_SRC;
517 while (--row);
519 else
521 bg = current_vp->bg_pattern;
524 if (!(data & 0x01))
525 *dst = bg;
527 dst += ROW_INC;
528 UPDATE_SRC;
530 while (--row);
532 break;
534 case DRMODE_FG:
535 fg = current_vp->fg_pattern;
538 if (data & 0x01)
539 *dst = fg;
541 dst += ROW_INC;
542 UPDATE_SRC;
544 while (--row);
545 break;
547 case DRMODE_SOLID:
548 fg = current_vp->fg_pattern;
549 if (lcd_backdrop)
551 bo = lcd_backdrop_offset;
554 *dst = (data & 0x01) ? fg
555 : *(fb_data *)((long)dst + bo);
556 dst += ROW_INC;
557 UPDATE_SRC;
559 while (--row);
561 else
563 bg = current_vp->bg_pattern;
566 *dst = (data & 0x01) ? fg : bg;
567 dst += ROW_INC;
568 UPDATE_SRC;
570 while (--row);
572 break;
575 while (src < src_end);
577 /* Draw a full monochrome bitmap */
578 void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
580 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
584 /* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2)
586 * For each pixel, 4bit of alpha information is stored in a byte-stream,
587 * so two pixels are packed into one byte.
588 * The lower nibble is the first pixel, the upper one the second. The stride is
589 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],...
590 * The format is independant of the internal display orientation and color
591 * representation, as to support the same font files on all displays.
592 * The values go linear from 0 (fully transparent) to 15 (fully opaque).
594 * This might suggest that rows need to have an even number of pixels.
595 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal
596 * with uneven colums (i.e. two rows can share one byte). And font files do
597 * exploit this.
598 * However, this is difficult to do for image files, especially bottom-up bitmaps,
599 * so lcd_bmp() do expect even rows.
602 #define ALPHA_COLOR_FONT_DEPTH 2
603 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
604 #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
605 #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
606 #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
607 #ifdef CPU_ARM
608 #define BLEND_INIT do {} while (0)
609 #define BLEND_FINISH do {} while(0)
610 #define BLEND_START(acc, color, alpha) \
611 asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
612 #define BLEND_CONT(acc, color, alpha) \
613 asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
614 #define BLEND_OUT(acc) do {} while (0)
615 #elif defined(CPU_COLDFIRE)
616 #define ALPHA_BITMAP_READ_WORDS
617 #define BLEND_INIT \
618 unsigned long _macsr = coldfire_get_macsr(); \
619 coldfire_set_macsr(EMAC_UNSIGNED)
620 #define BLEND_FINISH \
621 coldfire_set_macsr(_macsr)
622 #define BLEND_START(acc, color, alpha) \
623 asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
624 #define BLEND_CONT BLEND_START
625 #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
626 #else
627 #define BLEND_INIT do {} while (0)
628 #define BLEND_FINISH do {} while(0)
629 #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
630 #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
631 #define BLEND_OUT(acc) do {} while (0)
632 #endif
634 /* Blend the given two colors */
635 static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a)
637 a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1);
638 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
639 c1 = swap16(c1);
640 c2 = swap16(c2);
641 #endif
642 unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f;
643 unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f;
644 unsigned p;
645 BLEND_START(p, c1l, a);
646 BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a);
647 BLEND_OUT(p);
648 p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f;
649 p |= (p >> 16);
650 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
651 return swap16(p);
652 #else
653 return p;
654 #endif
657 /* Blend the given color with the value from the alpha_color_lookup table */
658 static inline unsigned blend_color(unsigned c, unsigned a)
660 return blend_two_colors(c, current_vp->fg_pattern, a);
663 /* Blend an image with an alpha channel
664 * if image is NULL, drawing will happen according to the drawmode
665 * src is the alpha channel (4bit per pixel) */
666 static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
667 const unsigned char *src, int src_x,
668 int src_y, int x, int y,
669 int width, int height,
670 int stride_image, int stride_src)
672 fb_data *dst, *dst_row;
673 const fb_data *image_row;
674 unsigned dmask = 0x00000000;
675 int drmode = current_vp->drawmode;
676 /* nothing to draw? */
677 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
678 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
679 return;
680 /* initialize blending */
681 BLEND_INIT;
683 /* clipping */
684 if (x < 0)
686 width += x;
687 src_x -= x;
688 x = 0;
690 if (y < 0)
692 height += y;
693 src_y -= y;
694 y = 0;
696 if (x + width > current_vp->width)
697 width = current_vp->width - x;
698 if (y + height > current_vp->height)
699 height = current_vp->height - y;
701 /* adjust for viewport */
702 x += current_vp->x;
703 y += current_vp->y;
705 #if defined(HAVE_VIEWPORT_CLIP)
706 /********************* Viewport on screen clipping ********************/
707 /* nothing to draw? */
708 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
709 || (x + width <= 0) || (y + height <= 0))
711 BLEND_FINISH;
712 return;
715 /* clip image in viewport in screen */
716 if (x < 0)
718 width += x;
719 src_x -= x;
720 x = 0;
722 if (y < 0)
724 height += y;
725 src_y -= y;
726 y = 0;
728 if (x + width > LCD_WIDTH)
729 width = LCD_WIDTH - x;
730 if (y + height > LCD_HEIGHT)
731 height = LCD_HEIGHT - y;
732 #endif
734 if (drmode & DRMODE_INVERSEVID)
736 dmask = 0xffffffff;
737 drmode &= DRMODE_SOLID; /* mask out inversevid */
739 /* sourcing from an image ignore drawmode.
740 * Set to DRMODE_BG as we use its code path in the switch below */
741 if (image != NULL)
743 drmode = DRMODE_BG;
745 if (drmode == DRMODE_BG)
747 dmask = ~dmask;
750 dst_row = FBADDR(x, y);
752 int col, row = height;
753 unsigned data, pixels;
754 unsigned skip_end = (stride_src - width);
755 unsigned skip_start = src_y * stride_src + src_x;
756 unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x,
757 src_x * stride_image + src_y);
759 #ifdef ALPHA_BITMAP_READ_WORDS
760 uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3);
761 skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3);
762 src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD;
763 data = letoh32(*src_w++) ^ dmask;
764 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD;
765 #else
766 src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
767 data = *src ^ dmask;
768 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE;
769 #endif
770 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
771 #ifdef ALPHA_BITMAP_READ_WORDS
772 pixels = 8 - pixels;
773 #endif
774 if (image)
775 image += skip_start_image;
776 image_row = image;
778 /* go through the rows and update each pixel */
781 col = width;
782 dst = dst_row;
783 dst_row += ROW_INC;
784 if (image_row) {
785 image = image_row;
786 image_row += STRIDE_MAIN(stride_image,1);
788 else
789 image = dst;
790 #ifdef ALPHA_BITMAP_READ_WORDS
791 #define UPDATE_SRC_ALPHA do { \
792 if (--pixels) \
793 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
794 else \
796 data = letoh32(*src_w++) ^ dmask; \
797 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
799 } while (0)
800 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
801 #define UPDATE_SRC_ALPHA do { \
802 if (pixels ^= 1) \
803 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
804 else \
805 data = *(++src) ^ dmask; \
806 } while (0)
807 #else
808 #define UPDATE_SRC_ALPHA do { \
809 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
810 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
811 else \
812 data = *(++src) ^ dmask; \
813 } while (0)
814 #endif
815 /* we don't want to have this in our inner
816 * loop and the codesize increase is minimal */
817 switch (drmode)
819 case DRMODE_COMPLEMENT:
822 *dst = blend_two_colors(*dst, ~(*dst),
823 data & ALPHA_COLOR_LOOKUP_SIZE );
824 dst += COL_INC;
825 UPDATE_SRC_ALPHA;
827 while (--col);
828 break;
829 case DRMODE_BG:
830 if(lcd_backdrop)
832 uintptr_t bo = lcd_backdrop_offset;
835 *dst = blend_two_colors(*(fb_data *)((uintptr_t)dst + bo),
836 *image, data & ALPHA_COLOR_LOOKUP_SIZE );
838 dst += COL_INC;
839 image += STRIDE_MAIN(1, stride_image);
840 UPDATE_SRC_ALPHA;
842 while (--col);
844 else
848 *dst = blend_two_colors(current_vp->bg_pattern,
849 *image, data & ALPHA_COLOR_LOOKUP_SIZE );
850 dst += COL_INC;
851 image += STRIDE_MAIN(1, stride_image);
852 UPDATE_SRC_ALPHA;
854 while (--col);
856 break;
857 case DRMODE_FG:
860 *dst = blend_color(*dst, data & ALPHA_COLOR_LOOKUP_SIZE );
861 dst += COL_INC;
862 UPDATE_SRC_ALPHA;
864 while (--col);
865 break;
866 case DRMODE_SOLID:
867 if(lcd_backdrop)
869 uintptr_t bo = lcd_backdrop_offset;
872 *dst = blend_color(*(fb_data *)((uintptr_t)dst + bo),
873 data & ALPHA_COLOR_LOOKUP_SIZE );
874 dst += COL_INC;
875 UPDATE_SRC_ALPHA;
877 while (--col);
879 else
883 *dst = blend_color(current_vp->bg_pattern,
884 data & ALPHA_COLOR_LOOKUP_SIZE );
885 dst += COL_INC;
886 UPDATE_SRC_ALPHA;
888 while (--col);
890 break;
892 #ifdef ALPHA_BITMAP_READ_WORDS
893 if (skip_end < pixels)
895 pixels -= skip_end;
896 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
897 } else {
898 pixels = skip_end - pixels;
899 src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD;
900 pixels %= ALPHA_COLOR_PIXEL_PER_WORD;
901 data = letoh32(*src_w++) ^ dmask;
902 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
903 pixels = 8 - pixels;
905 #else
906 if (skip_end)
908 pixels += skip_end;
909 if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
911 src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
912 pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
913 data = *src ^ dmask;
914 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
915 } else
916 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
918 #endif
919 } while (--row);
921 BLEND_FINISH;
924 /* Draw a full native bitmap */
925 void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
927 lcd_bitmap_part(src, 0, 0, STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
930 /* Draw a full native bitmap with a transparent color */
931 void lcd_bitmap_transparent(const fb_data *src, int x, int y,
932 int width, int height)
934 lcd_bitmap_transparent_part(src, 0, 0,
935 STRIDE(SCREEN_MAIN, width, height), x, y, width, height);
938 /* draw alpha bitmap for anti-alias font */
939 void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
940 int src_y, int stride, int x, int y,
941 int width, int height)
943 lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride);
946 /* Draw a partial bitmap (mono or native) including alpha channel */
947 void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y,
948 int x, int y, int width, int height)
950 int bitmap_stride = STRIDE_MAIN(bm->width, bm->height);
951 if (bm->format == FORMAT_MONO)
952 lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height);
953 else if (bm->alpha_offset > 0)
954 lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset,
955 src_x, src_y, x, y, width, height,
956 bitmap_stride, ALIGN_UP(bm->width, 2));
957 else
958 lcd_bitmap_transparent_part((fb_data*)bm->data,
959 src_x, src_y, bitmap_stride, x, y, width, height);
962 /* Draw a native bitmap with alpha channel */
963 void ICODE_ATTR lcd_bmp(const struct bitmap *bmp, int x, int y)
965 lcd_bmp_part(bmp, 0, 0, x, y, bmp->width, bmp->height);
969 * |R| |1.000000 -0.000001 1.402000| |Y'|
970 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
971 * |B| |1.000000 1.772000 0.000000| |Pr|
972 * Scaled, normalized, rounded and tweaked to yield RGB 565:
973 * |R| |74 0 101| |Y' - 16| >> 9
974 * |G| = |74 -24 -51| |Cb - 128| >> 8
975 * |B| |74 128 0| |Cr - 128| >> 9
977 #define YFAC (74)
978 #define RVFAC (101)
979 #define GUFAC (-24)
980 #define GVFAC (-51)
981 #define BUFAC (128)
983 static inline int clamp(int val, int min, int max)
985 if (val < min)
986 val = min;
987 else if (val > max)
988 val = max;
989 return val;
992 #ifndef _WIN32
994 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
995 * When building win32 simulators, we won't be using an optimized version of
996 * lcd_blit_yuv(), so just don't use the weak attribute.
998 __attribute__((weak))
999 #endif
1000 void lcd_yuv_set_options(unsigned options)
1002 (void)options;
1005 /* Draw a partial YUV colour bitmap */
1006 #ifndef _WIN32
1007 __attribute__((weak))
1008 #endif
1009 void lcd_blit_yuv(unsigned char * const src[3],
1010 int src_x, int src_y, int stride,
1011 int x, int y, int width, int height)
1013 const unsigned char *ysrc, *usrc, *vsrc;
1014 int linecounter;
1015 fb_data *dst, *row_end;
1016 long z;
1018 /* width and height must be >= 2 and an even number */
1019 width &= ~1;
1020 linecounter = height >> 1;
1022 #if LCD_WIDTH >= LCD_HEIGHT
1023 dst = FBADDR(x, y);
1024 row_end = dst + width;
1025 #else
1026 dst = FBADDR(LCD_WIDTH - y - 1, x);
1027 row_end = dst + LCD_WIDTH * width;
1028 #endif
1030 z = stride * src_y;
1031 ysrc = src[0] + z + src_x;
1032 usrc = src[1] + (z >> 2) + (src_x >> 1);
1033 vsrc = src[2] + (usrc - src[1]);
1035 /* stride => amount to jump from end of last row to start of next */
1036 stride -= width;
1038 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
1044 int y, cb, cr, rv, guv, bu, r, g, b;
1046 y = YFAC*(*ysrc++ - 16);
1047 cb = *usrc++ - 128;
1048 cr = *vsrc++ - 128;
1050 rv = RVFAC*cr;
1051 guv = GUFAC*cb + GVFAC*cr;
1052 bu = BUFAC*cb;
1054 r = y + rv;
1055 g = y + guv;
1056 b = y + bu;
1058 if ((unsigned)(r | g | b) > 64*256-1)
1060 r = clamp(r, 0, 64*256-1);
1061 g = clamp(g, 0, 64*256-1);
1062 b = clamp(b, 0, 64*256-1);
1065 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1067 #if LCD_WIDTH >= LCD_HEIGHT
1068 dst++;
1069 #else
1070 dst += LCD_WIDTH;
1071 #endif
1073 y = YFAC*(*ysrc++ - 16);
1074 r = y + rv;
1075 g = y + guv;
1076 b = y + bu;
1078 if ((unsigned)(r | g | b) > 64*256-1)
1080 r = clamp(r, 0, 64*256-1);
1081 g = clamp(g, 0, 64*256-1);
1082 b = clamp(b, 0, 64*256-1);
1085 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1087 #if LCD_WIDTH >= LCD_HEIGHT
1088 dst++;
1089 #else
1090 dst += LCD_WIDTH;
1091 #endif
1093 while (dst < row_end);
1095 ysrc += stride;
1096 usrc -= width >> 1;
1097 vsrc -= width >> 1;
1099 #if LCD_WIDTH >= LCD_HEIGHT
1100 row_end += LCD_WIDTH;
1101 dst += LCD_WIDTH - width;
1102 #else
1103 row_end -= 1;
1104 dst -= LCD_WIDTH*width + 1;
1105 #endif
1109 int y, cb, cr, rv, guv, bu, r, g, b;
1111 y = YFAC*(*ysrc++ - 16);
1112 cb = *usrc++ - 128;
1113 cr = *vsrc++ - 128;
1115 rv = RVFAC*cr;
1116 guv = GUFAC*cb + GVFAC*cr;
1117 bu = BUFAC*cb;
1119 r = y + rv;
1120 g = y + guv;
1121 b = y + bu;
1123 if ((unsigned)(r | g | b) > 64*256-1)
1125 r = clamp(r, 0, 64*256-1);
1126 g = clamp(g, 0, 64*256-1);
1127 b = clamp(b, 0, 64*256-1);
1130 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1132 #if LCD_WIDTH >= LCD_HEIGHT
1133 dst++;
1134 #else
1135 dst += LCD_WIDTH;
1136 #endif
1138 y = YFAC*(*ysrc++ - 16);
1139 r = y + rv;
1140 g = y + guv;
1141 b = y + bu;
1143 if ((unsigned)(r | g | b) > 64*256-1)
1145 r = clamp(r, 0, 64*256-1);
1146 g = clamp(g, 0, 64*256-1);
1147 b = clamp(b, 0, 64*256-1);
1150 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
1152 #if LCD_WIDTH >= LCD_HEIGHT
1153 dst++;
1154 #else
1155 dst += LCD_WIDTH;
1156 #endif
1158 while (dst < row_end);
1160 ysrc += stride;
1161 usrc += stride >> 1;
1162 vsrc += stride >> 1;
1164 #if LCD_WIDTH >= LCD_HEIGHT
1165 row_end += LCD_WIDTH;
1166 dst += LCD_WIDTH - width;
1167 #else
1168 row_end -= 1;
1169 dst -= LCD_WIDTH*width + 1;
1170 #endif
1172 while (--linecounter > 0);
1174 #if LCD_WIDTH >= LCD_HEIGHT
1175 lcd_update_rect(x, y, width, height);
1176 #else
1177 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
1178 #endif