Greyscale library: Plugins can now put the management structure in IRAM for higher...
[Rockbox.git] / apps / plugins / lib / gray_draw.c
blob4d75af5c9b1a733502e7546583ec4752e0db4417
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Greyscale framework
11 * Drawing functions
13 * This is a generic framework to display up to 33 shades of grey
14 * on low-depth bitmap LCDs (Archos b&w, Iriver 4-grey, iPod 4-grey)
15 * within plugins.
17 * Copyright (C) 2004-2006 Jens Arnold
19 * All files in this archive are subject to the GNU General Public License.
20 * See the file COPYING in the source tree root for full license agreement.
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
25 ****************************************************************************/
27 #include "plugin.h"
29 #ifdef HAVE_LCD_BITMAP
30 #include "gray.h"
32 /*** low-level drawing functions ***/
34 static void setpixel(unsigned char *address)
36 *address = _gray_info.fg_index;
39 static void clearpixel(unsigned char *address)
41 *address = _gray_info.bg_index;
44 static void flippixel(unsigned char *address)
46 *address = _gray_info.depth - *address;
49 static void nopixel(unsigned char *address)
51 (void)address;
54 void (* const _gray_pixelfuncs[8])(unsigned char *address) = {
55 flippixel, nopixel, setpixel, setpixel,
56 nopixel, clearpixel, nopixel, clearpixel
59 /*** Drawing functions ***/
61 /* Clear the whole display */
62 void gray_clear_display(void)
64 int brightness = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
65 _gray_info.fg_index : _gray_info.bg_index;
67 _gray_rb->memset(_gray_info.cur_buffer, brightness,
68 _GRAY_MULUQ(_gray_info.width, _gray_info.height));
71 /* Set a single pixel */
72 void gray_drawpixel(int x, int y)
74 if (((unsigned)x < (unsigned)_gray_info.width)
75 && ((unsigned)y < (unsigned)_gray_info.height))
76 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
77 _gray_pixelfuncs[_gray_info.drawmode](&_gray_info.cur_buffer[_GRAY_MULUQ(y,
78 _gray_info.width) + x]);
79 #else
80 _gray_pixelfuncs[_gray_info.drawmode](&_gray_info.cur_buffer[_GRAY_MULUQ(x,
81 _gray_info.height) + y]);
82 #endif
85 /* Draw a line */
86 void gray_drawline(int x1, int y1, int x2, int y2)
88 int numpixels;
89 int i;
90 int deltax, deltay;
91 int d, dinc1, dinc2;
92 int x, xinc1, xinc2;
93 int y, yinc1, yinc2;
94 void (*pfunc)(unsigned char *address) = _gray_pixelfuncs[_gray_info.drawmode];
96 deltax = abs(x2 - x1);
97 deltay = abs(y2 - y1);
98 xinc2 = 1;
99 yinc2 = 1;
101 if (deltax >= deltay)
103 numpixels = deltax;
104 d = 2 * deltay - deltax;
105 dinc1 = deltay * 2;
106 dinc2 = (deltay - deltax) * 2;
107 xinc1 = 1;
108 yinc1 = 0;
110 else
112 numpixels = deltay;
113 d = 2 * deltax - deltay;
114 dinc1 = deltax * 2;
115 dinc2 = (deltax - deltay) * 2;
116 xinc1 = 0;
117 yinc1 = 1;
119 numpixels++; /* include endpoints */
121 if (x1 > x2)
123 xinc1 = -xinc1;
124 xinc2 = -xinc2;
127 if (y1 > y2)
129 yinc1 = -yinc1;
130 yinc2 = -yinc2;
133 x = x1;
134 y = y1;
136 for (i = 0; i < numpixels; i++)
138 if (((unsigned)x < (unsigned)_gray_info.width)
139 && ((unsigned)y < (unsigned)_gray_info.height))
140 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
141 pfunc(&_gray_info.cur_buffer[_GRAY_MULUQ(y, _gray_info.width) + x]);
142 #else
143 pfunc(&_gray_info.cur_buffer[_GRAY_MULUQ(x, _gray_info.height) + y]);
144 #endif
146 if (d < 0)
148 d += dinc1;
149 x += xinc1;
150 y += yinc1;
152 else
154 d += dinc2;
155 x += xinc2;
156 y += yinc2;
161 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
163 /* Draw a horizontal line (optimised) */
164 void gray_hline(int x1, int x2, int y)
166 int x;
167 int bits = 0;
168 unsigned char *dst;
169 bool fillopt = false;
170 void (*pfunc)(unsigned char *address);
172 /* direction flip */
173 if (x2 < x1)
175 x = x1;
176 x1 = x2;
177 x2 = x;
180 /* nothing to draw? */
181 if (((unsigned)y >= (unsigned)_gray_info.height)
182 || (x1 >= _gray_info.width) || (x2 < 0))
183 return;
185 /* clipping */
186 if (x1 < 0)
187 x1 = 0;
188 if (x2 >= _gray_info.width)
189 x2 = _gray_info.width - 1;
191 if (_gray_info.drawmode & DRMODE_INVERSEVID)
193 if (_gray_info.drawmode & DRMODE_BG)
195 fillopt = true;
196 bits = _gray_info.bg_index;
199 else
201 if (_gray_info.drawmode & DRMODE_FG)
203 fillopt = true;
204 bits = _gray_info.fg_index;
207 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
208 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(y, _gray_info.width) + x1];
210 if (fillopt)
211 _gray_rb->memset(dst, bits, x2 - x1 + 1);
212 else
214 unsigned char *dst_end = dst + x2 - x1;
216 pfunc(dst++);
217 while (dst <= dst_end);
221 /* Draw a vertical line (optimised) */
222 void gray_vline(int x, int y1, int y2)
224 int y;
225 unsigned char *dst, *dst_end;
226 void (*pfunc)(unsigned char *address);
228 /* direction flip */
229 if (y2 < y1)
231 y = y1;
232 y1 = y2;
233 y2 = y;
236 /* nothing to draw? */
237 if (((unsigned)x >= (unsigned)_gray_info.width)
238 || (y1 >= _gray_info.height) || (y2 < 0))
239 return;
241 /* clipping */
242 if (y1 < 0)
243 y1 = 0;
244 if (y2 >= _gray_info.height)
245 y2 = _gray_info.height - 1;
247 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
248 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(y1, _gray_info.width) + x];
250 dst_end = dst + _GRAY_MULUQ(y2 - y1, _gray_info.width);
253 pfunc(dst);
254 dst += _gray_info.width;
256 while (dst <= dst_end);
259 /* Draw a filled triangle */
260 void gray_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3)
262 int x, y;
263 long fp_x1, fp_x2, fp_dx1, fp_dx2;
265 /* sort vertices by increasing y value */
266 if (y1 > y3)
268 if (y2 < y3) /* y2 < y3 < y1 */
270 x = x1; x1 = x2; x2 = x3; x3 = x;
271 y = y1; y1 = y2; y2 = y3; y3 = y;
273 else if (y2 > y1) /* y3 < y1 < y2 */
275 x = x1; x1 = x3; x3 = x2; x2 = x;
276 y = y1; y1 = y3; y3 = y2; y2 = y;
278 else /* y3 <= y2 <= y1 */
280 x = x1; x1 = x3; x3 = x;
281 y = y1; y1 = y3; y3 = y;
284 else
286 if (y2 < y1) /* y2 < y1 <= y3 */
288 x = x1; x1 = x2; x2 = x;
289 y = y1; y1 = y2; y2 = y;
291 else if (y2 > y3) /* y1 <= y3 < y2 */
293 x = x2; x2 = x3; x3 = x;
294 y = y2; y2 = y3; y3 = y;
296 /* else already sorted */
299 if (y1 < y3) /* draw */
301 fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
302 fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
304 if (y1 < y2) /* first part */
306 fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
307 fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
308 for (y = y1; y < y2; y++)
310 gray_hline(fp_x1 >> 16, fp_x2 >> 16, y);
311 fp_x1 += fp_dx1;
312 fp_x2 += fp_dx2;
315 if (y2 < y3) /* second part */
317 fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
318 fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
319 for (y = y2; y < y3; y++)
321 gray_hline(fp_x1 >> 16, fp_x2 >> 16, y);
322 fp_x1 += fp_dx1;
323 fp_x2 += fp_dx2;
328 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
330 /* Draw a horizontal line (optimised) */
331 void gray_hline(int x1, int x2, int y)
333 int x;
334 unsigned char *dst, *dst_end;
335 void (*pfunc)(unsigned char *address);
337 /* direction flip */
338 if (x2 < x1)
340 x = x1;
341 x1 = x2;
342 x2 = x;
345 /* nothing to draw? */
346 if (((unsigned)y >= (unsigned)_gray_info.height)
347 || (x1 >= _gray_info.width) || (x2 < 0))
348 return;
350 /* clipping */
351 if (x1 < 0)
352 x1 = 0;
353 if (x2 >= _gray_info.width)
354 x2 = _gray_info.width - 1;
356 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
357 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(x1, _gray_info.height) + y];
359 dst_end = dst + _GRAY_MULUQ(x2 - x1, _gray_info.height);
362 pfunc(dst);
363 dst += _gray_info.height;
365 while (dst <= dst_end);
368 /* Draw a vertical line (optimised) */
369 void gray_vline(int x, int y1, int y2)
371 int y;
372 int bits = 0;
373 unsigned char *dst;
374 bool fillopt = false;
375 void (*pfunc)(unsigned char *address);
377 /* direction flip */
378 if (y2 < y1)
380 y = y1;
381 y1 = y2;
382 y2 = y;
385 /* nothing to draw? */
386 if (((unsigned)x >= (unsigned)_gray_info.width)
387 || (y1 >= _gray_info.height) || (y2 < 0))
388 return;
390 /* clipping */
391 if (y1 < 0)
392 y1 = 0;
393 if (y2 >= _gray_info.height)
394 y2 = _gray_info.height - 1;
396 if (_gray_info.drawmode & DRMODE_INVERSEVID)
398 if (_gray_info.drawmode & DRMODE_BG)
400 fillopt = true;
401 bits = _gray_info.bg_index;
404 else
406 if (_gray_info.drawmode & DRMODE_FG)
408 fillopt = true;
409 bits = _gray_info.fg_index;
412 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
413 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(x, _gray_info.height) + y1];
415 if (fillopt)
416 _gray_rb->memset(dst, bits, y2 - y1 + 1);
417 else
419 unsigned char *dst_end = dst + y2 - y1;
421 pfunc(dst++);
422 while (dst <= dst_end);
426 /* Draw a filled triangle */
427 void gray_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3)
429 int x, y;
430 long fp_y1, fp_y2, fp_dy1, fp_dy2;
432 /* sort vertices by increasing x value */
433 if (x1 > x3)
435 if (x2 < x3) /* x2 < x3 < x1 */
437 x = x1; x1 = x2; x2 = x3; x3 = x;
438 y = y1; y1 = y2; y2 = y3; y3 = y;
440 else if (x2 > x1) /* x3 < x1 < x2 */
442 x = x1; x1 = x3; x3 = x2; x2 = x;
443 y = y1; y1 = y3; y3 = y2; y2 = y;
445 else /* x3 <= x2 <= x1 */
447 x = x1; x1 = x3; x3 = x;
448 y = y1; y1 = y3; y3 = y;
451 else
453 if (x2 < x1) /* x2 < x1 <= x3 */
455 x = x1; x1 = x2; x2 = x;
456 y = y1; y1 = y2; y2 = y;
458 else if (x2 > x3) /* x1 <= x3 < x2 */
460 x = x2; x2 = x3; x3 = x;
461 y = y2; y2 = y3; y3 = y;
463 /* else already sorted */
466 if (x1 < x3) /* draw */
468 fp_dy1 = ((y3 - y1) << 16) / (x3 - x1);
469 fp_y1 = (y1 << 16) + (1<<15) + (fp_dy1 >> 1);
471 if (x1 < x2) /* first part */
473 fp_dy2 = ((y2 - y1) << 16) / (x2 - x1);
474 fp_y2 = (y1 << 16) + (1<<15) + (fp_dy2 >> 1);
475 for (x = x1; x < x2; x++)
477 gray_vline(x, fp_y1 >> 16, fp_y2 >> 16);
478 fp_y1 += fp_dy1;
479 fp_y2 += fp_dy2;
482 if (x2 < x3) /* second part */
484 fp_dy2 = ((y3 - y2) << 16) / (x3 - x2);
485 fp_y2 = (y2 << 16) + (1<<15) + (fp_dy2 >> 1);
486 for (x = x2; x < x3; x++)
488 gray_vline(x, fp_y1 >> 16, fp_y2 >> 16);
489 fp_y1 += fp_dy1;
490 fp_y2 += fp_dy2;
495 #endif /* LCD_PIXELFORMAT */
497 /* Draw a rectangular box */
498 void gray_drawrect(int x, int y, int width, int height)
500 if ((width <= 0) || (height <= 0))
501 return;
503 int x2 = x + width - 1;
504 int y2 = y + height - 1;
506 gray_vline(x, y, y2);
507 gray_vline(x2, y, y2);
508 gray_hline(x, x2, y);
509 gray_hline(x, x2, y2);
512 /* Fill a rectangular area */
513 void gray_fillrect(int x, int y, int width, int height)
515 int bits = 0;
516 unsigned char *dst, *dst_end;
517 bool fillopt = false;
518 void (*pfunc)(unsigned char *address);
520 /* nothing to draw? */
521 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
522 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
523 return;
525 /* clipping */
526 if (x < 0)
528 width += x;
529 x = 0;
531 if (y < 0)
533 height += y;
534 y = 0;
536 if (x + width > _gray_info.width)
537 width = _gray_info.width - x;
538 if (y + height > _gray_info.height)
539 height = _gray_info.height - y;
541 if (_gray_info.drawmode & DRMODE_INVERSEVID)
543 if (_gray_info.drawmode & DRMODE_BG)
545 fillopt = true;
546 bits = _gray_info.bg_index;
549 else
551 if (_gray_info.drawmode & DRMODE_FG)
553 fillopt = true;
554 bits = _gray_info.fg_index;
557 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
558 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
559 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(y, _gray_info.width) + x];
560 dst_end = dst + _GRAY_MULUQ(height, _gray_info.width);
564 if (fillopt)
565 _gray_rb->memset(dst, bits, width);
566 else
568 unsigned char *dst_row = dst;
569 unsigned char *row_end = dst_row + width;
572 pfunc(dst_row++);
573 while (dst_row < row_end);
575 dst += _gray_info.width;
577 while (dst < dst_end);
578 #else
579 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(x, _gray_info.height) + y];
580 dst_end = dst + _GRAY_MULUQ(width, _gray_info.height);
584 if (fillopt)
585 _gray_rb->memset(dst, bits, height);
586 else
588 unsigned char *dst_col = dst;
589 unsigned char *col_end = dst_col + height;
592 pfunc(dst_col++);
593 while (dst_col < col_end);
595 dst += _gray_info.height;
597 while (dst < dst_end);
598 #endif
601 /* About Rockbox' internal monochrome bitmap format:
603 * A bitmap contains one bit for every pixel that defines if that pixel is
604 * foreground (1) or background (0). Bits within a byte are arranged
605 * vertically, LSB at top.
606 * The bytes are stored in row-major order, with byte 0 being top left,
607 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
608 * 0..7, the second row defines pixel row 8..15 etc. */
610 /* Draw a partial monochrome bitmap */
611 void gray_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
612 int stride, int x, int y, int width, int height)
614 const unsigned char *src_end;
615 unsigned char *dst, *dst_end;
616 void (*fgfunc)(unsigned char *address);
617 void (*bgfunc)(unsigned char *address);
619 /* nothing to draw? */
620 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
621 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
622 return;
624 /* clipping */
625 if (x < 0)
627 width += x;
628 src_x -= x;
629 x = 0;
631 if (y < 0)
633 height += y;
634 src_y -= y;
635 y = 0;
637 if (x + width > _gray_info.width)
638 width = _gray_info.width - x;
639 if (y + height > _gray_info.height)
640 height = _gray_info.height - y;
642 src += _GRAY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */
643 src_y &= 7;
644 src_end = src + width;
646 fgfunc = _gray_pixelfuncs[_gray_info.drawmode];
647 bgfunc = _gray_pixelfuncs[_gray_info.drawmode ^ DRMODE_INVERSEVID];
648 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
649 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(y, _gray_info.width) + x];
653 const unsigned char *src_col = src++;
654 unsigned char *dst_col = dst++;
655 unsigned data = *src_col >> src_y;
656 int numbits = 8 - src_y;
658 dst_end = dst_col + _GRAY_MULUQ(height, _gray_info.width);
661 if (data & 0x01)
662 fgfunc(dst_col);
663 else
664 bgfunc(dst_col);
666 dst_col += _gray_info.width;
668 data >>= 1;
669 if (--numbits == 0)
671 src_col += stride;
672 data = *src_col;
673 numbits = 8;
676 while (dst_col < dst_end);
678 while (src < src_end);
679 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
680 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(x, _gray_info.height) + y];
684 const unsigned char *src_col = src++;
685 unsigned char *dst_col = dst;
686 unsigned data = *src_col >> src_y;
687 int numbits = 8 - src_y;
689 dst_end = dst_col + height;
692 if (data & 0x01)
693 fgfunc(dst_col++);
694 else
695 bgfunc(dst_col++);
697 data >>= 1;
698 if (--numbits == 0)
700 src_col += stride;
701 data = *src_col;
702 numbits = 8;
705 while (dst_col < dst_end);
707 dst += _gray_info.height;
709 while (src < src_end);
710 #endif /* LCD_PIXELFORMAT */
713 /* Draw a full monochrome bitmap */
714 void gray_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
716 gray_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
719 /* Draw a partial greyscale bitmap, canonical format */
720 void gray_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
721 int stride, int x, int y, int width, int height)
723 unsigned char *dst, *dst_end;
725 /* nothing to draw? */
726 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
727 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
728 return;
730 /* clipping */
731 if (x < 0)
733 width += x;
734 src_x -= x;
735 x = 0;
737 if (y < 0)
739 height += y;
740 src_y -= y;
741 y = 0;
743 if (x + width > _gray_info.width)
744 width = _gray_info.width - x;
745 if (y + height > _gray_info.height)
746 height = _gray_info.height - y;
748 src += _GRAY_MULUQ(stride, src_y) + src_x; /* move starting point */
749 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
750 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(y, _gray_info.width) + x];
751 dst_end = dst + _GRAY_MULUQ(height, _gray_info.width);
755 const unsigned char *src_row = src;
756 unsigned char *dst_row = dst;
757 unsigned char *row_end = dst_row + width;
760 *dst_row++ = _gray_info.idxtable[*src_row++];
761 while (dst_row < row_end);
763 src += stride;
764 dst += _gray_info.width;
766 while (dst < dst_end);
767 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
768 dst = &_gray_info.cur_buffer[_GRAY_MULUQ(x, _gray_info.height) + y];
769 dst_end = dst + height;
773 const unsigned char *src_row = src;
774 unsigned char *dst_row = dst++;
775 unsigned char *row_end = dst_row + _GRAY_MULUQ(width, _gray_info.height);
779 *dst_row = _gray_info.idxtable[*src_row++];
780 dst_row += _gray_info.height;
782 while (dst_row < row_end);
784 src += stride;
786 while (dst < dst_end);
787 #endif /* LCD_PIXELFORMAT */
790 /* Draw a full greyscale bitmap, canonical format */
791 void gray_gray_bitmap(const unsigned char *src, int x, int y, int width,
792 int height)
794 gray_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
797 /* Put a string at a given pixel position, skipping first ofs pixel columns */
798 void gray_putsxyofs(int x, int y, int ofs, const unsigned char *str)
800 int ch;
801 struct font* pf = _gray_rb->font_get(_gray_info.curfont);
803 while ((ch = *str++) != '\0' && x < _gray_info.width)
805 int width;
806 const unsigned char *bits;
808 /* check input range */
809 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
810 ch = pf->defaultchar;
811 ch -= pf->firstchar;
813 /* get proportional width and glyph bits */
814 width = pf->width ? pf->width[ch] : pf->maxwidth;
816 if (ofs > width)
818 ofs -= width;
819 continue;
822 bits = pf->bits + (pf->offset ?
823 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
825 gray_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
827 x += width - ofs;
828 ofs = 0;
832 /* Put a string at a given pixel position */
833 void gray_putsxy(int x, int y, const unsigned char *str)
835 gray_putsxyofs(x, y, 0, str);
838 /*** Unbuffered drawing functions ***/
840 #ifdef SIMULATOR
842 /* Clear the greyscale display (sets all pixels to white) */
843 void gray_ub_clear_display(void)
845 _gray_rb->memset(_gray_info.cur_buffer, _gray_info.depth,
846 _GRAY_MULUQ(_gray_info.width, _gray_info.height));
847 gray_update();
850 /* Draw a partial greyscale bitmap, canonical format */
851 void gray_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
852 int stride, int x, int y, int width, int height)
854 gray_gray_bitmap_part(src, src_x, src_y, stride, x, y, width, height);
855 gray_update_rect(x, y, width, height);
858 #else /* !SIMULATOR */
860 /* Clear the greyscale display (sets all pixels to white) */
861 void gray_ub_clear_display(void)
863 _gray_rb->memset(_gray_info.plane_data, 0, _GRAY_MULUQ(_gray_info.depth,
864 _gray_info.plane_size));
867 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
869 /* Write a pixel block, defined by their brightnesses in a greymap.
870 Address is the byte in the first bitplane, src is the greymap start address,
871 mask determines which pixels of the destination block are changed. */
872 static void _writearray(unsigned char *address, const unsigned char *src,
873 unsigned mask)
875 unsigned long pat_stack[8];
876 unsigned long *pat_ptr = &pat_stack[8];
877 unsigned char *addr;
878 #ifdef CPU_ARM
879 const unsigned char *_src;
880 unsigned _mask, depth, trash;
882 _mask = mask;
883 _src = src;
885 /* precalculate the bit patterns with random shifts
886 for all 8 pixels and put them on an extra "stack" */
887 asm volatile
889 "mov %[mask], %[mask], lsl #24 \n" /* shift mask to upper byte */
890 "mov r3, #8 \n" /* loop count */
892 ".wa_loop: \n" /** load pattern for pixel **/
893 "mov r2, #0 \n" /* pattern for skipped pixel must be 0 */
894 "movs %[mask], %[mask], lsl #1 \n" /* shift out msb of mask */
895 "bcc .wa_skip \n" /* skip this pixel */
897 "ldrb r0, [%[src]] \n" /* load src byte */
898 "ldrb r0, [%[trns], r0] \n" /* idxtable into pattern index */
899 "ldr r2, [%[bpat], r0, lsl #2] \n" /* r2 = bitpattern[byte]; */
901 "add %[rnd], %[rnd], %[rnd], lsl #2 \n" /* multiply by 75 */
902 "rsb %[rnd], %[rnd], %[rnd], lsl #4 \n"
903 "add %[rnd], %[rnd], #74 \n" /* add another 74 */
904 /* Since the lower bits are not very random: get bits 8..15 (need max. 5) */
905 "and r1, %[rmsk], %[rnd], lsr #8 \n" /* ..and mask out unneeded bits */
907 "cmp r1, %[dpth] \n" /* random >= depth ? */
908 "subhs r1, r1, %[dpth] \n" /* yes: random -= depth */
910 "mov r0, r2, lsl r1 \n" /** rotate pattern **/
911 "sub r1, %[dpth], r1 \n"
912 "orr r2, r0, r2, lsr r1 \n"
914 ".wa_skip: \n"
915 "str r2, [%[patp], #-4]! \n" /* push on pattern stack */
917 "add %[src], %[src], #1 \n" /* src++; */
918 "subs r3, r3, #1 \n" /* loop 8 times (pixel block) */
919 "bne .wa_loop \n"
920 : /* outputs */
921 [src] "+r"(_src),
922 [patp]"+r"(pat_ptr),
923 [rnd] "+r"(_gray_random_buffer),
924 [mask]"+r"(_mask)
925 : /* inputs */
926 [bpat]"r"(_gray_info.bitpattern),
927 [trns]"r"(_gray_info.idxtable),
928 [dpth]"r"(_gray_info.depth),
929 [rmsk]"r"(_gray_info.randmask)
930 : /* clobbers */
931 "r0", "r1", "r2", "r3"
934 addr = address;
935 _mask = mask;
936 depth = _gray_info.depth;
938 /* set the bits for all 8 pixels in all bytes according to the
939 * precalculated patterns on the pattern stack */
940 asm volatile
942 "ldmia %[patp], {r1 - r8} \n" /* pop all 8 patterns */
944 /** Rotate the four 8x8 bit "blocks" within r1..r8 **/
946 "mov %[rx], #0xF0 \n" /** Stage 1: 4 bit "comb" **/
947 "orr %[rx], %[rx], %[rx], lsl #8 \n"
948 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...11110000 */
949 "eor r0, r1, r5, lsl #4 \n"
950 "and r0, r0, %[rx] \n"
951 "eor r1, r1, r0 \n" /* r1 = ...e3e2e1e0a3a2a1a0 */
952 "eor r5, r5, r0, lsr #4 \n" /* r5 = ...e7e6e5e4a7a6a5a4 */
953 "eor r0, r2, r6, lsl #4 \n"
954 "and r0, r0, %[rx] \n"
955 "eor r2, r2, r0 \n" /* r2 = ...f3f2f1f0b3b2b1b0 */
956 "eor r6, r6, r0, lsr #4 \n" /* r6 = ...f7f6f5f4f7f6f5f4 */
957 "eor r0, r3, r7, lsl #4 \n"
958 "and r0, r0, %[rx] \n"
959 "eor r3, r3, r0 \n" /* r3 = ...g3g2g1g0c3c2c1c0 */
960 "eor r7, r7, r0, lsr #4 \n" /* r7 = ...g7g6g5g4c7c6c5c4 */
961 "eor r0, r4, r8, lsl #4 \n"
962 "and r0, r0, %[rx] \n"
963 "eor r4, r4, r0 \n" /* r4 = ...h3h2h1h0d3d2d1d0 */
964 "eor r8, r8, r0, lsr #4 \n" /* r8 = ...h7h6h5h4d7d6d5d4 */
966 "mov %[rx], #0xCC \n" /** Stage 2: 2 bit "comb" **/
967 "orr %[rx], %[rx], %[rx], lsl #8 \n"
968 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...11001100 */
969 "eor r0, r1, r3, lsl #2 \n"
970 "and r0, r0, %[rx] \n"
971 "eor r1, r1, r0 \n" /* r1 = ...g1g0e1e0c1c0a1a0 */
972 "eor r3, r3, r0, lsr #2 \n" /* r3 = ...g3g2e3e2c3c2a3a2 */
973 "eor r0, r2, r4, lsl #2 \n"
974 "and r0, r0, %[rx] \n"
975 "eor r2, r2, r0 \n" /* r2 = ...h1h0f1f0d1d0b1b0 */
976 "eor r4, r4, r0, lsr #2 \n" /* r4 = ...h3h2f3f2d3d2b3b2 */
977 "eor r0, r5, r7, lsl #2 \n"
978 "and r0, r0, %[rx] \n"
979 "eor r5, r5, r0 \n" /* r5 = ...g5g4e5e4c5c4a5a4 */
980 "eor r7, r7, r0, lsr #2 \n" /* r7 = ...g7g6e7e6c7c6a7a6 */
981 "eor r0, r6, r8, lsl #2 \n"
982 "and r0, r0, %[rx] \n"
983 "eor r6, r6, r0 \n" /* r6 = ...h5h4f5f4d5d4b5b4 */
984 "eor r8, r8, r0, lsr #2 \n" /* r8 = ...h7h6f7f6d7d6b7b6 */
986 "mov %[rx], #0xAA \n" /** Stage 3: 1 bit "comb" **/
987 "orr %[rx], %[rx], %[rx], lsl #8 \n"
988 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...10101010 */
989 "eor r0, r1, r2, lsl #1 \n"
990 "and r0, r0, %[rx] \n"
991 "eor r1, r1, r0 \n" /* r1 = ...h0g0f0e0d0c0b0a0 */
992 "eor r2, r2, r0, lsr #1 \n" /* r2 = ...h1g1f1e1d1c1b1a1 */
993 "eor r0, r3, r4, lsl #1 \n"
994 "and r0, r0, %[rx] \n"
995 "eor r3, r3, r0 \n" /* r3 = ...h2g2f2e2d2c2b2a2 */
996 "eor r4, r4, r0, lsr #1 \n" /* r4 = ...h3g3f3e3d3c3b3a3 */
997 "eor r0, r5, r6, lsl #1 \n"
998 "and r0, r0, %[rx] \n"
999 "eor r5, r5, r0 \n" /* r5 = ...h4g4f4e4d4c4b4a4 */
1000 "eor r6, r6, r0, lsr #1 \n" /* r6 = ...h5g5f5e5d5c5b5a5 */
1001 "eor r0, r7, r8, lsl #1 \n"
1002 "and r0, r0, %[rx] \n"
1003 "eor r7, r7, r0 \n" /* r7 = ...h6g6f6e6d6c6b6a6 */
1004 "eor r8, r8, r0, lsr #1 \n" /* r8 = ...h7g7f7e7d7c7b7a7 */
1006 "sub r0, %[dpth], #1 \n" /** shift out unused low bytes **/
1007 "and r0, r0, #7 \n"
1008 "add pc, pc, r0, lsl #2 \n" /* jump into shift streak */
1009 "mov r8, r8, lsr #8 \n" /* r8: never reached */
1010 "mov r7, r7, lsr #8 \n"
1011 "mov r6, r6, lsr #8 \n"
1012 "mov r5, r5, lsr #8 \n"
1013 "mov r4, r4, lsr #8 \n"
1014 "mov r3, r3, lsr #8 \n"
1015 "mov r2, r2, lsr #8 \n"
1016 "mov r1, r1, lsr #8 \n"
1018 "mvn %[mask], %[mask] \n" /* "set" mask -> "keep" mask */
1019 "ands %[mask], %[mask], #0xff \n"
1020 "beq .wa_sstart \n" /* short loop if no bits to keep */
1022 "ldrb r0, [pc, r0] \n" /* jump into full loop */
1023 "add pc, pc, r0 \n"
1024 ".wa_ftable: \n"
1025 ".byte .wa_f1 - .wa_ftable - 4 \n" /* [jump tables are tricky] */
1026 ".byte .wa_f2 - .wa_ftable - 4 \n"
1027 ".byte .wa_f3 - .wa_ftable - 4 \n"
1028 ".byte .wa_f4 - .wa_ftable - 4 \n"
1029 ".byte .wa_f5 - .wa_ftable - 4 \n"
1030 ".byte .wa_f6 - .wa_ftable - 4 \n"
1031 ".byte .wa_f7 - .wa_ftable - 4 \n"
1032 ".byte .wa_f8 - .wa_ftable - 4 \n"
1034 ".wa_floop: \n" /** full loop (bits to keep)**/
1035 ".wa_f8: \n"
1036 "ldrb r0, [%[addr]] \n" /* load old byte */
1037 "and r0, r0, %[mask] \n" /* mask out replaced bits */
1038 "orr r0, r0, r1 \n" /* set new bits */
1039 "strb r0, [%[addr]], %[psiz] \n" /* store byte */
1040 "mov r1, r1, lsr #8 \n" /* shift out used-up byte */
1041 ".wa_f7: \n"
1042 "ldrb r0, [%[addr]] \n"
1043 "and r0, r0, %[mask] \n"
1044 "orr r0, r0, r2 \n"
1045 "strb r0, [%[addr]], %[psiz] \n"
1046 "mov r2, r2, lsr #8 \n"
1047 ".wa_f6: \n"
1048 "ldrb r0, [%[addr]] \n"
1049 "and r0, r0, %[mask] \n"
1050 "orr r0, r0, r3 \n"
1051 "strb r0, [%[addr]], %[psiz] \n"
1052 "mov r3, r3, lsr #8 \n"
1053 ".wa_f5: \n"
1054 "ldrb r0, [%[addr]] \n"
1055 "and r0, r0, %[mask] \n"
1056 "orr r0, r0, r4 \n"
1057 "strb r0, [%[addr]], %[psiz] \n"
1058 "mov r4, r4, lsr #8 \n"
1059 ".wa_f4: \n"
1060 "ldrb r0, [%[addr]] \n"
1061 "and r0, r0, %[mask] \n"
1062 "orr r0, r0, r5 \n"
1063 "strb r0, [%[addr]], %[psiz] \n"
1064 "mov r5, r5, lsr #8 \n"
1065 ".wa_f3: \n"
1066 "ldrb r0, [%[addr]] \n"
1067 "and r0, r0, %[mask] \n"
1068 "orr r0, r0, r6 \n"
1069 "strb r0, [%[addr]], %[psiz] \n"
1070 "mov r6, r6, lsr #8 \n"
1071 ".wa_f2: \n"
1072 "ldrb r0, [%[addr]] \n"
1073 "and r0, r0, %[mask] \n"
1074 "orr r0, r0, r7 \n"
1075 "strb r0, [%[addr]], %[psiz] \n"
1076 "mov r7, r7, lsr #8 \n"
1077 ".wa_f1: \n"
1078 "ldrb r0, [%[addr]] \n"
1079 "and r0, r0, %[mask] \n"
1080 "orr r0, r0, r8 \n"
1081 "strb r0, [%[addr]], %[psiz] \n"
1082 "mov r8, r8, lsr #8 \n"
1084 "subs %[dpth], %[dpth], #8 \n" /* next round if anything left */
1085 "bhi .wa_floop \n"
1087 "b .wa_end \n"
1089 ".wa_sstart: \n"
1090 "ldrb r0, [pc, r0] \n" /* jump into short loop*/
1091 "add pc, pc, r0 \n"
1092 ".wa_stable: \n"
1093 ".byte .wa_s1 - .wa_stable - 4 \n"
1094 ".byte .wa_s2 - .wa_stable - 4 \n"
1095 ".byte .wa_s3 - .wa_stable - 4 \n"
1096 ".byte .wa_s4 - .wa_stable - 4 \n"
1097 ".byte .wa_s5 - .wa_stable - 4 \n"
1098 ".byte .wa_s6 - .wa_stable - 4 \n"
1099 ".byte .wa_s7 - .wa_stable - 4 \n"
1100 ".byte .wa_s8 - .wa_stable - 4 \n"
1102 ".wa_sloop: \n" /** short loop (nothing to keep) **/
1103 ".wa_s8: \n"
1104 "strb r1, [%[addr]], %[psiz] \n" /* store byte */
1105 "mov r1, r1, lsr #8 \n" /* shift out used-up byte */
1106 ".wa_s7: \n"
1107 "strb r2, [%[addr]], %[psiz] \n"
1108 "mov r2, r2, lsr #8 \n"
1109 ".wa_s6: \n"
1110 "strb r3, [%[addr]], %[psiz] \n"
1111 "mov r3, r3, lsr #8 \n"
1112 ".wa_s5: \n"
1113 "strb r4, [%[addr]], %[psiz] \n"
1114 "mov r4, r4, lsr #8 \n"
1115 ".wa_s4: \n"
1116 "strb r5, [%[addr]], %[psiz] \n"
1117 "mov r5, r5, lsr #8 \n"
1118 ".wa_s3: \n"
1119 "strb r6, [%[addr]], %[psiz] \n"
1120 "mov r6, r6, lsr #8 \n"
1121 ".wa_s2: \n"
1122 "strb r7, [%[addr]], %[psiz] \n"
1123 "mov r7, r7, lsr #8 \n"
1124 ".wa_s1: \n"
1125 "strb r8, [%[addr]], %[psiz] \n"
1126 "mov r8, r8, lsr #8 \n"
1128 "subs %[dpth], %[dpth], #8 \n" /* next round if anything left */
1129 "bhi .wa_sloop \n"
1131 ".wa_end: \n"
1132 : /* outputs */
1133 [addr]"+r"(addr),
1134 [mask]"+r"(_mask),
1135 [dpth]"+r"(depth),
1136 [rx] "=&r"(trash)
1137 : /* inputs */
1138 [psiz]"r"(_gray_info.plane_size),
1139 [patp]"[rx]"(pat_ptr)
1140 : /* clobbers */
1141 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
1143 #else /* C version, for reference*/
1144 #warning C version of _writearray() used
1145 unsigned char *end;
1146 unsigned test = 0x80;
1147 int i;
1149 /* precalculate the bit patterns with random shifts
1150 * for all 8 pixels and put them on an extra "stack" */
1151 for (i = 7; i >= 0; i--)
1153 unsigned pat = 0;
1155 if (mask & test)
1157 int shift;
1159 pat = _gray_info.bitpattern[_gray_info.idxtable[*src]];
1161 /* shift pattern pseudo-random, simple & fast PRNG */
1162 _gray_random_buffer = 75 * _gray_random_buffer + 74;
1163 shift = (_gray_random_buffer >> 8) & _gray_info.randmask;
1164 if (shift >= _gray_info.depth)
1165 shift -= _gray_info.depth;
1167 pat = (pat << shift) | (pat >> (_gray_info.depth - shift));
1169 *(--pat_ptr) = pat;
1170 src++;
1171 test >>= 1;
1174 addr = address;
1175 end = addr + _GRAY_MULUQ(_gray_info.depth, _gray_info.plane_size);
1177 /* set the bits for all 8 pixels in all bytes according to the
1178 * precalculated patterns on the pattern stack */
1179 test = 1 << ((-_gray_info.depth) & 7);
1180 mask = (~mask & 0xff);
1181 if (mask == 0)
1185 unsigned data = 0;
1187 for (i = 7; i >= 0; i--)
1188 data = (data << 1) | ((pat_stack[i] & test) ? 1 : 0);
1190 *addr = data;
1191 addr += _gray_info.plane_size;
1192 test <<= 1;
1194 while (addr < end);
1196 else
1200 unsigned data = 0;
1202 for (i = 7; i >= 0; i--)
1203 data = (data << 1) | ((pat_stack[i] & test) ? 1 : 0);
1205 *addr = (*addr & mask) | data;
1206 addr += _gray_info.plane_size;
1207 test <<= 1;
1209 while (addr < end);
1211 #endif
1214 /* Draw a partial greyscale bitmap, canonical format */
1215 void gray_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
1216 int stride, int x, int y, int width, int height)
1218 int shift, nx;
1219 unsigned char *dst, *dst_end;
1220 unsigned mask, mask_right;
1222 /* nothing to draw? */
1223 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
1224 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
1225 return;
1227 /* clipping */
1228 if (x < 0)
1230 width += x;
1231 src_x -= x;
1232 x = 0;
1234 if (y < 0)
1236 height += y;
1237 src_y -= y;
1238 y = 0;
1240 if (x + width > _gray_info.width)
1241 width = _gray_info.width - x;
1242 if (y + height > _gray_info.height)
1243 height = _gray_info.height - y;
1245 shift = x & 7;
1246 src += _GRAY_MULUQ(stride, src_y) + src_x - shift;
1247 dst = _gray_info.plane_data + (x >> 3) + _GRAY_MULUQ(_gray_info.bwidth, y);
1248 nx = width - 1 + shift;
1250 mask = 0xFFu >> shift;
1251 mask_right = 0xFFu << (~nx & 7);
1253 dst_end = dst + _GRAY_MULUQ(_gray_info.bwidth, height);
1256 const unsigned char *src_row = src;
1257 unsigned char *dst_row = dst;
1258 unsigned mask_row = mask;
1260 for (x = nx; x >= 8; x -= 8)
1262 _writearray(dst_row++, src_row, mask_row);
1263 src_row += 8;
1264 mask_row = 0xFFu;
1266 _writearray(dst_row, src_row, mask_row & mask_right);
1268 src += stride;
1269 dst += _gray_info.bwidth;
1271 while (dst < dst_end);
1273 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING */
1275 /* Write a pixel block, defined by their brightnesses in a greymap.
1276 Address is the byte in the first bitplane, src is the greymap start address,
1277 stride is the increment for the greymap to get to the next pixel, mask
1278 determines which pixels of the destination block are changed. */
1279 static void _writearray(unsigned char *address, const unsigned char *src,
1280 int stride, unsigned mask) __attribute__((noinline));
1281 static void _writearray(unsigned char *address, const unsigned char *src,
1282 int stride, unsigned mask)
1284 unsigned long pat_stack[8];
1285 unsigned long *pat_ptr = &pat_stack[8];
1286 unsigned char *addr;
1287 #if CONFIG_CPU == SH7034
1288 const unsigned char *_src;
1289 unsigned _mask, depth, trash;
1291 _mask = mask;
1292 _src = src;
1294 /* precalculate the bit patterns with random shifts
1295 for all 8 pixels and put them on an extra "stack" */
1296 asm volatile
1298 "mov #8, r3 \n" /* loop count */
1300 ".wa_loop: \n" /** load pattern for pixel **/
1301 "mov #0, r0 \n" /* pattern for skipped pixel must be 0 */
1302 "shlr %[mask] \n" /* shift out lsb of mask */
1303 "bf .wa_skip \n" /* skip this pixel */
1305 "mov.b @%[src], r0 \n" /* load src byte */
1306 "mov #75, r1 \n"
1307 "extu.b r0, r0 \n" /* extend unsigned */
1308 "mov.b @(r0,%[trns]), r0 \n" /* idxtable into pattern index */
1309 "mulu r1, %[rnd] \n" /* multiply by 75 */
1310 "extu.b r0, r0 \n" /* extend unsigned */
1311 "shll2 r0 \n"
1312 "mov.l @(r0,%[bpat]), r4 \n" /* r4 = bitpattern[byte]; */
1313 "sts macl, %[rnd] \n"
1314 "add #74, %[rnd] \n" /* add another 74 */
1315 /* Since the lower bits are not very random: */
1316 "swap.b %[rnd], r1 \n" /* get bits 8..15 (need max. 5) */
1317 "and %[rmsk], r1 \n" /* mask out unneeded bits */
1319 "cmp/hs %[dpth], r1 \n" /* random >= depth ? */
1320 "bf .wa_ntrim \n"
1321 "sub %[dpth], r1 \n" /* yes: random -= depth; */
1322 ".wa_ntrim: \n"
1324 "mov.l .ashlsi3, r0 \n" /** rotate pattern **/
1325 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
1326 "mov r1, r5 \n"
1328 "mov %[dpth], r5 \n"
1329 "sub r1, r5 \n" /* r5 = depth - r1 */
1330 "mov.l .lshrsi3, r1 \n"
1331 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
1332 "mov r0, r1 \n" /* store previous result in r1 */
1334 "or r1, r0 \n" /* rotated_pattern = r0 | r1 */
1336 ".wa_skip: \n"
1337 "mov.l r0, @-%[patp] \n" /* push on pattern stack */
1339 "add %[stri], %[src] \n" /* src += stride; */
1340 "add #-1, r3 \n" /* loop 8 times (pixel block) */
1341 "cmp/pl r3 \n"
1342 "bt .wa_loop \n"
1343 : /* outputs */
1344 [src] "+r"(_src),
1345 [rnd] "+r"(_gray_random_buffer),
1346 [patp]"+r"(pat_ptr),
1347 [mask]"+r"(_mask)
1348 : /* inputs */
1349 [stri]"r"(stride),
1350 [dpth]"r"(_gray_info.depth),
1351 [bpat]"r"(_gray_info.bitpattern),
1352 [rmsk]"r"(_gray_info.randmask),
1353 [trns]"r"(_gray_info.idxtable)
1354 : /* clobbers */
1355 "r0", "r1", "r3", "r4", "r5", "macl", "pr"
1358 addr = address;
1359 _mask = mask;
1360 depth = _gray_info.depth;
1362 /* set the bits for all 8 pixels in all bytes according to the
1363 * precalculated patterns on the pattern stack */
1364 asm volatile
1366 "mov.l @%[patp]+, r8 \n" /* pop all 8 patterns */
1367 "mov.l @%[patp]+, r7 \n"
1368 "mov.l @%[patp]+, r6 \n"
1369 "mov.l @%[patp]+, r5 \n"
1370 "mov.l @%[patp]+, r4 \n"
1371 "mov.l @%[patp]+, r3 \n"
1372 "mov.l @%[patp]+, r2 \n"
1373 "mov.l @%[patp], r1 \n"
1375 /** Rotate the four 8x8 bit "blocks" within r1..r8 **/
1377 "mov.l .wa_mask4, %[rx] \n" /* bitmask = ...11110000 */
1378 "mov r5, r0 \n" /** Stage 1: 4 bit "comb" **/
1379 "shll2 r0 \n"
1380 "shll2 r0 \n"
1381 "xor r1, r0 \n"
1382 "and %[rx], r0 \n"
1383 "xor r0, r1 \n" /* r1 = ...e3e2e1e0a3a2a1a0 */
1384 "shlr2 r0 \n"
1385 "shlr2 r0 \n"
1386 "xor r0, r5 \n" /* r5 = ...e7e6e5e4a7a6a5a4 */
1387 "mov r6, r0 \n"
1388 "shll2 r0 \n"
1389 "shll2 r0 \n"
1390 "xor r2, r0 \n"
1391 "and %[rx], r0 \n"
1392 "xor r0, r2 \n" /* r2 = ...f3f2f1f0b3b2b1b0 */
1393 "shlr2 r0 \n"
1394 "shlr2 r0 \n"
1395 "xor r0, r6 \n" /* r6 = ...f7f6f5f4f7f6f5f4 */
1396 "mov r7, r0 \n"
1397 "shll2 r0 \n"
1398 "shll2 r0 \n"
1399 "xor r3, r0 \n"
1400 "and %[rx], r0 \n"
1401 "xor r0, r3 \n" /* r3 = ...g3g2g1g0c3c2c1c0 */
1402 "shlr2 r0 \n"
1403 "shlr2 r0 \n"
1404 "xor r0, r7 \n" /* r7 = ...g7g6g5g4c7c6c5c4 */
1405 "mov r8, r0 \n"
1406 "shll2 r0 \n"
1407 "shll2 r0 \n"
1408 "xor r4, r0 \n"
1409 "and %[rx], r0 \n"
1410 "xor r0, r4 \n" /* r4 = ...h3h2h1h0d3d2d1d0 */
1411 "shlr2 r0 \n"
1412 "shlr2 r0 \n"
1413 "xor r0, r8 \n" /* r8 = ...h7h6h5h4d7d6d5d4 */
1415 "mov.l .wa_mask2, %[rx] \n" /* bitmask = ...11001100 */
1416 "mov r3, r0 \n" /** Stage 2: 2 bit "comb" **/
1417 "shll2 r0 \n"
1418 "xor r1, r0 \n"
1419 "and %[rx], r0 \n"
1420 "xor r0, r1 \n" /* r1 = ...g1g0e1e0c1c0a1a0 */
1421 "shlr2 r0 \n"
1422 "xor r0, r3 \n" /* r3 = ...g3g2e3e2c3c2a3a2 */
1423 "mov r4, r0 \n"
1424 "shll2 r0 \n"
1425 "xor r2, r0 \n"
1426 "and %[rx], r0 \n"
1427 "xor r0, r2 \n" /* r2 = ...h1h0f1f0d1d0b1b0 */
1428 "shlr2 r0 \n"
1429 "xor r0, r4 \n" /* r4 = ...h3h2f3f2d3d2b3b2 */
1430 "mov r7, r0 \n"
1431 "shll2 r0 \n"
1432 "xor r5, r0 \n"
1433 "and %[rx], r0 \n"
1434 "xor r0, r5 \n" /* r5 = ...g5g4e5e4c5c4a5a4 */
1435 "shlr2 r0 \n"
1436 "xor r0, r7 \n" /* r7 = ...g7g6e7e6c7c6a7a6 */
1437 "mov r8, r0 \n"
1438 "shll2 r0 \n"
1439 "xor r6, r0 \n"
1440 "and %[rx], r0 \n"
1441 "xor r0, r6 \n" /* r6 = ...h5h4f5f4d5d4b5b4 */
1442 "shlr2 r0 \n"
1443 "xor r0, r8 \n" /* r8 = ...h7h6f7f6d7d6b7b6 */
1445 "mov.l .wa_mask1, %[rx] \n" /* bitmask = ...10101010 */
1446 "mov r2, r0 \n" /** Stage 3: 1 bit "comb" **/
1447 "shll r0 \n"
1448 "xor r1, r0 \n"
1449 "and %[rx], r0 \n"
1450 "xor r0, r1 \n" /* r1 = ...h0g0f0e0d0c0b0a0 */
1451 "shlr r0 \n"
1452 "xor r0, r2 \n" /* r2 = ...h1g1f1e1d1c1b1a1 */
1453 "mov r4, r0 \n"
1454 "shll r0 \n"
1455 "xor r3, r0 \n"
1456 "and %[rx], r0 \n"
1457 "xor r0, r3 \n" /* r3 = ...h2g2f2e2d2c2b2a2 */
1458 "shlr r0 \n"
1459 "xor r0, r4 \n" /* r4 = ...h3g3f3e3d3c3b3a3 */
1460 "mov r6, r0 \n"
1461 "shll r0 \n"
1462 "xor r5, r0 \n"
1463 "and %[rx], r0 \n"
1464 "xor r0, r5 \n" /* r5 = ...h4g4f4e4d4c4b4a4 */
1465 "shlr r0 \n"
1466 "xor r0, r6 \n" /* r6 = ...h5g5f5e5d5c5b5a5 */
1467 "mov r8, r0 \n"
1468 "shll r0 \n"
1469 "xor r7, r0 \n"
1470 "and %[rx], r0 \n"
1471 "xor r0, r7 \n" /* r7 = ...h6g6f6e6d6c6b6a6 */
1472 "shlr r0 \n"
1473 "xor r0, r8 \n" /* r8 = ...h7g7f7e7d7c7b7a7 */
1475 "mov %[dpth], %[rx] \n" /** shift out unused low bytes **/
1476 "add #-1, %[rx] \n"
1477 "mov #7, r0 \n"
1478 "and r0, %[rx] \n"
1479 "mova .wa_pshift, r0 \n"
1480 "add %[rx], r0 \n"
1481 "add %[rx], r0 \n"
1482 "jmp @r0 \n" /* jump into shift streak */
1483 "nop \n"
1485 ".align 2 \n"
1486 ".wa_pshift: \n"
1487 "shlr8 r7 \n"
1488 "shlr8 r6 \n"
1489 "shlr8 r5 \n"
1490 "shlr8 r4 \n"
1491 "shlr8 r3 \n"
1492 "shlr8 r2 \n"
1493 "shlr8 r1 \n"
1495 "not %[mask], %[mask] \n" /* "set" mask -> "keep" mask */
1496 "extu.b %[mask], %[mask] \n" /* mask out high bits */
1497 "tst %[mask], %[mask] \n"
1498 "bt .wa_sstart \n" /* short loop if nothing to keep */
1500 "mova .wa_ftable, r0 \n" /* jump into full loop */
1501 "mov.b @(r0, %[rx]), %[rx] \n"
1502 "add %[rx], r0 \n"
1503 "jmp @r0 \n"
1504 "nop \n"
1506 ".align 2 \n"
1507 ".wa_ftable: \n"
1508 ".byte .wa_f1 - .wa_ftable \n"
1509 ".byte .wa_f2 - .wa_ftable \n"
1510 ".byte .wa_f3 - .wa_ftable \n"
1511 ".byte .wa_f4 - .wa_ftable \n"
1512 ".byte .wa_f5 - .wa_ftable \n"
1513 ".byte .wa_f6 - .wa_ftable \n"
1514 ".byte .wa_f7 - .wa_ftable \n"
1515 ".byte .wa_f8 - .wa_ftable \n"
1517 ".wa_floop: \n" /** full loop (there are bits to keep)**/
1518 ".wa_f8: \n"
1519 "mov.b @%[addr], r0 \n" /* load old byte */
1520 "and %[mask], r0 \n" /* mask out replaced bits */
1521 "or r1, r0 \n" /* set new bits */
1522 "mov.b r0, @%[addr] \n" /* store byte */
1523 "add %[psiz], %[addr] \n"
1524 "shlr8 r1 \n" /* shift out used-up byte */
1525 ".wa_f7: \n"
1526 "mov.b @%[addr], r0 \n"
1527 "and %[mask], r0 \n"
1528 "or r2, r0 \n"
1529 "mov.b r0, @%[addr] \n"
1530 "add %[psiz], %[addr] \n"
1531 "shlr8 r2 \n"
1532 ".wa_f6: \n"
1533 "mov.b @%[addr], r0 \n"
1534 "and %[mask], r0 \n"
1535 "or r3, r0 \n"
1536 "mov.b r0, @%[addr] \n"
1537 "add %[psiz], %[addr] \n"
1538 "shlr8 r3 \n"
1539 ".wa_f5: \n"
1540 "mov.b @%[addr], r0 \n"
1541 "and %[mask], r0 \n"
1542 "or r4, r0 \n"
1543 "mov.b r0, @%[addr] \n"
1544 "add %[psiz], %[addr] \n"
1545 "shlr8 r4 \n"
1546 ".wa_f4: \n"
1547 "mov.b @%[addr], r0 \n"
1548 "and %[mask], r0 \n"
1549 "or r5, r0 \n"
1550 "mov.b r0, @%[addr] \n"
1551 "add %[psiz], %[addr] \n"
1552 "shlr8 r5 \n"
1553 ".wa_f3: \n"
1554 "mov.b @%[addr], r0 \n"
1555 "and %[mask], r0 \n"
1556 "or r6, r0 \n"
1557 "mov.b r0, @%[addr] \n"
1558 "add %[psiz], %[addr] \n"
1559 "shlr8 r6 \n"
1560 ".wa_f2: \n"
1561 "mov.b @%[addr], r0 \n"
1562 "and %[mask], r0 \n"
1563 "or r7, r0 \n"
1564 "mov.b r0, @%[addr] \n"
1565 "add %[psiz], %[addr] \n"
1566 "shlr8 r7 \n"
1567 ".wa_f1: \n"
1568 "mov.b @%[addr], r0 \n"
1569 "and %[mask], r0 \n"
1570 "or r8, r0 \n"
1571 "mov.b r0, @%[addr] \n"
1572 "add %[psiz], %[addr] \n"
1573 "shlr8 r8 \n"
1575 "add #-8, %[dpth] \n"
1576 "cmp/pl %[dpth] \n" /* next round if anything left */
1577 "bt .wa_floop \n"
1579 "bra .wa_end \n"
1580 "nop \n"
1582 /* References to C library routines used in the precalc block */
1583 ".align 2 \n"
1584 ".ashlsi3: \n" /* C library routine: */
1585 ".long ___ashlsi3 \n" /* shift r4 left by r5, result in r0 */
1586 ".lshrsi3: \n" /* C library routine: */
1587 ".long ___lshrsi3 \n" /* shift r4 right by r5, result in r0 */
1588 /* both routines preserve r4, destroy r5 and take ~16 cycles */
1590 /* Bitmasks for the bit block rotation */
1591 ".wa_mask4: \n"
1592 ".long 0xF0F0F0F0 \n"
1593 ".wa_mask2: \n"
1594 ".long 0xCCCCCCCC \n"
1595 ".wa_mask1: \n"
1596 ".long 0xAAAAAAAA \n"
1598 ".wa_sstart: \n"
1599 "mova .wa_stable, r0 \n" /* jump into short loop */
1600 "mov.b @(r0, %[rx]), %[rx] \n"
1601 "add %[rx], r0 \n"
1602 "jmp @r0 \n"
1603 "nop \n"
1605 ".align 2 \n"
1606 ".wa_stable: \n"
1607 ".byte .wa_s1 - .wa_stable \n"
1608 ".byte .wa_s2 - .wa_stable \n"
1609 ".byte .wa_s3 - .wa_stable \n"
1610 ".byte .wa_s4 - .wa_stable \n"
1611 ".byte .wa_s5 - .wa_stable \n"
1612 ".byte .wa_s6 - .wa_stable \n"
1613 ".byte .wa_s7 - .wa_stable \n"
1614 ".byte .wa_s8 - .wa_stable \n"
1616 ".wa_sloop: \n" /** short loop (nothing to keep) **/
1617 ".wa_s8: \n"
1618 "mov.b r1, @%[addr] \n" /* store byte */
1619 "add %[psiz], %[addr] \n"
1620 "shlr8 r1 \n" /* shift out used-up byte */
1621 ".wa_s7: \n"
1622 "mov.b r2, @%[addr] \n"
1623 "add %[psiz], %[addr] \n"
1624 "shlr8 r2 \n"
1625 ".wa_s6: \n"
1626 "mov.b r3, @%[addr] \n"
1627 "add %[psiz], %[addr] \n"
1628 "shlr8 r3 \n"
1629 ".wa_s5: \n"
1630 "mov.b r4, @%[addr] \n"
1631 "add %[psiz], %[addr] \n"
1632 "shlr8 r4 \n"
1633 ".wa_s4: \n"
1634 "mov.b r5, @%[addr] \n"
1635 "add %[psiz], %[addr] \n"
1636 "shlr8 r5 \n"
1637 ".wa_s3: \n"
1638 "mov.b r6, @%[addr] \n"
1639 "add %[psiz], %[addr] \n"
1640 "shlr8 r6 \n"
1641 ".wa_s2: \n"
1642 "mov.b r7, @%[addr] \n"
1643 "add %[psiz], %[addr] \n"
1644 "shlr8 r7 \n"
1645 ".wa_s1: \n"
1646 "mov.b r8, @%[addr] \n"
1647 "add %[psiz], %[addr] \n"
1648 "shlr8 r8 \n"
1650 "add #-8, %[dpth] \n"
1651 "cmp/pl %[dpth] \n" /* next round if anything left */
1652 "bt .wa_sloop \n"
1654 ".wa_end: \n"
1655 : /* outputs */
1656 [addr]"+r"(addr),
1657 [mask]"+r"(_mask),
1658 [dpth]"+r"(depth),
1659 [rx] "=&r"(trash)
1660 : /* inputs */
1661 [psiz]"r"(_gray_info.plane_size),
1662 [patp]"[rx]"(pat_ptr)
1663 : /* clobbers */
1664 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "macl"
1666 #elif defined(CPU_COLDFIRE)
1667 const unsigned char *_src;
1668 unsigned _mask, depth, trash;
1670 _mask = mask;
1671 _src = src;
1673 /* precalculate the bit patterns with random shifts
1674 for all 8 pixels and put them on an extra "stack" */
1675 asm volatile
1677 "moveq.l #8, %%d3 \n" /* loop count */
1679 ".wa_loop: \n" /** load pattern for pixel **/
1680 "clr.l %%d2 \n" /* pattern for skipped pixel must be 0 */
1681 "lsr.l #1, %[mask] \n" /* shift out lsb of mask */
1682 "bcc.b .wa_skip \n" /* skip this pixel */
1684 "clr.l %%d0 \n"
1685 "move.b (%[src]), %%d0 \n" /* load src byte */
1686 "move.b (%%d0:l:1, %[trns]), %%d0 \n" /* idxtable into pattern index */
1687 "move.l (%%d0:l:4, %[bpat]), %%d2 \n" /* d2 = bitpattern[byte]; */
1689 "mulu.w #75, %[rnd] \n" /* multiply by 75 */
1690 "add.l #74, %[rnd] \n" /* add another 74 */
1691 /* Since the lower bits are not very random: */
1692 "move.l %[rnd], %%d1 \n"
1693 "lsr.l #8, %%d1 \n" /* get bits 8..15 (need max. 5) */
1694 "and.l %[rmsk], %%d1 \n" /* mask out unneeded bits */
1696 "cmp.l %[dpth], %%d1 \n" /* random >= depth ? */
1697 "blo.b .wa_ntrim \n"
1698 "sub.l %[dpth], %%d1 \n" /* yes: random -= depth; */
1699 ".wa_ntrim: \n"
1701 "move.l %%d2, %%d0 \n" /** rotate pattern **/
1702 "lsl.l %%d1, %%d0 \n"
1703 "sub.l %[dpth], %%d1 \n"
1704 "neg.l %%d1 \n" /* d1 = depth - d1 */
1705 "lsr.l %%d1, %%d2 \n"
1706 "or.l %%d0, %%d2 \n"
1708 ".wa_skip: \n"
1709 "move.l %%d2, -(%[patp]) \n" /* push on pattern stack */
1711 "add.l %[stri], %[src] \n" /* src += stride; */
1712 "subq.l #1, %%d3 \n" /* loop 8 times (pixel block) */
1713 "bne.b .wa_loop \n"
1714 : /* outputs */
1715 [src] "+a"(_src),
1716 [patp]"+a"(pat_ptr),
1717 [rnd] "+d"(_gray_random_buffer),
1718 [mask]"+d"(_mask)
1719 : /* inputs */
1720 [stri]"r"(stride),
1721 [bpat]"a"(_gray_info.bitpattern),
1722 [trns]"a"(_gray_info.idxtable),
1723 [dpth]"d"(_gray_info.depth),
1724 [rmsk]"d"(_gray_info.randmask)
1725 : /* clobbers */
1726 "d0", "d1", "d2", "d3"
1729 addr = address;
1730 _mask = ~mask & 0xff;
1731 depth = _gray_info.depth;
1733 /* set the bits for all 8 pixels in all bytes according to the
1734 * precalculated patterns on the pattern stack */
1735 asm volatile
1737 "movem.l (%[patp]), %%d1-%%d7/%%a0 \n" /* pop all 8 patterns */
1738 /* move.l %%d5, %[ax] */ /* need %%d5 as workspace, but not yet */
1740 /** Rotate the four 8x8 bit "blocks" within r1..r8 **/
1742 "move.l %%d1, %%d0 \n" /** Stage 1: 4 bit "comb" **/
1743 "lsl.l #4, %%d0 \n"
1744 /* move.l %[ax], %%d5 */ /* already in d5 */
1745 "eor.l %%d5, %%d0 \n"
1746 "and.l #0xF0F0F0F0, %%d0 \n" /* bitmask = ...11110000 */
1747 "eor.l %%d0, %%d5 \n"
1748 "move.l %%d5, %[ax] \n" /* ax = ...h3h2h1h0d3d2d1d0 */
1749 "lsr.l #4, %%d0 \n"
1750 "eor.l %%d0, %%d1 \n" /* d1 = ...h7h6h5h4d7d6d5d4 */
1751 "move.l %%d2, %%d0 \n"
1752 "lsl.l #4, %%d0 \n"
1753 "eor.l %%d6, %%d0 \n"
1754 "and.l #0xF0F0F0F0, %%d0 \n"
1755 "eor.l %%d0, %%d6 \n" /* d6 = ...g3g2g1g0c3c2c1c0 */
1756 "lsr.l #4, %%d0 \n"
1757 "eor.l %%d0, %%d2 \n" /* d2 = ...g7g6g5g4c7c6c5c4 */
1758 "move.l %%d3, %%d0 \n"
1759 "lsl.l #4, %%d0 \n"
1760 "eor.l %%d7, %%d0 \n"
1761 "and.l #0xF0F0F0F0, %%d0 \n"
1762 "eor.l %%d0, %%d7 \n" /* d7 = ...f3f2f1f0b3b2b1b0 */
1763 "lsr.l #4, %%d0 \n"
1764 "eor.l %%d0, %%d3 \n" /* d3 = ...f7f6f5f4f7f6f5f4 */
1765 "move.l %%d4, %%d0 \n"
1766 "lsl.l #4, %%d0 \n"
1767 "move.l %%a0, %%d5 \n"
1768 "eor.l %%d5, %%d0 \n"
1769 "and.l #0xF0F0F0F0, %%d0 \n"
1770 "eor.l %%d0, %%d5 \n" /* (a0 = ...e3e2e1e0a3a2a1a0) */
1771 /* move.l %%d5, %%a0 */ /* but d5 is kept until next usage */
1772 "lsr.l #4, %%d0 \n"
1773 "eor.l %%d0, %%d4 \n" /* d4 = ...e7e6e5e4a7a6a5a4 */
1775 "move.l %%d6, %%d0 \n" /** Stage 2: 2 bit "comb" **/
1776 "lsl.l #2, %%d0 \n"
1777 /* move.l %%a0, %%d5 */ /* still in d5 */
1778 "eor.l %%d5, %%d0 \n"
1779 "and.l #0xCCCCCCCC, %%d0 \n" /* bitmask = ...11001100 */
1780 "eor.l %%d0, %%d5 \n"
1781 "move.l %%d5, %%a0 \n" /* a0 = ...g1g0e1e0c1c0a1a0 */
1782 "lsr.l #2, %%d0 \n"
1783 "eor.l %%d0, %%d6 \n" /* d6 = ...g3g2e3e2c3c2a3a2 */
1784 "move.l %[ax], %%d5 \n"
1785 "move.l %%d5, %%d0 \n"
1786 "lsl.l #2, %%d0 \n"
1787 "eor.l %%d7, %%d0 \n"
1788 "and.l #0xCCCCCCCC, %%d0 \n"
1789 "eor.l %%d0, %%d7 \n" /* r2 = ...h1h0f1f0d1d0b1b0 */
1790 "lsr.l #2, %%d0 \n"
1791 "eor.l %%d0, %%d5 \n" /* (ax = ...h3h2f3f2d3d2b3b2) */
1792 /* move.l %%d5, %[ax] */ /* but d5 is kept until next usage */
1793 "move.l %%d2, %%d0 \n"
1794 "lsl.l #2, %%d0 \n"
1795 "eor.l %%d4, %%d0 \n"
1796 "and.l #0xCCCCCCCC, %%d0 \n"
1797 "eor.l %%d0, %%d4 \n" /* d4 = ...g5g4e5e4c5c4a5a4 */
1798 "lsr.l #2, %%d0 \n"
1799 "eor.l %%d0, %%d2 \n" /* d2 = ...g7g6e7e6c7c6a7a6 */
1800 "move.l %%d1, %%d0 \n"
1801 "lsl.l #2, %%d0 \n"
1802 "eor.l %%d3, %%d0 \n"
1803 "and.l #0xCCCCCCCC, %%d0 \n"
1804 "eor.l %%d0, %%d3 \n" /* d3 = ...h5h4f5f4d5d4b5b4 */
1805 "lsr.l #2, %%d0 \n"
1806 "eor.l %%d0, %%d1 \n" /* d1 = ...h7h6f7f6d7d6b7b6 */
1808 "move.l %%d1, %%d0 \n" /** Stage 3: 1 bit "comb" **/
1809 "lsl.l #1, %%d0 \n"
1810 "eor.l %%d2, %%d0 \n"
1811 "and.l #0xAAAAAAAA, %%d0 \n" /* bitmask = ...10101010 */
1812 "eor.l %%d0, %%d2 \n" /* d2 = ...h6g6f6e6d6c6b6a6 */
1813 "lsr.l #1, %%d0 \n"
1814 "eor.l %%d0, %%d1 \n" /* d1 = ...h7g7f7e7d7c7b7a7 */
1815 "move.l %%d3, %%d0 \n"
1816 "lsl.l #1, %%d0 \n"
1817 "eor.l %%d4, %%d0 \n"
1818 "and.l #0xAAAAAAAA, %%d0 \n"
1819 "eor.l %%d0, %%d4 \n" /* d4 = ...h4g4f4e4d4c4b4a4 */
1820 "lsr.l #1, %%d0 \n"
1821 "eor.l %%d0, %%d3 \n" /* d3 = ...h5g5f5e5d5c5b5a5 */
1822 /* move.l %[ax], %%d5 */ /* still in d5 */
1823 "move.l %%d5, %%d0 \n"
1824 "lsl.l #1, %%d0 \n"
1825 "eor.l %%d6, %%d0 \n"
1826 "and.l #0xAAAAAAAA, %%d0 \n"
1827 "eor.l %%d0, %%d6 \n" /* d6 = ...h2g2f2e2d2c2b2a2 */
1828 "lsr.l #1, %%d0 \n"
1829 "eor.l %%d0, %%d5 \n"
1830 "move.l %%d5, %[ax] \n" /* ax = ...h3g3f3e3d3c3b3a3 */
1831 "move.l %%d7, %%d0 \n"
1832 "lsl.l #1, %%d0 \n"
1833 "move.l %%a0, %%d5 \n"
1834 "eor.l %%d5, %%d0 \n"
1835 "and.l #0xAAAAAAAA, %%d0 \n"
1836 "eor.l %%d0, %%d5 \n" /* (a0 = ...h0g0f0e0d0c0b0a0) */
1837 /* move.l %%d5, %%a0 */ /* but keep in d5 for shift streak */
1838 "lsr.l #1, %%d0 \n"
1839 "eor.l %%d0, %%d7 \n" /* d7 = ...h1g1f1e1d1c1b1a1 */
1841 "move.l %[dpth], %%d0 \n" /** shift out unused low bytes **/
1842 "subq.l #1, %%d0 \n"
1843 "and.l #7, %%d0 \n"
1844 "move.l %%d0, %%a0 \n"
1845 "move.l %[ax], %%d0 \n" /* all data in D registers */
1846 "jmp (2, %%pc, %%a0:l:2) \n" /* jump into shift streak */
1847 "lsr.l #8, %%d2 \n"
1848 "lsr.l #8, %%d3 \n"
1849 "lsr.l #8, %%d4 \n"
1850 "lsr.l #8, %%d0 \n"
1851 "lsr.l #8, %%d6 \n"
1852 "lsr.l #8, %%d7 \n"
1853 "lsr.l #8, %%d5 \n"
1854 "move.l %%d0, %[ax] \n" /* put the 2 extra words back.. */
1855 "move.l %%a0, %%d0 \n" /* keep the value for later */
1856 "move.l %%d5, %%a0 \n" /* ..into their A registers */
1858 "tst.l %[mask] \n"
1859 "jeq .wa_sstart \n" /* short loop if nothing to keep */
1861 "move.l %[mask], %%d5 \n" /* need mask in data reg. */
1862 "move.l %%d1, %[mask] \n" /* free d1 as working reg. */
1864 "jmp (2, %%pc, %%d0:l:2) \n" /* jump into full loop */
1865 "bra.s .wa_f1 \n"
1866 "bra.s .wa_f2 \n"
1867 "bra.s .wa_f3 \n"
1868 "bra.s .wa_f4 \n"
1869 "bra.s .wa_f5 \n"
1870 "bra.s .wa_f6 \n"
1871 "bra.s .wa_f7 \n"
1872 /* bra.s .wa_f8 */ /* identical with target */
1874 ".wa_floop: \n" /** full loop (there are bits to keep)**/
1875 ".wa_f8: \n"
1876 "move.b (%[addr]), %%d0 \n" /* load old byte */
1877 "and.l %%d5, %%d0 \n" /* mask out replaced bits */
1878 "move.l %%a0, %%d1 \n"
1879 "or.l %%d1, %%d0 \n" /* set new bits */
1880 "move.b %%d0, (%[addr]) \n" /* store byte */
1881 "add.l %[psiz], %[addr] \n"
1882 "lsr.l #8, %%d1 \n" /* shift out used-up byte */
1883 "move.l %%d1, %%a0 \n"
1884 ".wa_f7: \n"
1885 "move.b (%[addr]), %%d0 \n"
1886 "and.l %%d5, %%d0 \n"
1887 "or.l %%d7, %%d0 \n"
1888 "move.b %%d0, (%[addr]) \n"
1889 "add.l %[psiz], %[addr] \n"
1890 "lsr.l #8, %%d7 \n"
1891 ".wa_f6: \n"
1892 "move.b (%[addr]), %%d0 \n"
1893 "and.l %%d5, %%d0 \n"
1894 "or.l %%d6, %%d0 \n"
1895 "move.b %%d0, (%[addr]) \n"
1896 "add.l %[psiz], %[addr] \n"
1897 "lsr.l #8, %%d6 \n"
1898 ".wa_f5: \n"
1899 "move.b (%[addr]), %%d0 \n"
1900 "and.l %%d5, %%d0 \n"
1901 "move.l %[ax], %%d1 \n"
1902 "or.l %%d1, %%d0 \n"
1903 "move.b %%d0, (%[addr]) \n"
1904 "add.l %[psiz], %[addr] \n"
1905 "lsr.l #8, %%d1 \n"
1906 "move.l %%d1, %[ax] \n"
1907 ".wa_f4: \n"
1908 "move.b (%[addr]), %%d0 \n"
1909 "and.l %%d5, %%d0 \n"
1910 "or.l %%d4, %%d0 \n"
1911 "move.b %%d0, (%[addr]) \n"
1912 "add.l %[psiz], %[addr] \n"
1913 "lsr.l #8, %%d4 \n"
1914 ".wa_f3: \n"
1915 "move.b (%[addr]), %%d0 \n"
1916 "and.l %%d5, %%d0 \n"
1917 "or.l %%d3, %%d0 \n"
1918 "move.b %%d0, (%[addr]) \n"
1919 "add.l %[psiz], %[addr] \n"
1920 "lsr.l #8, %%d3 \n"
1921 ".wa_f2: \n"
1922 "move.b (%[addr]), %%d0 \n"
1923 "and.l %%d5, %%d0 \n"
1924 "or.l %%d2, %%d0 \n"
1925 "move.b %%d0, (%[addr]) \n"
1926 "add.l %[psiz], %[addr] \n"
1927 "lsr.l #8, %%d2 \n"
1928 ".wa_f1: \n"
1929 "move.b (%[addr]), %%d0 \n"
1930 "and.l %%d5, %%d0 \n"
1931 "move.l %[mask], %%d1 \n"
1932 "or.l %%d1, %%d0 \n"
1933 "move.b %%d0, (%[addr]) \n"
1934 "add.l %[psiz], %[addr] \n"
1935 "lsr.l #8, %%d1 \n"
1936 "move.l %%d1, %[mask] \n"
1938 "subq.l #8, %[dpth] \n"
1939 "tst.l %[dpth] \n" /* subq doesn't set flags for A reg */
1940 "jgt .wa_floop \n" /* next round if anything left */
1942 "jra .wa_end \n"
1944 ".wa_sstart: \n"
1945 "jmp (2, %%pc, %%d0:l:2) \n" /* jump into short loop */
1946 "bra.s .wa_s1 \n"
1947 "bra.s .wa_s2 \n"
1948 "bra.s .wa_s3 \n"
1949 "bra.s .wa_s4 \n"
1950 "bra.s .wa_s5 \n"
1951 "bra.s .wa_s6 \n"
1952 "bra.s .wa_s7 \n"
1953 /* bra.s .wa_s8 */ /* identical with target */
1955 ".wa_sloop: \n" /** short loop (nothing to keep) **/
1956 ".wa_s8: \n"
1957 "move.l %%a0, %%d5 \n"
1958 "move.b %%d5, (%[addr]) \n" /* store byte */
1959 "add.l %[psiz], %[addr] \n"
1960 "lsr.l #8, %%d5 \n" /* shift out used-up byte */
1961 "move.l %%d5, %%a0 \n"
1962 ".wa_s7: \n"
1963 "move.b %%d7, (%[addr]) \n"
1964 "add.l %[psiz], %[addr] \n"
1965 "lsr.l #8, %%d7 \n"
1966 ".wa_s6: \n"
1967 "move.b %%d6, (%[addr]) \n"
1968 "add.l %[psiz], %[addr] \n"
1969 "lsr.l #8, %%d6 \n"
1970 ".wa_s5: \n"
1971 "move.l %[ax], %%d5 \n"
1972 "move.b %%d5, (%[addr]) \n"
1973 "add.l %[psiz], %[addr] \n"
1974 "lsr.l #8, %%d5 \n"
1975 "move.l %%d5, %[ax] \n"
1976 ".wa_s4: \n"
1977 "move.b %%d4, (%[addr]) \n"
1978 "add.l %[psiz], %[addr] \n"
1979 "lsr.l #8, %%d4 \n"
1980 ".wa_s3: \n"
1981 "move.b %%d3, (%[addr]) \n"
1982 "add.l %[psiz], %[addr] \n"
1983 "lsr.l #8, %%d3 \n"
1984 ".wa_s2: \n"
1985 "move.b %%d2, (%[addr]) \n"
1986 "add.l %[psiz], %[addr] \n"
1987 "lsr.l #8, %%d2 \n"
1988 ".wa_s1: \n"
1989 "move.b %%d1, (%[addr]) \n"
1990 "add.l %[psiz], %[addr] \n"
1991 "lsr.l #8, %%d1 \n"
1993 "subq.l #8, %[dpth] \n"
1994 "tst.l %[dpth] \n" /* subq doesn't set flags for A reg */
1995 "jgt .wa_sloop \n" /* next round if anything left */
1997 ".wa_end: \n"
1998 : /* outputs */
1999 [addr]"+a"(addr),
2000 [dpth]"+a"(depth),
2001 [mask]"+a"(_mask),
2002 [ax] "=&a"(trash)
2003 : /* inputs */
2004 [psiz]"a"(_gray_info.plane_size),
2005 [patp]"[ax]"(pat_ptr)
2006 : /* clobbers */
2007 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0"
2009 #elif defined(CPU_ARM)
2010 const unsigned char *_src;
2011 unsigned _mask, depth, trash;
2013 _mask = mask;
2014 _src = src;
2016 pat_ptr = &pat_stack[0];
2018 /* precalculate the bit patterns with random shifts
2019 for all 8 pixels and put them on an extra "stack" */
2020 asm volatile
2022 "mov r3, #8 \n" /* loop count */
2024 ".wa_loop: \n" /** load pattern for pixel **/
2025 "mov r2, #0 \n" /* pattern for skipped pixel must be 0 */
2026 "movs %[mask], %[mask], lsr #1 \n" /* shift out msb of mask */
2027 "bcc .wa_skip \n" /* skip this pixel */
2029 "ldrb r0, [%[src]] \n" /* load src byte */
2030 "ldrb r0, [%[trns], r0] \n" /* idxtable into pattern index */
2031 "ldr r2, [%[bpat], r0, lsl #2] \n" /* r2 = bitpattern[byte]; */
2033 "add %[rnd], %[rnd], %[rnd], lsl #2 \n" /* multiply by 75 */
2034 "rsb %[rnd], %[rnd], %[rnd], lsl #4 \n"
2035 "add %[rnd], %[rnd], #74 \n" /* add another 74 */
2036 /* Since the lower bits are not very random: get bits 8..15 (need max. 5) */
2037 "and r1, %[rmsk], %[rnd], lsr #8 \n" /* ..and mask out unneeded bits */
2039 "cmp r1, %[dpth] \n" /* random >= depth ? */
2040 "subhs r1, r1, %[dpth] \n" /* yes: random -= depth */
2042 "mov r0, r2, lsl r1 \n" /** rotate pattern **/
2043 "sub r1, %[dpth], r1 \n"
2044 "orr r2, r0, r2, lsr r1 \n"
2046 ".wa_skip: \n"
2047 "str r2, [%[patp]], #4 \n" /* push on pattern stack */
2049 "add %[src], %[src], %[stri] \n" /* src += stride; */
2050 "subs r3, r3, #1 \n" /* loop 8 times (pixel block) */
2051 "bne .wa_loop \n"
2052 : /* outputs */
2053 [src] "+r"(_src),
2054 [patp]"+r"(pat_ptr),
2055 [rnd] "+r"(_gray_random_buffer),
2056 [mask]"+r"(_mask)
2057 : /* inputs */
2058 [stri]"r"(stride),
2059 [bpat]"r"(_gray_info.bitpattern),
2060 [trns]"r"(_gray_info.idxtable),
2061 [dpth]"r"(_gray_info.depth),
2062 [rmsk]"r"(_gray_info.randmask)
2063 : /* clobbers */
2064 "r0", "r1", "r2", "r3"
2067 addr = address;
2068 _mask = mask;
2069 depth = _gray_info.depth;
2071 /* set the bits for all 8 pixels in all bytes according to the
2072 * precalculated patterns on the pattern stack */
2073 asm volatile
2075 "ldmdb %[patp], {r1 - r8} \n" /* pop all 8 patterns */
2077 /** Rotate the four 8x8 bit "blocks" within r1..r8 **/
2079 "mov %[rx], #0xF0 \n" /** Stage 1: 4 bit "comb" **/
2080 "orr %[rx], %[rx], %[rx], lsl #8 \n"
2081 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...11110000 */
2082 "eor r0, r1, r5, lsl #4 \n"
2083 "and r0, r0, %[rx] \n"
2084 "eor r1, r1, r0 \n" /* r1 = ...e3e2e1e0a3a2a1a0 */
2085 "eor r5, r5, r0, lsr #4 \n" /* r5 = ...e7e6e5e4a7a6a5a4 */
2086 "eor r0, r2, r6, lsl #4 \n"
2087 "and r0, r0, %[rx] \n"
2088 "eor r2, r2, r0 \n" /* r2 = ...f3f2f1f0b3b2b1b0 */
2089 "eor r6, r6, r0, lsr #4 \n" /* r6 = ...f7f6f5f4f7f6f5f4 */
2090 "eor r0, r3, r7, lsl #4 \n"
2091 "and r0, r0, %[rx] \n"
2092 "eor r3, r3, r0 \n" /* r3 = ...g3g2g1g0c3c2c1c0 */
2093 "eor r7, r7, r0, lsr #4 \n" /* r7 = ...g7g6g5g4c7c6c5c4 */
2094 "eor r0, r4, r8, lsl #4 \n"
2095 "and r0, r0, %[rx] \n"
2096 "eor r4, r4, r0 \n" /* r4 = ...h3h2h1h0d3d2d1d0 */
2097 "eor r8, r8, r0, lsr #4 \n" /* r8 = ...h7h6h5h4d7d6d5d4 */
2099 "mov %[rx], #0xCC \n" /** Stage 2: 2 bit "comb" **/
2100 "orr %[rx], %[rx], %[rx], lsl #8 \n"
2101 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...11001100 */
2102 "eor r0, r1, r3, lsl #2 \n"
2103 "and r0, r0, %[rx] \n"
2104 "eor r1, r1, r0 \n" /* r1 = ...g1g0e1e0c1c0a1a0 */
2105 "eor r3, r3, r0, lsr #2 \n" /* r3 = ...g3g2e3e2c3c2a3a2 */
2106 "eor r0, r2, r4, lsl #2 \n"
2107 "and r0, r0, %[rx] \n"
2108 "eor r2, r2, r0 \n" /* r2 = ...h1h0f1f0d1d0b1b0 */
2109 "eor r4, r4, r0, lsr #2 \n" /* r4 = ...h3h2f3f2d3d2b3b2 */
2110 "eor r0, r5, r7, lsl #2 \n"
2111 "and r0, r0, %[rx] \n"
2112 "eor r5, r5, r0 \n" /* r5 = ...g5g4e5e4c5c4a5a4 */
2113 "eor r7, r7, r0, lsr #2 \n" /* r7 = ...g7g6e7e6c7c6a7a6 */
2114 "eor r0, r6, r8, lsl #2 \n"
2115 "and r0, r0, %[rx] \n"
2116 "eor r6, r6, r0 \n" /* r6 = ...h5h4f5f4d5d4b5b4 */
2117 "eor r8, r8, r0, lsr #2 \n" /* r8 = ...h7h6f7f6d7d6b7b6 */
2119 "mov %[rx], #0xAA \n" /** Stage 3: 1 bit "comb" **/
2120 "orr %[rx], %[rx], %[rx], lsl #8 \n"
2121 "orr %[rx], %[rx], %[rx], lsl #16\n" /* bitmask = ...10101010 */
2122 "eor r0, r1, r2, lsl #1 \n"
2123 "and r0, r0, %[rx] \n"
2124 "eor r1, r1, r0 \n" /* r1 = ...h0g0f0e0d0c0b0a0 */
2125 "eor r2, r2, r0, lsr #1 \n" /* r2 = ...h1g1f1e1d1c1b1a1 */
2126 "eor r0, r3, r4, lsl #1 \n"
2127 "and r0, r0, %[rx] \n"
2128 "eor r3, r3, r0 \n" /* r3 = ...h2g2f2e2d2c2b2a2 */
2129 "eor r4, r4, r0, lsr #1 \n" /* r4 = ...h3g3f3e3d3c3b3a3 */
2130 "eor r0, r5, r6, lsl #1 \n"
2131 "and r0, r0, %[rx] \n"
2132 "eor r5, r5, r0 \n" /* r5 = ...h4g4f4e4d4c4b4a4 */
2133 "eor r6, r6, r0, lsr #1 \n" /* r6 = ...h5g5f5e5d5c5b5a5 */
2134 "eor r0, r7, r8, lsl #1 \n"
2135 "and r0, r0, %[rx] \n"
2136 "eor r7, r7, r0 \n" /* r7 = ...h6g6f6e6d6c6b6a6 */
2137 "eor r8, r8, r0, lsr #1 \n" /* r8 = ...h7g7f7e7d7c7b7a7 */
2139 "sub r0, %[dpth], #1 \n" /** shift out unused low bytes **/
2140 "and r0, r0, #7 \n"
2141 "add pc, pc, r0, lsl #2 \n" /* jump into shift streak */
2142 "mov r8, r8, lsr #8 \n" /* r8: never reached */
2143 "mov r7, r7, lsr #8 \n"
2144 "mov r6, r6, lsr #8 \n"
2145 "mov r5, r5, lsr #8 \n"
2146 "mov r4, r4, lsr #8 \n"
2147 "mov r3, r3, lsr #8 \n"
2148 "mov r2, r2, lsr #8 \n"
2149 "mov r1, r1, lsr #8 \n"
2151 "mvn %[mask], %[mask] \n" /* "set" mask -> "keep" mask */
2152 "ands %[mask], %[mask], #0xff \n"
2153 "beq .wa_sstart \n" /* short loop if no bits to keep */
2155 "ldrb r0, [pc, r0] \n" /* jump into full loop */
2156 "add pc, pc, r0 \n"
2157 ".wa_ftable: \n"
2158 ".byte .wa_f1 - .wa_ftable - 4 \n" /* [jump tables are tricky] */
2159 ".byte .wa_f2 - .wa_ftable - 4 \n"
2160 ".byte .wa_f3 - .wa_ftable - 4 \n"
2161 ".byte .wa_f4 - .wa_ftable - 4 \n"
2162 ".byte .wa_f5 - .wa_ftable - 4 \n"
2163 ".byte .wa_f6 - .wa_ftable - 4 \n"
2164 ".byte .wa_f7 - .wa_ftable - 4 \n"
2165 ".byte .wa_f8 - .wa_ftable - 4 \n"
2167 ".wa_floop: \n" /** full loop (bits to keep)**/
2168 ".wa_f8: \n"
2169 "ldrb r0, [%[addr]] \n" /* load old byte */
2170 "and r0, r0, %[mask] \n" /* mask out replaced bits */
2171 "orr r0, r0, r1 \n" /* set new bits */
2172 "strb r0, [%[addr]], %[psiz] \n" /* store byte */
2173 "mov r1, r1, lsr #8 \n" /* shift out used-up byte */
2174 ".wa_f7: \n"
2175 "ldrb r0, [%[addr]] \n"
2176 "and r0, r0, %[mask] \n"
2177 "orr r0, r0, r2 \n"
2178 "strb r0, [%[addr]], %[psiz] \n"
2179 "mov r2, r2, lsr #8 \n"
2180 ".wa_f6: \n"
2181 "ldrb r0, [%[addr]] \n"
2182 "and r0, r0, %[mask] \n"
2183 "orr r0, r0, r3 \n"
2184 "strb r0, [%[addr]], %[psiz] \n"
2185 "mov r3, r3, lsr #8 \n"
2186 ".wa_f5: \n"
2187 "ldrb r0, [%[addr]] \n"
2188 "and r0, r0, %[mask] \n"
2189 "orr r0, r0, r4 \n"
2190 "strb r0, [%[addr]], %[psiz] \n"
2191 "mov r4, r4, lsr #8 \n"
2192 ".wa_f4: \n"
2193 "ldrb r0, [%[addr]] \n"
2194 "and r0, r0, %[mask] \n"
2195 "orr r0, r0, r5 \n"
2196 "strb r0, [%[addr]], %[psiz] \n"
2197 "mov r5, r5, lsr #8 \n"
2198 ".wa_f3: \n"
2199 "ldrb r0, [%[addr]] \n"
2200 "and r0, r0, %[mask] \n"
2201 "orr r0, r0, r6 \n"
2202 "strb r0, [%[addr]], %[psiz] \n"
2203 "mov r6, r6, lsr #8 \n"
2204 ".wa_f2: \n"
2205 "ldrb r0, [%[addr]] \n"
2206 "and r0, r0, %[mask] \n"
2207 "orr r0, r0, r7 \n"
2208 "strb r0, [%[addr]], %[psiz] \n"
2209 "mov r7, r7, lsr #8 \n"
2210 ".wa_f1: \n"
2211 "ldrb r0, [%[addr]] \n"
2212 "and r0, r0, %[mask] \n"
2213 "orr r0, r0, r8 \n"
2214 "strb r0, [%[addr]], %[psiz] \n"
2215 "mov r8, r8, lsr #8 \n"
2217 "subs %[dpth], %[dpth], #8 \n" /* next round if anything left */
2218 "bhi .wa_floop \n"
2220 "b .wa_end \n"
2222 ".wa_sstart: \n"
2223 "ldrb r0, [pc, r0] \n" /* jump into short loop*/
2224 "add pc, pc, r0 \n"
2225 ".wa_stable: \n"
2226 ".byte .wa_s1 - .wa_stable - 4 \n"
2227 ".byte .wa_s2 - .wa_stable - 4 \n"
2228 ".byte .wa_s3 - .wa_stable - 4 \n"
2229 ".byte .wa_s4 - .wa_stable - 4 \n"
2230 ".byte .wa_s5 - .wa_stable - 4 \n"
2231 ".byte .wa_s6 - .wa_stable - 4 \n"
2232 ".byte .wa_s7 - .wa_stable - 4 \n"
2233 ".byte .wa_s8 - .wa_stable - 4 \n"
2235 ".wa_sloop: \n" /** short loop (nothing to keep) **/
2236 ".wa_s8: \n"
2237 "strb r1, [%[addr]], %[psiz] \n" /* store byte */
2238 "mov r1, r1, lsr #8 \n" /* shift out used-up byte */
2239 ".wa_s7: \n"
2240 "strb r2, [%[addr]], %[psiz] \n"
2241 "mov r2, r2, lsr #8 \n"
2242 ".wa_s6: \n"
2243 "strb r3, [%[addr]], %[psiz] \n"
2244 "mov r3, r3, lsr #8 \n"
2245 ".wa_s5: \n"
2246 "strb r4, [%[addr]], %[psiz] \n"
2247 "mov r4, r4, lsr #8 \n"
2248 ".wa_s4: \n"
2249 "strb r5, [%[addr]], %[psiz] \n"
2250 "mov r5, r5, lsr #8 \n"
2251 ".wa_s3: \n"
2252 "strb r6, [%[addr]], %[psiz] \n"
2253 "mov r6, r6, lsr #8 \n"
2254 ".wa_s2: \n"
2255 "strb r7, [%[addr]], %[psiz] \n"
2256 "mov r7, r7, lsr #8 \n"
2257 ".wa_s1: \n"
2258 "strb r8, [%[addr]], %[psiz] \n"
2259 "mov r8, r8, lsr #8 \n"
2261 "subs %[dpth], %[dpth], #8 \n" /* next round if anything left */
2262 "bhi .wa_sloop \n"
2264 ".wa_end: \n"
2265 : /* outputs */
2266 [addr]"+r"(addr),
2267 [mask]"+r"(_mask),
2268 [dpth]"+r"(depth),
2269 [rx] "=&r"(trash)
2270 : /* inputs */
2271 [psiz]"r"(_gray_info.plane_size),
2272 [patp]"[rx]"(pat_ptr)
2273 : /* clobbers */
2274 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
2276 #else /* C version, for reference*/
2277 #warning C version of _writearray() used
2278 unsigned char *end;
2279 unsigned test = 1;
2280 int i;
2282 /* precalculate the bit patterns with random shifts
2283 * for all 8 pixels and put them on an extra "stack" */
2284 for (i = 7; i >= 0; i--)
2286 unsigned pat = 0;
2288 if (mask & test)
2290 int shift;
2292 pat = _gray_info.bitpattern[_gray_info.idxtable[*src]];
2294 /* shift pattern pseudo-random, simple & fast PRNG */
2295 _gray_random_buffer = 75 * _gray_random_buffer + 74;
2296 shift = (_gray_random_buffer >> 8) & _gray_info.randmask;
2297 if (shift >= _gray_info.depth)
2298 shift -= _gray_info.depth;
2300 pat = (pat << shift) | (pat >> (_gray_info.depth - shift));
2302 *(--pat_ptr) = pat;
2303 src += stride;
2304 test <<= 1;
2307 addr = address;
2308 end = addr + _GRAY_MULUQ(_gray_info.depth, _gray_info.plane_size);
2310 /* set the bits for all 8 pixels in all bytes according to the
2311 * precalculated patterns on the pattern stack */
2312 test = 1 << ((-_gray_info.depth) & 7);
2313 mask = (~mask & 0xff);
2314 if (mask == 0)
2318 unsigned data = 0;
2320 for (i = 0; i < 8; i++)
2321 data = (data << 1) | ((pat_stack[i] & test) ? 1 : 0);
2323 *addr = data;
2324 addr += _gray_info.plane_size;
2325 test <<= 1;
2327 while (addr < end);
2329 else
2333 unsigned data = 0;
2335 for (i = 0; i < 8; i++)
2336 data = (data << 1) | ((pat_stack[i] & test) ? 1 : 0);
2338 *addr = (*addr & mask) | data;
2339 addr += _gray_info.plane_size;
2340 test <<= 1;
2342 while (addr < end);
2344 #endif
2347 /* Draw a partial greyscale bitmap, canonical format */
2348 void gray_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
2349 int stride, int x, int y, int width, int height)
2351 int shift, ny;
2352 unsigned char *dst, *dst_end;
2353 unsigned mask, mask_bottom;
2355 /* nothing to draw? */
2356 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
2357 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
2358 return;
2360 /* clipping */
2361 if (x < 0)
2363 width += x;
2364 src_x -= x;
2365 x = 0;
2367 if (y < 0)
2369 height += y;
2370 src_y -= y;
2371 y = 0;
2373 if (x + width > _gray_info.width)
2374 width = _gray_info.width - x;
2375 if (y + height > _gray_info.height)
2376 height = _gray_info.height - y;
2378 shift = y & 7;
2379 src += _GRAY_MULUQ(stride, src_y) + src_x - _GRAY_MULUQ(stride, shift);
2380 dst = _gray_info.plane_data + x
2381 + _GRAY_MULUQ(_gray_info.width, y >> 3);
2382 ny = height - 1 + shift;
2384 mask = 0xFFu << shift;
2385 mask_bottom = 0xFFu >> (~ny & 7);
2387 for (; ny >= 8; ny -= 8)
2389 const unsigned char *src_row = src;
2390 unsigned char *dst_row = dst;
2392 dst_end = dst_row + width;
2394 _writearray(dst_row++, src_row++, stride, mask);
2395 while (dst_row < dst_end);
2397 src += stride << 3;
2398 dst += _gray_info.width;
2399 mask = 0xFFu;
2401 mask &= mask_bottom;
2402 dst_end = dst + width;
2404 _writearray(dst++, src++, stride, mask);
2405 while (dst < dst_end);
2407 #endif /* LCD_PIXELFORMAT */
2409 #endif /* !SIMULATOR */
2411 /* Draw a full greyscale bitmap, canonical format */
2412 void gray_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
2413 int height)
2415 gray_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
2418 #endif /* HAVE_LCD_BITMAP */