diff options
author | Jens Arnold <amiconn@rockbox.org> | 2006-02-16 20:03:07 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2006-02-16 20:03:07 +0000 |
commit | 41e1aa888b9d1fc41aaf158191980cce3e548302 (patch) | |
tree | 2f04f7e5a6f93559defdf037b6b918eb44112ac3 /firmware/drivers | |
parent | 7c64631792f5bb3bd804ff5880808d275be89a4d (diff) | |
download | rockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.tar.gz rockbox-41e1aa888b9d1fc41aaf158191980cce3e548302.zip |
Grayscale iPods: Fixed & optimised LCD driver. Further optimisation is possible. * LCD driver now uses proper native bitmaps resembling the LCD internal format. Mono bitmaps are still transposed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8706 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/lcd-2bit-horz.c | 261 |
1 files changed, 188 insertions, 73 deletions
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c index 1045ba654b..f9f5152faa 100644 --- a/firmware/drivers/lcd-2bit-horz.c +++ b/firmware/drivers/lcd-2bit-horz.c | |||
@@ -45,6 +45,10 @@ static const unsigned char dibits[16] ICONST_ATTR = { | |||
45 | 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF | 45 | 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static const unsigned char pixmask[4] ICONST_ATTR = { | ||
49 | 0x03, 0x0C, 0x30, 0xC0 | ||
50 | }; | ||
51 | |||
48 | static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ | 52 | static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ |
49 | static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ | 53 | static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ |
50 | static int drawmode = DRMODE_SOLID; | 54 | static int drawmode = DRMODE_SOLID; |
@@ -70,8 +74,6 @@ static const char scroll_tick_table[16] = { | |||
70 | }; | 74 | }; |
71 | 75 | ||
72 | 76 | ||
73 | static unsigned char notmask[4] = { 0xfc, 0xf3, 0xcf, 0x3f }; | ||
74 | |||
75 | /* LCD init */ | 77 | /* LCD init */ |
76 | void lcd_init(void) | 78 | void lcd_init(void) |
77 | { | 79 | { |
@@ -154,29 +156,23 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h) | |||
154 | 156 | ||
155 | /*** low-level drawing functions ***/ | 157 | /*** low-level drawing functions ***/ |
156 | 158 | ||
157 | static void setpixel_value(int x, int y, unsigned val) | ||
158 | { | ||
159 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | ||
160 | |||
161 | *data = (*data & notmask[x&3]) | (val << ((x&3)<<1)); | ||
162 | } | ||
163 | |||
164 | static void setpixel(int x, int y) | 159 | static void setpixel(int x, int y) |
165 | { | 160 | { |
166 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | 161 | unsigned char *data = &lcd_framebuffer[y][x>>2]; |
167 | 162 | unsigned mask = pixmask[x & 3]; | |
168 | *data = (*data & notmask[x&3]) | (fg_pattern << ((x&3)<<1)); | 163 | *data = (*data & ~mask) | (fg_pattern & mask); |
169 | } | 164 | } |
170 | 165 | ||
171 | static void clearpixel(int x, int y) | 166 | static void clearpixel(int x, int y) |
172 | { | 167 | { |
173 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | 168 | unsigned char *data = &lcd_framebuffer[y][x>>2]; |
174 | *data = (*data & notmask[x&3]) | (bg_pattern << ((x&3)<<1)); | 169 | unsigned mask = pixmask[x & 3]; |
170 | *data = (*data & ~mask) | (bg_pattern & mask); | ||
175 | } | 171 | } |
176 | 172 | ||
177 | static void flippixel(int x, int y) | 173 | static void flippixel(int x, int y) |
178 | { | 174 | { |
179 | lcd_framebuffer[y][x>>2] ^= 3 << (2 * (x & 3)); | 175 | lcd_framebuffer[y][x>>2] ^= pixmask[x & 3]; |
180 | } | 176 | } |
181 | 177 | ||
182 | static void nopixel(int x, int y) | 178 | static void nopixel(int x, int y) |
@@ -190,6 +186,78 @@ lcd_pixelfunc_type* const lcd_pixelfuncs[8] = { | |||
190 | nopixel, clearpixel, nopixel, clearpixel | 186 | nopixel, clearpixel, nopixel, clearpixel |
191 | }; | 187 | }; |
192 | 188 | ||
189 | /* 'mask' and 'bits' contain 2 bits per pixel */ | ||
190 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | ||
191 | ICODE_ATTR; | ||
192 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | ||
193 | { | ||
194 | *address ^= bits & mask; | ||
195 | } | ||
196 | |||
197 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
198 | ICODE_ATTR; | ||
199 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
200 | { | ||
201 | mask &= ~bits; | ||
202 | *address = (*address & ~mask) | (bg_pattern & mask); | ||
203 | } | ||
204 | |||
205 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
206 | ICODE_ATTR; | ||
207 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
208 | { | ||
209 | mask &= bits; | ||
210 | *address = (*address & ~mask) | (fg_pattern & mask); | ||
211 | } | ||
212 | |||
213 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | ||
214 | ICODE_ATTR; | ||
215 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | ||
216 | { | ||
217 | *address = (*address & ~mask) | (bits & mask & fg_pattern) | ||
218 | | (~bits & mask & bg_pattern); | ||
219 | } | ||
220 | |||
221 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
222 | ICODE_ATTR; | ||
223 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
224 | { | ||
225 | *address ^= ~bits & mask; | ||
226 | } | ||
227 | |||
228 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
229 | ICODE_ATTR; | ||
230 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
231 | { | ||
232 | mask &= bits; | ||
233 | *address = (*address & ~mask) | (bg_pattern & mask); | ||
234 | } | ||
235 | |||
236 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
237 | ICODE_ATTR; | ||
238 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
239 | { | ||
240 | mask &= ~bits; | ||
241 | *address = (*address & ~mask) | (fg_pattern & mask); | ||
242 | } | ||
243 | |||
244 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
245 | ICODE_ATTR; | ||
246 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
247 | { | ||
248 | *address = (*address & ~mask) | (~bits & mask & fg_pattern) | ||
249 | | (bits & mask & bg_pattern); | ||
250 | } | ||
251 | |||
252 | lcd_blockfunc_type* const lcd_blockfuncs[8] = { | ||
253 | flipblock, bgblock, fgblock, solidblock, | ||
254 | flipinvblock, bginvblock, fginvblock, solidinvblock | ||
255 | }; | ||
256 | |||
257 | static inline void setblock(unsigned char *address, unsigned mask, unsigned bits) | ||
258 | { | ||
259 | *address = (*address & ~mask) | (bits & mask); | ||
260 | } | ||
193 | 261 | ||
194 | /*** drawing functions ***/ | 262 | /*** drawing functions ***/ |
195 | 263 | ||
@@ -283,16 +351,17 @@ void lcd_drawline(int x1, int y1, int x2, int y2) | |||
283 | /* Draw a horizontal line (optimised) */ | 351 | /* Draw a horizontal line (optimised) */ |
284 | void lcd_hline(int x1, int x2, int y) | 352 | void lcd_hline(int x1, int x2, int y) |
285 | { | 353 | { |
286 | int x; | 354 | int nx; |
287 | 355 | unsigned char *dst; | |
288 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | 356 | unsigned mask, mask_right; |
357 | lcd_blockfunc_type *bfunc; | ||
289 | 358 | ||
290 | /* direction flip */ | 359 | /* direction flip */ |
291 | if (x2 < x1) | 360 | if (x2 < x1) |
292 | { | 361 | { |
293 | x = x1; | 362 | nx = x1; |
294 | x1 = x2; | 363 | x1 = x2; |
295 | x2 = x; | 364 | x2 = nx; |
296 | } | 365 | } |
297 | 366 | ||
298 | /* nothing to draw? */ | 367 | /* nothing to draw? */ |
@@ -305,25 +374,35 @@ void lcd_hline(int x1, int x2, int y) | |||
305 | if (x2 >= LCD_WIDTH) | 374 | if (x2 >= LCD_WIDTH) |
306 | x2 = LCD_WIDTH-1; | 375 | x2 = LCD_WIDTH-1; |
307 | 376 | ||
308 | while(x1 <= x2) { | 377 | bfunc = lcd_blockfuncs[drawmode]; |
309 | pfunc(x1,y); | 378 | dst = &lcd_framebuffer[y][x1>>2]; |
310 | ++x1; | 379 | nx = x2 - (x1 & ~3); |
380 | mask = 0xFFu << (2 * (x1 & 3)); | ||
381 | mask_right = 0xFFu >> (2 * (~nx & 3)); | ||
382 | |||
383 | for (; nx >= 4; nx -= 4) | ||
384 | { | ||
385 | bfunc(dst++, mask, 0xFFu); | ||
386 | mask = 0xFFu; | ||
311 | } | 387 | } |
388 | mask &= mask_right; | ||
389 | bfunc(dst, mask, 0xFFu); | ||
312 | } | 390 | } |
313 | 391 | ||
314 | /* Draw a vertical line (optimised) */ | 392 | /* Draw a vertical line (optimised) */ |
315 | void lcd_vline(int x, int y1, int y2) | 393 | void lcd_vline(int x, int y1, int y2) |
316 | { | 394 | { |
317 | int ny; | 395 | int y; |
318 | 396 | unsigned char *dst, *dst_end; | |
319 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | 397 | unsigned mask; |
398 | lcd_blockfunc_type *bfunc; | ||
320 | 399 | ||
321 | /* direction flip */ | 400 | /* direction flip */ |
322 | if (y2 < y1) | 401 | if (y2 < y1) |
323 | { | 402 | { |
324 | ny = y1; | 403 | y = y1; |
325 | y1 = y2; | 404 | y1 = y2; |
326 | y2 = ny; | 405 | y2 = y; |
327 | } | 406 | } |
328 | 407 | ||
329 | /* nothing to draw? */ | 408 | /* nothing to draw? */ |
@@ -336,10 +415,17 @@ void lcd_vline(int x, int y1, int y2) | |||
336 | if (y2 >= LCD_HEIGHT) | 415 | if (y2 >= LCD_HEIGHT) |
337 | y2 = LCD_HEIGHT-1; | 416 | y2 = LCD_HEIGHT-1; |
338 | 417 | ||
339 | 418 | bfunc = lcd_blockfuncs[drawmode]; | |
340 | while(y1++ <= y2) { | 419 | dst = &lcd_framebuffer[y1][x>>2]; |
341 | pfunc(x, y1); | 420 | mask = pixmask[x & 3]; |
421 | |||
422 | dst_end = dst + (y2 - y1) * (LCD_WIDTH/4); | ||
423 | do | ||
424 | { | ||
425 | bfunc(dst, mask, 0xFFu); | ||
426 | dst += (LCD_WIDTH/4); | ||
342 | } | 427 | } |
428 | while (dst <= dst_end); | ||
343 | } | 429 | } |
344 | 430 | ||
345 | /* Draw a rectangular box */ | 431 | /* Draw a rectangular box */ |
@@ -360,8 +446,10 @@ void lcd_drawrect(int x, int y, int width, int height) | |||
360 | /* Fill a rectangular area */ | 446 | /* Fill a rectangular area */ |
361 | void lcd_fillrect(int x, int y, int width, int height) | 447 | void lcd_fillrect(int x, int y, int width, int height) |
362 | { | 448 | { |
363 | int ny; | 449 | int nx; |
364 | 450 | unsigned char *dst, *dst_end; | |
451 | unsigned mask, mask_right; | ||
452 | lcd_blockfunc_type *bfunc; | ||
365 | 453 | ||
366 | /* nothing to draw? */ | 454 | /* nothing to draw? */ |
367 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | 455 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) |
@@ -384,12 +472,36 @@ void lcd_fillrect(int x, int y, int width, int height) | |||
384 | if (y + height > LCD_HEIGHT) | 472 | if (y + height > LCD_HEIGHT) |
385 | height = LCD_HEIGHT - y; | 473 | height = LCD_HEIGHT - y; |
386 | 474 | ||
387 | ny = y; | 475 | bfunc = lcd_blockfuncs[drawmode]; |
388 | while (ny <= height) | 476 | dst = &lcd_framebuffer[y][x>>2]; |
477 | nx = width - 1 + (x & 3); | ||
478 | mask = 0xFFu << (2 * (x & 3)); | ||
479 | mask_right = 0xFFu >> (2 * (~nx & 3)); | ||
480 | |||
481 | for (; nx >= 4; nx -= 4) | ||
482 | { | ||
483 | unsigned char *dst_col = dst; | ||
484 | |||
485 | dst_end = dst_col + height * (LCD_WIDTH/4); | ||
486 | do | ||
487 | { | ||
488 | bfunc(dst_col, mask, 0xFFu); | ||
489 | dst_col += (LCD_WIDTH/4); | ||
490 | } | ||
491 | while (dst_col < dst_end); | ||
492 | |||
493 | dst++; | ||
494 | mask = 0xFFu; | ||
495 | } | ||
496 | mask &= mask_right; | ||
497 | |||
498 | dst_end = dst + height * (LCD_WIDTH/4); | ||
499 | do | ||
389 | { | 500 | { |
390 | lcd_hline (x, width, ny); | 501 | bfunc(dst, mask, 0xFFu); |
391 | ny++; | 502 | dst += (LCD_WIDTH/4); |
392 | } | 503 | } |
504 | while (dst < dst_end); | ||
393 | } | 505 | } |
394 | 506 | ||
395 | /* About Rockbox' internal monochrome bitmap format: | 507 | /* About Rockbox' internal monochrome bitmap format: |
@@ -485,11 +597,10 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig | |||
485 | /* About Rockbox' internal native bitmap format: | 597 | /* About Rockbox' internal native bitmap format: |
486 | * | 598 | * |
487 | * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey, | 599 | * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey, |
488 | * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB | 600 | * 10 = dark grey, 11 = black. Bits within a byte are arranged horizontally, |
489 | * at top. | 601 | * LSB at the left. |
490 | * The bytes are stored in row-major order, with byte 0 being top left, | 602 | * The bytes are stored in row-major order, with byte 0 being top left, |
491 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | 603 | * byte 1 2nd from left etc. Each row of bytes defines one pixel row. |
492 | * 0..3, the second row defines pixel row 4..7 etc. | ||
493 | * | 604 | * |
494 | * This is the same as the internal lcd hw format. */ | 605 | * This is the same as the internal lcd hw format. */ |
495 | 606 | ||
@@ -500,8 +611,9 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | |||
500 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | 611 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, |
501 | int stride, int x, int y, int width, int height) | 612 | int stride, int x, int y, int width, int height) |
502 | { | 613 | { |
503 | int ny, nx, ymax; | 614 | int shift, nx; |
504 | const unsigned char * src_end; | 615 | unsigned char *dst, *dst_end; |
616 | unsigned mask, mask_right; | ||
505 | 617 | ||
506 | /* nothing to draw? */ | 618 | /* nothing to draw? */ |
507 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | 619 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) |
@@ -526,46 +638,49 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | |||
526 | if (y + height > LCD_HEIGHT) | 638 | if (y + height > LCD_HEIGHT) |
527 | height = LCD_HEIGHT - y; | 639 | height = LCD_HEIGHT - y; |
528 | 640 | ||
529 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | 641 | stride = (stride + 3) >> 2; /* convert to no. of bytes */ |
530 | src_y &= 7; | 642 | |
531 | src_end = src + width; | 643 | src += stride * src_y + (src_x >> 2); /* move starting point */ |
644 | src_x &= 3; | ||
645 | x -= src_x; | ||
646 | dst = &lcd_framebuffer[y][x>>2]; | ||
647 | shift = x & 3; | ||
648 | nx = width - 1 + shift + src_x; | ||
649 | |||
650 | mask = 0xFFu << (2 * (shift + src_x)); | ||
651 | mask_right = 0xFFu >> (2 * (~nx & 3)); | ||
532 | 652 | ||
533 | nx = x; | 653 | shift *= 2; |
654 | dst_end = dst + height * (LCD_WIDTH/4); | ||
534 | do | 655 | do |
535 | { | 656 | { |
536 | const unsigned char *src_col = src++; | 657 | const unsigned char *src_row = src; |
537 | unsigned data = *src_col >> src_y; | 658 | unsigned char *dst_row = dst; |
538 | int numbits = 8 - src_y; | 659 | unsigned mask_row = mask; |
660 | unsigned data = 0; | ||
539 | 661 | ||
540 | ymax = y + height; | 662 | for (x = nx; x >= 4; x -= 4) |
541 | ny = y; | ||
542 | do | ||
543 | { | 663 | { |
544 | if (data & 0x03) | 664 | data |= *src_row++ << shift; |
545 | setpixel_value (nx,ny, 0xFF); | 665 | |
546 | else | 666 | if (mask_row & 0xFF) |
547 | if (data & 0x01) | ||
548 | setpixel_value (nx,ny, 0x3F); | ||
549 | else | ||
550 | if (data & 0x02) | ||
551 | setpixel_value (nx,ny, 0xCF); | ||
552 | else | ||
553 | setpixel_value (nx,ny, 0x00); | ||
554 | |||
555 | ny++; | ||
556 | |||
557 | data >>= 2; | ||
558 | if (--numbits == 0) | ||
559 | { | 667 | { |
560 | src_col += stride; | 668 | setblock(dst_row, mask_row, data); |
561 | data = *src_col; | 669 | mask_row = 0xFF; |
562 | numbits = 4; | ||
563 | } | 670 | } |
671 | else | ||
672 | mask_row >>= 8; | ||
673 | |||
674 | dst_row++; | ||
675 | data >>= 8; | ||
564 | } | 676 | } |
565 | while (ny < ymax); | 677 | data |= *src_row << shift; |
566 | nx++; | 678 | setblock(dst_row, mask_row & mask_right, data); |
679 | |||
680 | src += stride; | ||
681 | dst += (LCD_WIDTH/4); | ||
567 | } | 682 | } |
568 | while (src < src_end); | 683 | while (dst < dst_end); |
569 | } | 684 | } |
570 | 685 | ||
571 | /* Draw a full native bitmap */ | 686 | /* Draw a full native bitmap */ |