rk27xx: Disable cache while invalidating it.
[maemo-rb.git] / firmware / drivers / lcd-2bit-vi.c
blob8dc746f5219517872d6eea28fa4b517a5ae1074e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved 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 ****************************************************************************/
24 #include "config.h"
26 #include "lcd.h"
27 #include "kernel.h"
28 #include "thread.h"
29 #include <stdlib.h>
30 #include "string-extra.h" /* mem*() */
31 #include "file.h"
32 #include "debug.h"
33 #include "system.h"
34 #include "font.h"
35 #include "rbunicode.h"
36 #include "bidi.h"
37 #include "scroll_engine.h"
39 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
40 #define LCDFN(fn) lcd_ ## fn
41 #define FBFN(fn) fb_ ## fn
42 #define LCDM(ma) LCD_ ## ma
43 #define FBSIZE FRAMEBUFFER_SIZE
44 #define LCDNAME "lcd_"
45 #define LCDFB(x,y) FBADDR(x, y)
46 #define MAIN_LCD
47 #endif
49 /*** globals ***/
51 FBFN(data) LCDFN(static_framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IRAM_LCDFRAMEBUFFER;
52 FBFN(data) *LCDFN(framebuffer) = &LCDFN(static_framebuffer)[0][0];
55 static const FBFN(data) patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
57 static FBFN(data) *backdrop = NULL;
58 static long backdrop_offset IDATA_ATTR = 0;
60 static struct viewport default_vp =
62 .x = 0,
63 .y = 0,
64 .width = LCDM(WIDTH),
65 .height = LCDM(HEIGHT),
66 .font = FONT_SYSFIXED,
67 .drawmode = DRMODE_SOLID,
68 .fg_pattern = LCDM(DEFAULT_FG),
69 .bg_pattern = LCDM(DEFAULT_BG)
72 static struct viewport * current_vp IBSS_ATTR;
74 static unsigned fg_pattern IBSS_ATTR;
75 static unsigned bg_pattern IBSS_ATTR;
77 /*** Viewports ***/
79 void LCDFN(set_viewport)(struct viewport* vp)
81 if (vp == NULL)
82 current_vp = &default_vp;
83 else
84 current_vp = vp;
86 fg_pattern = patterns[current_vp->fg_pattern & 3];
87 bg_pattern = patterns[current_vp->bg_pattern & 3];
89 #if defined(SIMULATOR)
90 /* Force the viewport to be within bounds. If this happens it should
91 * be considered an error - the viewport will not draw as it might be
92 * expected.
94 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
95 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
96 || current_vp->x + current_vp->width > LCDM(WIDTH)
97 || current_vp->y + current_vp->height > LCDM(HEIGHT))
99 #if !defined(HAVE_VIEWPORT_CLIP)
100 DEBUGF("ERROR: "
101 #else
102 DEBUGF("NOTE: "
103 #endif
104 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
105 current_vp->x, current_vp->y,
106 current_vp->width, current_vp->height);
109 #endif
112 void LCDFN(update_viewport)(void)
114 LCDFN(update_rect)(current_vp->x, current_vp->y,
115 current_vp->width, current_vp->height);
118 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
120 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
123 /* LCD init */
124 void LCDFN(init)(void)
126 LCDFN(set_viewport)(NULL);
127 LCDFN(clear_display)();
128 LCDFN(init_device)();
129 #ifdef MAIN_LCD
130 scroll_init();
131 #endif
134 /*** parameter handling ***/
136 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
137 /* When compiling for remote LCD and the main LCD is colour. */
138 unsigned lcd_remote_color_to_native(unsigned color)
140 unsigned r = (color & 0xf800) >> 10;
141 unsigned g = (color & 0x07e0) >> 5;
142 unsigned b = (color & 0x001f) << 2;
144 * |R|
145 * |Y'| = |0.299000 0.587000 0.114000| |G|
146 * |B|
148 return (5*r + 9*g + b) >> 8;
150 #endif
152 void LCDFN(set_drawmode)(int mode)
154 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
157 int LCDFN(get_drawmode)(void)
159 return current_vp->drawmode;
162 void LCDFN(set_foreground)(unsigned brightness)
164 current_vp->fg_pattern = brightness;
165 fg_pattern = patterns[brightness & 3];
168 unsigned LCDFN(get_foreground)(void)
170 return current_vp->fg_pattern;
173 void LCDFN(set_background)(unsigned brightness)
175 current_vp->bg_pattern = brightness;
176 bg_pattern = patterns[brightness & 3];
179 unsigned LCDFN(get_background)(void)
181 return current_vp->bg_pattern;
184 void LCDFN(set_drawinfo)(int mode, unsigned fg_brightness,
185 unsigned bg_brightness)
187 LCDFN(set_drawmode)(mode);
188 LCDFN(set_foreground)(fg_brightness);
189 LCDFN(set_background)(bg_brightness);
192 int LCDFN(getwidth)(void)
194 return current_vp->width;
197 int LCDFN(getheight)(void)
199 return current_vp->height;
201 void LCDFN(setfont)(int newfont)
203 current_vp->font = newfont;
206 int LCDFN(getfont)(void)
208 return current_vp->font;
211 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
213 return font_getstringsize(str, w, h, current_vp->font);
216 /*** low-level drawing functions ***/
218 static void setpixel(int x, int y)
220 unsigned mask = 0x0101 << (y & 7);
221 FBFN(data) *address = LCDFB(x,y>>3);
222 unsigned data = *address;
224 *address = data ^ ((data ^ fg_pattern) & mask);
227 static void clearpixel(int x, int y)
229 unsigned mask = 0x0101 << (y & 7);
230 FBFN(data) *address = LCDFB(x,y>>3);
231 unsigned data = *address;
233 *address = data ^ ((data ^ bg_pattern) & mask);
236 static void clearimgpixel(int x, int y)
238 unsigned mask = 0x0101 << (y & 7);
239 FBFN(data) *address = LCDFB(x,y>>3);
240 unsigned data = *address;
242 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
243 + backdrop_offset)) & mask);
246 static void flippixel(int x, int y)
248 unsigned mask = 0x0101 << (y & 7);
249 FBFN(data) *address = LCDFB(x,y>>3);
251 *address ^= mask;
254 static void nopixel(int x, int y)
256 (void)x;
257 (void)y;
260 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = {
261 flippixel, nopixel, setpixel, setpixel,
262 nopixel, clearpixel, nopixel, clearpixel
265 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = {
266 flippixel, nopixel, setpixel, setpixel,
267 nopixel, clearimgpixel, nopixel, clearimgpixel
270 LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
272 /* 'mask' and 'bits' contain 2 bits per pixel */
273 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
274 unsigned bits)
276 *address ^= bits & mask;
279 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
280 unsigned bits)
282 unsigned data = *address;
284 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
287 static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask,
288 unsigned bits)
290 unsigned data = *address;
292 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
293 + backdrop_offset)) & mask & ~bits);
296 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
297 unsigned bits)
299 unsigned data = *address;
301 *address = data ^ ((data ^ fg_pattern) & mask & bits);
304 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
305 unsigned bits)
307 unsigned data = *address;
308 unsigned bgp = bg_pattern;
310 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
311 *address = data ^ ((data ^ bits) & mask);
314 static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask,
315 unsigned bits)
317 unsigned data = *address;
318 unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset);
320 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
321 *address = data ^ ((data ^ bits) & mask);
324 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
325 unsigned bits)
327 *address ^= ~bits & mask;
330 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
331 unsigned bits)
333 unsigned data = *address;
335 *address = data ^ ((data ^ bg_pattern) & mask & bits);
338 static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask,
339 unsigned bits)
341 unsigned data = *address;
343 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
344 + backdrop_offset)) & mask & bits);
347 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
348 unsigned bits)
350 unsigned data = *address;
352 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
355 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
356 unsigned bits)
358 unsigned data = *address;
359 unsigned fgp = fg_pattern;
361 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
362 *address = data ^ ((data ^ bits) & mask);
365 static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask,
366 unsigned bits)
368 unsigned data = *address;
369 unsigned fgp = fg_pattern;
371 bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address
372 + backdrop_offset)) & bits);
373 *address = data ^ ((data ^ bits) & mask);
376 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = {
377 flipblock, bgblock, fgblock, solidblock,
378 flipinvblock, bginvblock, fginvblock, solidinvblock
381 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = {
382 flipblock, bgimgblock, fgblock, solidimgblock,
383 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
386 LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
389 void LCDFN(set_backdrop)(FBFN(data) *bd)
391 backdrop = bd;
392 if (bd)
394 backdrop_offset = (long)bd - (long)LCDFN(framebuffer);
395 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop);
396 LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop);
398 else
400 backdrop_offset = 0;
401 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
402 LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
406 FBFN(data)* LCDFN(get_backdrop)(void)
408 return backdrop;
411 static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits)
413 unsigned data = *address;
415 bits ^= data;
416 *address = data ^ (bits & mask);
419 /*** drawing functions ***/
421 /* Clear the whole display */
422 void LCDFN(clear_display)(void)
424 if (default_vp.drawmode & DRMODE_INVERSEVID)
426 memset(LCDFN(framebuffer), patterns[default_vp.fg_pattern & 3],
427 FBSIZE);
429 else
431 if (backdrop)
432 memcpy(LCDFN(framebuffer), backdrop, FBSIZE);
433 else
434 memset(LCDFN(framebuffer), patterns[default_vp.bg_pattern & 3],
435 FBSIZE);
438 LCDFN(scroll_info).lines = 0;
441 /* Clear the current viewport */
442 void LCDFN(clear_viewport)(void)
444 int lastmode;
446 if (current_vp == &default_vp)
448 LCDFN(clear_display)();
450 else
452 lastmode = current_vp->drawmode;
454 /* Invert the INVERSEVID bit and set basic mode to SOLID */
455 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
456 DRMODE_SOLID;
458 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
460 current_vp->drawmode = lastmode;
462 LCDFN(scroll_stop)(current_vp);
466 /* Set a single pixel */
467 void LCDFN(drawpixel)(int x, int y)
469 if ( ((unsigned)x < (unsigned)current_vp->width)
470 && ((unsigned)y < (unsigned)current_vp->height)
471 #if defined(HAVE_VIEWPORT_CLIP)
472 && ((unsigned)x < (unsigned)LCDM(WIDTH))
473 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
474 #endif
476 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
479 /* Draw a line */
480 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
482 int numpixels;
483 int i;
484 int deltax, deltay;
485 int d, dinc1, dinc2;
486 int x, xinc1, xinc2;
487 int y, yinc1, yinc2;
488 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
490 deltax = abs(x2 - x1);
491 if (deltax == 0)
493 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
494 LCDFN(vline)(x1, y1, y2);
495 return;
497 deltay = abs(y2 - y1);
498 if (deltay == 0)
500 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
501 LCDFN(hline)(x1, x2, y1);
502 return;
504 xinc2 = 1;
505 yinc2 = 1;
507 if (deltax >= deltay)
509 numpixels = deltax;
510 d = 2 * deltay - deltax;
511 dinc1 = deltay * 2;
512 dinc2 = (deltay - deltax) * 2;
513 xinc1 = 1;
514 yinc1 = 0;
516 else
518 numpixels = deltay;
519 d = 2 * deltax - deltay;
520 dinc1 = deltax * 2;
521 dinc2 = (deltax - deltay) * 2;
522 xinc1 = 0;
523 yinc1 = 1;
525 numpixels++; /* include endpoints */
527 if (x1 > x2)
529 xinc1 = -xinc1;
530 xinc2 = -xinc2;
533 if (y1 > y2)
535 yinc1 = -yinc1;
536 yinc2 = -yinc2;
539 x = x1;
540 y = y1;
542 for (i = 0; i < numpixels; i++)
544 if ( ((unsigned)x < (unsigned)current_vp->width)
545 && ((unsigned)y < (unsigned)current_vp->height)
546 #if defined(HAVE_VIEWPORT_CLIP)
547 && ((unsigned)x < (unsigned)LCDM(WIDTH))
548 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
549 #endif
551 pfunc(current_vp->x + x, current_vp->y + y);
553 if (d < 0)
555 d += dinc1;
556 x += xinc1;
557 y += yinc1;
559 else
561 d += dinc2;
562 x += xinc2;
563 y += yinc2;
568 /* Draw a horizontal line (optimised) */
569 void LCDFN(hline)(int x1, int x2, int y)
571 int x;
572 int width;
573 FBFN(data) *dst, *dst_end;
574 unsigned mask;
575 LCDFN(blockfunc_type) *bfunc;
577 /* direction flip */
578 if (x2 < x1)
580 x = x1;
581 x1 = x2;
582 x2 = x;
585 /******************** In viewport clipping **********************/
586 /* nothing to draw? */
587 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
588 || (x2 < 0))
589 return;
591 if (x1 < 0)
592 x1 = 0;
593 if (x2 >= current_vp->width)
594 x2 = current_vp->width-1;
596 /* adjust x1 and y to viewport */
597 x1 += current_vp->x;
598 x2 += current_vp->x;
599 y += current_vp->y;
601 #if defined(HAVE_VIEWPORT_CLIP)
602 /********************* Viewport on screen clipping ********************/
603 /* nothing to draw? */
604 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
605 || (x2 < 0))
606 return;
608 /* clipping */
609 if (x1 < 0)
610 x1 = 0;
611 if (x2 >= LCDM(WIDTH))
612 x2 = LCDM(WIDTH)-1;
613 #endif
615 width = x2 - x1 + 1;
617 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
618 dst = LCDFB(x1,y>>3);
619 mask = 0x0101 << (y & 7);
621 dst_end = dst + width;
623 bfunc(dst++, mask, 0xFFFFu);
624 while (dst < dst_end);
627 /* Draw a vertical line (optimised) */
628 void LCDFN(vline)(int x, int y1, int y2)
630 int ny;
631 FBFN(data) *dst;
632 unsigned mask, mask_bottom;
633 LCDFN(blockfunc_type) *bfunc;
635 /* direction flip */
636 if (y2 < y1)
638 ny = y1;
639 y1 = y2;
640 y2 = ny;
643 /******************** In viewport clipping **********************/
644 /* nothing to draw? */
645 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
646 || (y2 < 0))
647 return;
649 if (y1 < 0)
650 y1 = 0;
651 if (y2 >= current_vp->height)
652 y2 = current_vp->height-1;
654 /* adjust for viewport */
655 y1 += current_vp->y;
656 y2 += current_vp->y;
657 x += current_vp->x;
659 #if defined(HAVE_VIEWPORT_CLIP)
660 /********************* Viewport on screen clipping ********************/
661 /* nothing to draw? */
662 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
663 || (y2 < 0))
664 return;
666 /* clipping */
667 if (y1 < 0)
668 y1 = 0;
669 if (y2 >= LCDM(HEIGHT))
670 y2 = LCDM(HEIGHT)-1;
671 #endif
673 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
674 dst = LCDFB(x,y1>>3);
675 ny = y2 - (y1 & ~7);
676 mask = (0xFFu << (y1 & 7)) & 0xFFu;
677 mask |= mask << 8;
678 mask_bottom = 0xFFu >> (~ny & 7);
679 mask_bottom |= mask_bottom << 8;
681 for (; ny >= 8; ny -= 8)
683 bfunc(dst, mask, 0xFFFFu);
684 dst += LCDM(WIDTH);
685 mask = 0xFFFFu;
687 mask &= mask_bottom;
688 bfunc(dst, mask, 0xFFFFu);
691 /* Draw a rectangular box */
692 void LCDFN(drawrect)(int x, int y, int width, int height)
694 if ((width <= 0) || (height <= 0))
695 return;
697 int x2 = x + width - 1;
698 int y2 = y + height - 1;
700 LCDFN(vline)(x, y, y2);
701 LCDFN(vline)(x2, y, y2);
702 LCDFN(hline)(x, x2, y);
703 LCDFN(hline)(x, x2, y2);
706 /* Fill a rectangular area */
707 void LCDFN(fillrect)(int x, int y, int width, int height)
709 int ny;
710 FBFN(data) *dst, *dst_end;
711 unsigned mask, mask_bottom;
712 unsigned bits = 0;
713 LCDFN(blockfunc_type) *bfunc;
714 bool fillopt = false;
716 /******************** In viewport clipping **********************/
717 /* nothing to draw? */
718 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
719 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
720 return;
722 if (x < 0)
724 width += x;
725 x = 0;
727 if (y < 0)
729 height += y;
730 y = 0;
732 if (x + width > current_vp->width)
733 width = current_vp->width - x;
734 if (y + height > current_vp->height)
735 height = current_vp->height - y;
737 /* adjust for viewport */
738 x += current_vp->x;
739 y += current_vp->y;
741 #if defined(HAVE_VIEWPORT_CLIP)
742 /********************* Viewport on screen clipping ********************/
743 /* nothing to draw? */
744 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
745 || (x + width <= 0) || (y + height <= 0))
746 return;
748 /* clip image in viewport in screen */
749 if (x < 0)
751 width += x;
752 x = 0;
754 if (y < 0)
756 height += y;
757 y = 0;
759 if (x + width > LCDM(WIDTH))
760 width = LCDM(WIDTH) - x;
761 if (y + height > LCDM(HEIGHT))
762 height = LCDM(HEIGHT) - y;
763 #endif
766 if (current_vp->drawmode & DRMODE_INVERSEVID)
768 if ((current_vp->drawmode & DRMODE_BG) && !backdrop)
770 fillopt = true;
771 bits = bg_pattern;
774 else
776 if (current_vp->drawmode & DRMODE_FG)
778 fillopt = true;
779 bits = fg_pattern;
782 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
783 dst = LCDFB(x,y>>3);
784 ny = height - 1 + (y & 7);
785 mask = (0xFFu << (y & 7)) & 0xFFu;
786 mask |= mask << 8;
787 mask_bottom = 0xFFu >> (~ny & 7);
788 mask_bottom |= mask_bottom << 8;
790 for (; ny >= 8; ny -= 8)
792 if (fillopt && (mask == 0xFFFFu))
793 memset16(dst, bits, width);
794 else
796 FBFN(data) *dst_row = dst;
798 dst_end = dst_row + width;
800 bfunc(dst_row++, mask, 0xFFFFu);
801 while (dst_row < dst_end);
804 dst += LCDM(WIDTH);
805 mask = 0xFFFFu;
807 mask &= mask_bottom;
809 if (fillopt && (mask == 0xFFFFu))
810 memset16(dst, bits, width);
811 else
813 dst_end = dst + width;
815 bfunc(dst++, mask, 0xFFFFu);
816 while (dst < dst_end);
820 /* About Rockbox' internal monochrome bitmap format:
822 * A bitmap contains one bit for every pixel that defines if that pixel is
823 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
824 * at top.
825 * The bytes are stored in row-major order, with byte 0 being top left,
826 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
827 * 0..7, the second row defines pixel row 8..15 etc.
829 * This is similar to the internal lcd hw format. */
831 /* Draw a partial monochrome bitmap */
832 void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
833 int src_y, int stride, int x, int y,
834 int width, int height)
836 int shift, ny;
837 FBFN(data) *dst, *dst_end;
838 unsigned data, mask, mask_bottom;
839 LCDFN(blockfunc_type) *bfunc;
841 /******************** Image in viewport clipping **********************/
842 /* nothing to draw? */
843 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
844 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
845 return;
847 if (x < 0)
849 width += x;
850 src_x -= x;
851 x = 0;
853 if (y < 0)
855 height += y;
856 src_y -= y;
857 y = 0;
859 if (x + width > current_vp->width)
860 width = current_vp->width - x;
861 if (y + height > current_vp->height)
862 height = current_vp->height - y;
864 /* adjust for viewport */
865 x += current_vp->x;
866 y += current_vp->y;
868 #if defined(HAVE_VIEWPORT_CLIP)
869 /********************* Viewport on screen clipping ********************/
870 /* nothing to draw? */
871 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
872 || (x + width <= 0) || (y + height <= 0))
873 return;
875 /* clip image in viewport in screen */
876 if (x < 0)
878 width += x;
879 src_x -= x;
880 x = 0;
882 if (y < 0)
884 height += y;
885 src_y -= y;
886 y = 0;
888 if (x + width > LCDM(WIDTH))
889 width = LCDM(WIDTH) - x;
890 if (y + height > LCDM(HEIGHT))
891 height = LCDM(HEIGHT) - y;
892 #endif
894 src += stride * (src_y >> 3) + src_x; /* move starting point */
895 src_y &= 7;
896 y -= src_y;
897 dst = LCDFB(x,y>>3);
898 shift = y & 7;
899 ny = height - 1 + shift + src_y;
901 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
902 mask = 0xFFu << (shift + src_y);
903 /* not byte-doubled here because shift+src_y can be > 7 */
904 mask_bottom = 0xFFu >> (~ny & 7);
905 mask_bottom |= mask_bottom << 8;
907 if (shift == 0)
909 mask &= 0xFFu;
910 mask |= mask << 8;
912 for (; ny >= 8; ny -= 8)
914 const unsigned char *src_row = src;
915 FBFN(data) *dst_row = dst;
917 dst_end = dst_row + width;
920 data = *src_row++;
921 bfunc(dst_row++, mask, data | (data << 8));
923 while (dst_row < dst_end);
925 src += stride;
926 dst += LCDM(WIDTH);
927 mask = 0xFFFFu;
929 mask &= mask_bottom;
931 dst_end = dst + width;
934 data = *src++;
935 bfunc(dst++, mask, data | (data << 8));
937 while (dst < dst_end);
939 else
941 unsigned ddata;
943 dst_end = dst + width;
946 const unsigned char *src_col = src++;
947 FBFN(data) *dst_col = dst++;
948 unsigned mask_col = mask & 0xFFu;
950 mask_col |= mask_col << 8;
951 data = 0;
953 for (y = ny; y >= 8; y -= 8)
955 data |= *src_col << shift;
957 if (mask_col)
959 ddata = data & 0xFFu;
960 bfunc(dst_col, mask_col, ddata | (ddata << 8));
961 mask_col = 0xFFFFu;
963 else
965 mask_col = (mask >> 8) & 0xFFu;
966 mask_col |= mask_col << 8;
969 src_col += stride;
970 dst_col += LCDM(WIDTH);
971 data >>= 8;
973 data |= *src_col << shift;
974 mask_col &= mask_bottom;
975 ddata = data & 0xFFu;
976 bfunc(dst_col, mask_col, ddata | (ddata << 8));
978 while (dst < dst_end);
982 /* Draw a full monochrome bitmap */
983 void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width,
984 int height)
986 LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height);
989 /* About Rockbox' internal native bitmap format:
991 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
992 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
993 * are arranged vertically, LSB at top.
994 * The pairs of bytes are stored as shorts, in row-major order, with word 0
995 * being top left, word 1 2nd from left etc. The first row of words defines
996 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
998 * This is the same as the internal lcd hw format. */
1000 /* Draw a partial native bitmap */
1001 void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
1002 int src_y, int stride, int x, int y,
1003 int width, int height)
1005 int shift, ny;
1006 FBFN(data) *dst, *dst_end;
1007 unsigned mask, mask_bottom;
1009 /******************** Image in viewport clipping **********************/
1010 /* nothing to draw? */
1011 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
1012 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
1013 return;
1015 if (x < 0)
1017 width += x;
1018 src_x -= x;
1019 x = 0;
1021 if (y < 0)
1023 height += y;
1024 src_y -= y;
1025 y = 0;
1027 if (x + width > current_vp->width)
1028 width = current_vp->width - x;
1029 if (y + height > current_vp->height)
1030 height = current_vp->height - y;
1032 /* adjust for viewport */
1033 x += current_vp->x;
1034 y += current_vp->y;
1036 #if defined(HAVE_VIEWPORT_CLIP)
1037 /********************* Viewport on screen clipping ********************/
1038 /* nothing to draw? */
1039 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
1040 || (x + width <= 0) || (y + height <= 0))
1041 return;
1043 /* clip image in viewport in screen */
1044 if (x < 0)
1046 width += x;
1047 src_x -= x;
1048 x = 0;
1050 if (y < 0)
1052 height += y;
1053 src_y -= y;
1054 y = 0;
1056 if (x + width > LCDM(WIDTH))
1057 width = LCDM(WIDTH) - x;
1058 if (y + height > LCDM(HEIGHT))
1059 height = LCDM(HEIGHT) - y;
1060 #endif
1062 src += stride * (src_y >> 3) + src_x; /* move starting point */
1063 src_y &= 7;
1064 y -= src_y;
1065 dst = LCDFB(x,y>>3);
1066 shift = y & 7;
1067 ny = height - 1 + shift + src_y;
1069 mask = 0xFFu << (shift + src_y);
1070 /* not byte-doubled here because shift+src_y can be > 7 */
1071 mask_bottom = 0xFFu >> (~ny & 7);
1072 mask_bottom |= mask_bottom << 8;
1074 if (shift == 0)
1076 mask &= 0xFFu;
1077 mask |= mask << 8;
1079 for (; ny >= 8; ny -= 8)
1081 if (mask == 0xFFFFu)
1082 memcpy(dst, src, width * sizeof(FBFN(data)));
1083 else
1085 const FBFN(data) *src_row = src;
1086 FBFN(data) *dst_row = dst;
1088 dst_end = dst_row + width;
1090 setblock(dst_row++, mask, *src_row++);
1091 while (dst_row < dst_end);
1093 src += stride;
1094 dst += LCDM(WIDTH);
1095 mask = 0xFFFFu;
1097 mask &= mask_bottom;
1099 if (mask == 0xFFFFu)
1100 memcpy(dst, src, width * sizeof(FBFN(data)));
1101 else
1103 dst_end = dst + width;
1105 setblock(dst++, mask, *src++);
1106 while (dst < dst_end);
1109 else
1111 unsigned datamask = (0xFFu << shift) & 0xFFu;
1113 datamask |= datamask << 8;
1115 dst_end = dst + width;
1118 const FBFN(data) *src_col = src++;
1119 FBFN(data) *dst_col = dst++;
1120 unsigned mask_col = mask & 0xFFu;
1121 unsigned data, olddata = 0;
1123 mask_col |= mask_col << 8;
1125 for (y = ny; y >= 8; y -= 8)
1127 data = *src_col << shift;
1129 if (mask_col)
1131 setblock(dst_col, mask_col,
1132 olddata ^((olddata ^ data) & datamask));
1133 mask_col = 0xFFFFu;
1135 else
1137 mask_col = (mask >> 8) & 0xFFu;
1138 mask_col |= mask_col << 8;
1140 src_col += stride;
1141 dst_col += LCDM(WIDTH);
1142 olddata = data >> 8;
1144 data = *src_col << shift;
1145 setblock(dst_col, mask_col & mask_bottom,
1146 olddata ^((olddata ^ data) & datamask));
1148 while (dst < dst_end);
1152 /* Draw a full native bitmap */
1153 void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height)
1155 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
1158 #include "lcd-bitmap-common.c"