lcd drivers: Convert lcd_[remote_]framebuffer to a pointer
[maemo-rb.git] / firmware / drivers / lcd-16bit.c
blob71768b674415499c713ecad32e33e9f5bd0bf182
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Dave Chapman
11 * Copyright (C) 2009 by Karl Kurbjun
13 * Rockbox driver for 16-bit colour LCDs
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.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
25 #include "config.h"
27 #include "cpu.h"
28 #include "lcd.h"
29 #include "kernel.h"
30 #include "thread.h"
31 #include <stdlib.h>
32 #include "string-extra.h" /* mem*() */
33 #include "file.h"
34 #include "debug.h"
35 #include "system.h"
36 #include "font.h"
37 #include "rbunicode.h"
38 #include "bidi.h"
39 #include "scroll_engine.h"
41 #define ROW_INC LCD_WIDTH
42 #define COL_INC 1
44 #include "lcd-16bit-common.c"
45 #include "lcd-bitmap-common.c"
47 /*** drawing functions ***/
49 /* Clear the current viewport */
50 void lcd_clear_viewport(void)
52 fb_data *dst, *dst_end;
54 dst = FBADDR(current_vp->x, current_vp->y);
55 dst_end = dst + current_vp->height * LCD_WIDTH;
57 if (current_vp->drawmode & DRMODE_INVERSEVID)
61 memset16(dst, current_vp->fg_pattern, current_vp->width);
62 dst += LCD_WIDTH;
64 while (dst < dst_end);
66 else
68 if (!lcd_backdrop)
72 memset16(dst, current_vp->bg_pattern, current_vp->width);
73 dst += LCD_WIDTH;
75 while (dst < dst_end);
77 else
81 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
82 current_vp->width * sizeof(fb_data));
83 dst += LCD_WIDTH;
85 while (dst < dst_end);
89 if (current_vp == &default_vp)
91 lcd_scroll_info.lines = 0;
93 else
95 lcd_scroll_stop(current_vp);
99 /* Draw a horizontal line (optimised) */
100 void lcd_hline(int x1, int x2, int y)
102 int x, width;
103 unsigned bits = 0;
104 enum fill_opt fillopt = OPT_NONE;
105 fb_data *dst, *dst_end;
107 /* direction flip */
108 if (x2 < x1)
110 x = x1;
111 x1 = x2;
112 x2 = x;
115 /******************** In viewport clipping **********************/
116 /* nothing to draw? */
117 if (((unsigned)y >= (unsigned)current_vp->height) ||
118 (x1 >= current_vp->width) ||
119 (x2 < 0))
120 return;
122 if (x1 < 0)
123 x1 = 0;
124 if (x2 >= current_vp->width)
125 x2 = current_vp->width-1;
127 /* Adjust x1 and y to viewport */
128 x1 += current_vp->x;
129 x2 += current_vp->x;
130 y += current_vp->y;
132 #if defined(HAVE_VIEWPORT_CLIP)
133 /********************* Viewport on screen clipping ********************/
134 /* nothing to draw? */
135 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
136 || (x2 < 0))
137 return;
139 /* clipping */
140 if (x1 < 0)
141 x1 = 0;
142 if (x2 >= LCD_WIDTH)
143 x2 = LCD_WIDTH-1;
144 #endif
146 width = x2 - x1 + 1;
148 /* drawmode and optimisation */
149 if (current_vp->drawmode & DRMODE_INVERSEVID)
151 if (current_vp->drawmode & DRMODE_BG)
153 if (!lcd_backdrop)
155 fillopt = OPT_SET;
156 bits = current_vp->bg_pattern;
158 else
159 fillopt = OPT_COPY;
162 else
164 if (current_vp->drawmode & DRMODE_FG)
166 fillopt = OPT_SET;
167 bits = current_vp->fg_pattern;
170 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
171 return;
173 dst = FBADDR(x1, y);
175 switch (fillopt)
177 case OPT_SET:
178 memset16(dst, bits, width);
179 break;
181 case OPT_COPY:
182 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
183 width * sizeof(fb_data));
184 break;
186 case OPT_NONE: /* DRMODE_COMPLEMENT */
187 dst_end = dst + width;
189 *dst = ~(*dst);
190 while (++dst < dst_end);
191 break;
195 /* Draw a vertical line (optimised) */
196 void lcd_vline(int x, int y1, int y2)
198 int y;
199 fb_data *dst, *dst_end;
200 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
202 /* direction flip */
203 if (y2 < y1)
205 y = y1;
206 y1 = y2;
207 y2 = y;
210 /******************** In viewport clipping **********************/
211 /* nothing to draw? */
212 if (((unsigned)x >= (unsigned)current_vp->width) ||
213 (y1 >= current_vp->height) ||
214 (y2 < 0))
215 return;
217 if (y1 < 0)
218 y1 = 0;
219 if (y2 >= current_vp->height)
220 y2 = current_vp->height-1;
222 /* adjust for viewport */
223 x += current_vp->x;
224 y1 += current_vp->y;
225 y2 += current_vp->y;
227 #if defined(HAVE_VIEWPORT_CLIP)
228 /********************* Viewport on screen clipping ********************/
229 /* nothing to draw? */
230 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
231 || (y2 < 0))
232 return;
234 /* clipping */
235 if (y1 < 0)
236 y1 = 0;
237 if (y2 >= LCD_HEIGHT)
238 y2 = LCD_HEIGHT-1;
239 #endif
241 dst = FBADDR(x , y1);
242 dst_end = dst + (y2 - y1) * LCD_WIDTH;
246 pfunc(dst);
247 dst += LCD_WIDTH;
249 while (dst <= dst_end);
252 /* Fill a rectangular area */
253 void lcd_fillrect(int x, int y, int width, int height)
255 unsigned bits = 0;
256 enum fill_opt fillopt = OPT_NONE;
257 fb_data *dst, *dst_end;
259 /******************** In viewport clipping **********************/
260 /* nothing to draw? */
261 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
262 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
263 return;
265 if (x < 0)
267 width += x;
268 x = 0;
270 if (y < 0)
272 height += y;
273 y = 0;
275 if (x + width > current_vp->width)
276 width = current_vp->width - x;
277 if (y + height > current_vp->height)
278 height = current_vp->height - y;
280 /* adjust for viewport */
281 x += current_vp->x;
282 y += current_vp->y;
284 #if defined(HAVE_VIEWPORT_CLIP)
285 /********************* Viewport on screen clipping ********************/
286 /* nothing to draw? */
287 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
288 || (x + width <= 0) || (y + height <= 0))
289 return;
291 /* clip image in viewport in screen */
292 if (x < 0)
294 width += x;
295 x = 0;
297 if (y < 0)
299 height += y;
300 y = 0;
302 if (x + width > LCD_WIDTH)
303 width = LCD_WIDTH - x;
304 if (y + height > LCD_HEIGHT)
305 height = LCD_HEIGHT - y;
306 #endif
308 /* drawmode and optimisation */
309 if (current_vp->drawmode & DRMODE_INVERSEVID)
311 if (current_vp->drawmode & DRMODE_BG)
313 if (!lcd_backdrop)
315 fillopt = OPT_SET;
316 bits = current_vp->bg_pattern;
318 else
319 fillopt = OPT_COPY;
322 else
324 if (current_vp->drawmode & DRMODE_FG)
326 fillopt = OPT_SET;
327 bits = current_vp->fg_pattern;
330 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
331 return;
333 dst = FBADDR(x, y);
334 dst_end = dst + height * LCD_WIDTH;
338 fb_data *dst_row, *row_end;
340 switch (fillopt)
342 case OPT_SET:
343 memset16(dst, bits, width);
344 break;
346 case OPT_COPY:
347 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
348 width * sizeof(fb_data));
349 break;
351 case OPT_NONE: /* DRMODE_COMPLEMENT */
352 dst_row = dst;
353 row_end = dst_row + width;
355 *dst_row = ~(*dst_row);
356 while (++dst_row < row_end);
357 break;
359 dst += LCD_WIDTH;
361 while (dst < dst_end);
364 /* Draw a partial native bitmap */
365 void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
366 int stride, int x, int y, int width,
367 int height)
369 fb_data *dst;
371 /******************** Image in viewport clipping **********************/
372 /* nothing to draw? */
373 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
374 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
375 return;
377 if (x < 0)
379 width += x;
380 src_x -= x;
381 x = 0;
383 if (y < 0)
385 height += y;
386 src_y -= y;
387 y = 0;
390 if (x + width > current_vp->width)
391 width = current_vp->width - x;
392 if (y + height > current_vp->height)
393 height = current_vp->height - y;
395 /* adjust for viewport */
396 x += current_vp->x;
397 y += current_vp->y;
399 #if defined(HAVE_VIEWPORT_CLIP)
400 /********************* Viewport on screen clipping ********************/
401 /* nothing to draw? */
402 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
403 || (x + width <= 0) || (y + height <= 0))
404 return;
406 /* clip image in viewport in screen */
407 if (x < 0)
409 width += x;
410 src_x -= x;
411 x = 0;
413 if (y < 0)
415 height += y;
416 src_y -= y;
417 y = 0;
419 if (x + width > LCD_WIDTH)
420 width = LCD_WIDTH - x;
421 if (y + height > LCD_HEIGHT)
422 height = LCD_HEIGHT - y;
423 #endif
425 src += stride * src_y + src_x; /* move starting point */
426 dst = FBADDR(x, y);
430 memcpy(dst, src, width * sizeof(fb_data));
431 src += stride;
432 dst += LCD_WIDTH;
434 while (--height > 0);
437 /* Draw a partial native bitmap with transparency and foreground colors */
438 void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
439 int src_y, int stride, int x,
440 int y, int width, int height)
442 fb_data *dst;
443 unsigned fg = current_vp->fg_pattern;
445 /******************** Image in viewport clipping **********************/
446 /* nothing to draw? */
447 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
448 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
449 return;
451 if (x < 0)
453 width += x;
454 src_x -= x;
455 x = 0;
457 if (y < 0)
459 height += y;
460 src_y -= y;
461 y = 0;
464 if (x + width > current_vp->width)
465 width = current_vp->width - x;
466 if (y + height > current_vp->height)
467 height = current_vp->height - y;
469 /* adjust for viewport */
470 x += current_vp->x;
471 y += current_vp->y;
473 #if defined(HAVE_VIEWPORT_CLIP)
474 /********************* Viewport on screen clipping ********************/
475 /* nothing to draw? */
476 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
477 || (x + width <= 0) || (y + height <= 0))
478 return;
480 /* clip image in viewport in screen */
481 if (x < 0)
483 width += x;
484 src_x -= x;
485 x = 0;
487 if (y < 0)
489 height += y;
490 src_y -= y;
491 y = 0;
493 if (x + width > LCD_WIDTH)
494 width = LCD_WIDTH - x;
495 if (y + height > LCD_HEIGHT)
496 height = LCD_HEIGHT - y;
497 #endif
499 src += stride * src_y + src_x; /* move starting point */
500 dst = FBADDR(x, y);
502 #ifdef CPU_ARM
504 int w, px;
505 asm volatile (
506 ".rowstart: \n"
507 "mov %[w], %[width] \n" /* Load width for inner loop */
508 ".nextpixel: \n"
509 "ldrh %[px], [%[s]], #2 \n" /* Load src pixel */
510 "add %[d], %[d], #2 \n" /* Uncoditionally increment dst */
511 /* done here for better pipelining */
512 "cmp %[px], %[fgcolor] \n" /* Compare to foreground color */
513 "streqh %[fgpat], [%[d], #-2] \n" /* Store foregroud if match */
514 "cmpne %[px], %[transcolor] \n" /* Compare to transparent color */
515 "strneh %[px], [%[d], #-2] \n" /* Store dst if not transparent */
516 "subs %[w], %[w], #1 \n" /* Width counter has run down? */
517 "bgt .nextpixel \n" /* More in this row? */
518 "add %[s], %[s], %[sstp], lsl #1 \n" /* Skip over to start of next line */
519 "add %[d], %[d], %[dstp], lsl #1 \n"
520 "subs %[h], %[h], #1 \n" /* Height counter has run down? */
521 "bgt .rowstart \n" /* More rows? */
522 : [w]"=&r"(w), [h]"+&r"(height), [px]"=&r"(px),
523 [s]"+&r"(src), [d]"+&r"(dst)
524 : [width]"r"(width),
525 [sstp]"r"(stride - width),
526 [dstp]"r"(LCD_WIDTH - width),
527 [transcolor]"r"(TRANSPARENT_COLOR),
528 [fgcolor]"r"(REPLACEWITHFG_COLOR),
529 [fgpat]"r"(fg)
532 #else /* optimized C version */
535 const fb_data *src_row = src;
536 fb_data *dst_row = dst;
537 fb_data *row_end = dst_row + width;
540 unsigned data = *src_row++;
541 if (data != TRANSPARENT_COLOR)
543 if (data == REPLACEWITHFG_COLOR)
544 data = fg;
545 *dst_row = data;
548 while (++dst_row < row_end);
549 src += stride;
550 dst += LCD_WIDTH;
552 while (--height > 0);
553 #endif