]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libgfxbitmap/lib/src/bitmap.c
update
[l4.git] / l4 / pkg / libgfxbitmap / lib / src / bitmap.c
1 /**
2  * \file
3  * \brief       bitmap functions
4  *
5  * \date        2001
6  * \author      Christian Helmuth <ch12@os.inf.tu-dresden.de>
7  *              Frank Mehnert <fm3@os.inf.tu-dresden.de>
8  *              Adam Lackorzynski <adam@os.inf.tu-dresden.de> */
9 /*
10  * (c) 2001-2009 Author(s)
11  *     economic rights: Technische Universität Dresden (Germany)
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU Lesser General Public License 2.1.
14  * Please see the COPYING-LGPL-2.1 file for details.
15  */
16
17 #include <stdlib.h>
18 #include <string.h>             /* needed for memmove */
19
20 #include <l4/sys/cache.h>
21
22 #include <l4/libgfxbitmap/bitmap.h>
23
24 static int use_fastmemcpy;
25
26 #define OFFSET(x, y, ptr, bytepp) ptr += (y) * bwidth + (x) * (bytepp);
27
28 static inline void
29 _bmap16lsb(l4_uint8_t *vfb,
30            l4_uint8_t *bmap,
31            l4_uint32_t fgc,
32            l4_uint32_t bgc,
33            l4_uint32_t w, l4_uint32_t h,
34            struct gfxbitmap_offset* offset,
35            l4_uint32_t bwidth)
36 {
37    l4_uint32_t nobits=0;
38    l4_uint32_t i, j, k, kmod;
39
40    nobits += offset->preskip_y
41       * (w + offset->preskip_x + offset->endskip_x);
42    /* length of one line in bmap (bits!) */
43
44    for (i = 0; i < h; i++) {
45       nobits += offset->preskip_x;
46       for (j = 0; j < w; j++, nobits++) {
47          k = nobits>>3;
48          kmod = (nobits)%8;
49          if ( bmap[k] & (0x01 << kmod) )
50             *(l4_uint16_t*) (&vfb[2*j]) = (l4_uint16_t) (fgc & 0xffff);
51          else
52             *(l4_uint16_t*) (&vfb[2*j]) = (l4_uint16_t) (bgc & 0xffff);
53       }
54 #ifdef CLEAN_CACHE
55       l4_sys_cache_clean_range((unsigned long)vfb,
56                                (unsigned long)vfb + w*2);
57 #endif
58       vfb += bwidth;
59    }
60 }
61
62 static inline void
63 _bmap16msb(l4_uint8_t *vfb,
64            l4_uint8_t *bmap,
65            l4_uint32_t fgc,
66            l4_uint32_t bgc,
67            l4_uint32_t w, l4_uint32_t h,
68            struct gfxbitmap_offset* offset,
69            l4_uint32_t bwidth)
70 {
71   l4_uint32_t i, j;
72   l4_uint32_t nobits = offset->preskip_y
73                    * (w + offset->preskip_x + offset->endskip_x);
74
75   for (i = 0; i < h; i++)
76     {
77       unsigned char mask, *b;
78       nobits += offset->preskip_x;
79       mask = 0x80 >> (nobits % 8);
80       b = bmap + nobits / 8;
81       for (j = 0; j < w; j++, nobits++)
82         {
83           /* gcc is able to code the entire loop without using any jump
84            * if compiled with -march=i686 (uses cmov instructions then) */
85           *(l4_uint16_t*) (&vfb[2*j]) = (*b & mask)
86                                         ? (l4_uint16_t) (fgc & 0xffff)
87                                         : (l4_uint16_t) (bgc & 0xffff);
88           b += mask & 1;
89           mask = (mask >> 1) | (mask << 7); /* gcc optimizes this into ROR */
90         }
91 #ifdef CLEAN_CACHE
92       l4_sys_cache_clean_range((unsigned long)vfb,
93                                (unsigned long)vfb + w*2);
94 #endif
95       vfb += bwidth;
96       nobits += offset->endskip_x;
97    }
98 }
99
100 static inline void
101 _bmap24lsb(l4_uint8_t *vfb,
102            l4_uint8_t *bmap,
103            l4_uint32_t fgc,
104            l4_uint32_t bgc,
105            l4_uint32_t w, l4_uint32_t h,
106            struct gfxbitmap_offset* offset,
107            l4_uint32_t bwidth)
108 {
109    l4_uint32_t nobits=0;
110    l4_uint32_t i,j, k,kmod;
111
112    nobits += offset->preskip_y
113       * (w + offset->preskip_x + offset->endskip_x);
114    /* length of one line in bmap (bits!) */
115
116    for (i = 0; i < h; i++) {
117       nobits += offset->preskip_x;
118       for (j = 0; j < w; j++, nobits++) {
119          k = nobits>>3;
120          kmod = (nobits)%8;
121          if ( bmap[k] & (0x01 << kmod) ) {
122             *(l4_uint16_t*) (&vfb[3*j]) = (l4_uint16_t) (fgc & 0xffff);
123             vfb[3*j+2] = (l4_uint8_t) (fgc >> 16);
124          }
125          else {
126             *(l4_uint16_t*) (&vfb[3*j]) = (l4_uint16_t) (bgc & 0xffff);
127             vfb[3*j+2] = (l4_uint8_t) (bgc >> 16);
128          }
129       }
130 #ifdef CLEAN_CACHE
131       l4_sys_cache_clean_range((unsigned long)vfb,
132                                (unsigned long)vfb + w*3);
133 #endif
134       vfb += bwidth;
135    }
136 }
137
138 static inline void
139 _bmap24msb(l4_uint8_t *vfb,
140            l4_uint8_t *bmap,
141            l4_uint32_t fgc,
142            l4_uint32_t bgc,
143            l4_uint32_t w, l4_uint32_t h,
144            struct gfxbitmap_offset* offset,
145            l4_uint32_t bwidth)
146 {
147    l4_uint32_t nobits=0;
148    l4_uint32_t i,j, k,kmod;
149
150    nobits += offset->preskip_y
151       * (w + offset->preskip_x + offset->endskip_x);
152    /* length of one line in bmap (bits!) */
153
154    for (i = 0; i < h; i++) {
155       nobits += offset->preskip_x;
156       for (j = 0; j < w; j++, nobits++) {
157          k = nobits>>3;
158          kmod = (nobits)%8;
159          if ( bmap[k] & (0x80 >> kmod) ) {
160             *(l4_uint16_t*) (&vfb[3*j]) = (l4_uint16_t) (fgc & 0xffff);
161             vfb[3*j+2] = (l4_uint8_t) (fgc >> 16);
162          }
163          else {
164             *(l4_uint16_t*) (&vfb[3*j]) = (l4_uint16_t) (bgc & 0xffff);
165             vfb[3*j+2] = (l4_uint8_t) (bgc >> 16);
166          }
167       }
168 #ifdef CLEAN_CACHE
169       l4_sys_cache_clean_range((unsigned long)vfb,
170                                (unsigned long)vfb + w*3);
171 #endif
172       vfb += bwidth;
173       /* length of one line in bmap parsed */
174       nobits += offset->endskip_x;
175    }
176 }
177
178 static inline void
179 _bmap32lsb(l4_uint8_t *vfb,
180            l4_uint8_t *bmap,
181            l4_uint32_t fgc,
182            l4_uint32_t bgc,
183            l4_uint32_t w, l4_uint32_t h,
184            struct gfxbitmap_offset* offset,
185            l4_uint32_t bwidth)
186 {
187    l4_uint32_t nobits=0;
188    l4_uint32_t i,j, k,kmod;
189
190    nobits += offset->preskip_y
191       * (w + offset->preskip_x + offset->endskip_x);
192    /* length of one line in bmap (bits!) */
193
194    for (i = 0; i < h; i++) {
195       nobits += offset->preskip_x;
196       for (j = 0; j < w; j++, nobits++) {
197          l4_uint32_t *dest = (l4_uint32_t*)&vfb[4*j];
198          k = nobits>>3;
199          kmod = (nobits)%8;
200          *dest = (bmap[k] & (0x01 << kmod))
201             ? fgc & 0xffffffff
202             : bgc & 0xffffffff;
203       }
204 #ifdef CLEAN_CACHE
205       l4_sys_cache_clean_range((unsigned long)vfb,
206                                (unsigned long)vfb + w*4);
207 #endif
208       vfb += bwidth;
209    }
210 }
211
212 static inline void
213 _bmap32msb(l4_uint8_t *vfb,
214            l4_uint8_t *bmap,
215            l4_uint32_t fgc,
216            l4_uint32_t bgc,
217            l4_uint32_t w, l4_uint32_t h,
218            struct gfxbitmap_offset* offset,
219            l4_uint32_t bwidth)
220 {
221    l4_uint32_t nobits=0;
222    l4_uint32_t i,j,k,kmod;
223
224    nobits += offset->preskip_y
225       * (w + offset->preskip_x + offset->endskip_x);
226    /* length of one line in bmap (bits!) */
227
228    for (i = 0; i < h; i++) {
229       nobits += offset->preskip_x;
230       for (j = 0; j < w; j++, nobits++) {
231          k = nobits>>3;
232          kmod = (nobits)%8;
233          if ( bmap[k] & (0x80 >> kmod) )
234             *(l4_uint32_t*) (&vfb[4*j]) = (l4_uint32_t) (fgc & 0x00ffffff);
235          else
236             *(l4_uint32_t*) (&vfb[4*j]) = (l4_uint32_t) (bgc & 0x00ffffff);
237       }
238 #ifdef CLEAN_CACHE
239       l4_sys_cache_clean_range((unsigned long)vfb,
240                                (unsigned long)vfb + w*4);
241 #endif
242       vfb += bwidth;
243       /* length of one line in bmap parsed */
244       nobits += offset->endskip_x;
245    }
246 }
247
248 static inline void
249 _set16(l4_uint8_t *dest,
250        l4_uint8_t *pmap,
251        l4_uint32_t w, l4_uint32_t h,
252        struct gfxbitmap_offset* offset,
253        l4_uint32_t bwidth,
254        l4_uint32_t pwidth)
255 {
256   l4_uint32_t i;
257
258 #ifdef ARCH_x86
259   if (use_fastmemcpy && (w % 4 == 0))
260     {
261       asm ("emms");
262       for (i = 0; i < h; i++)
263         {
264           l4_umword_t dummy;
265           pmap += 2 * offset->preskip_x;
266           asm volatile("xorl    %%edx,%%edx              \n\t"
267                        "1:                               \n\t"
268                        "movq    (%%esi,%%edx,8),%%mm0    \n\t"
269                        "movntq  %%mm0,(%%edi,%%edx,8)    \n\t"
270                        "add     $1,%%edx                 \n\t"
271                        "dec     %%ecx                    \n\t"
272                        "jnz     1b                       \n\t"
273                        : "=c"(dummy), "=d"(dummy)
274                        : "c"(w/4), "S"(pmap), "D"(dest));
275           dest += bwidth;
276           pmap += pwidth;
277         }
278       asm ("sfence; emms");
279     }
280   else
281 #endif
282     {
283       for (i = 0; i < h; i++)
284         {
285           pmap += 2 * offset->preskip_x;
286           memcpy(dest, pmap, w*2);
287 #ifdef CLEAN_CACHE
288           l4_sys_cache_clean_range((unsigned long)dest,
289                                    (unsigned long)dest + w*2);
290 #endif
291           dest += bwidth;
292           pmap += pwidth;
293         }
294     }
295 }
296
297 static inline void
298 _set24(l4_uint8_t *dest,
299        l4_uint8_t *pmap,
300        l4_uint32_t w, l4_uint32_t h,
301        struct gfxbitmap_offset* offset,
302        l4_uint32_t bwidth,
303        l4_uint32_t pwidth)
304 {
305   l4_uint32_t i;
306
307   for (i = 0; i < h; i++)
308     {
309       pmap += 3 * offset->preskip_x;
310       memcpy(dest, pmap, w*3);
311 #ifdef CLEAN_CACHE
312       l4_sys_cache_clean_range((unsigned long)dest,
313                                (unsigned long)dest + w*3);
314 #endif
315       dest += bwidth;
316       pmap += pwidth;
317     }
318 }
319
320 static inline void
321 _set32(l4_uint8_t *dest,
322        l4_uint8_t *pmap,
323        l4_uint32_t w, l4_uint32_t h,
324        struct gfxbitmap_offset* offset,
325        l4_uint32_t bwidth,
326        l4_uint32_t pwidth)
327 {
328   l4_uint32_t i;
329
330   for (i = 0; i < h; i++)
331     {
332       pmap += 4 * offset->preskip_x;
333       memcpy(dest, pmap, w*4);
334 #ifdef CLEAN_CACHE
335       l4_sys_cache_clean_range((unsigned long)dest,
336                                (unsigned long)dest + w*4);
337 #endif
338       dest += bwidth;
339       pmap += pwidth;
340    }
341 }
342
343 static inline void
344 _copy16(l4_uint8_t *dest,
345         l4_uint8_t *src,
346         l4_int16_t x, l4_int16_t y,
347         l4_int16_t dx, l4_int16_t dy,
348         l4_uint32_t w, l4_uint32_t h,
349         l4_uint32_t bwidth)
350 {
351   l4_uint32_t i;
352
353   if (dy == y && dx == x)
354     return;
355
356   if (y >= dy)
357     {
358       OFFSET( x,  y, src,  2);
359       OFFSET(dx, dy, dest, 2);
360       for (i = 0; i < h; i++)
361         {
362           /* memmove can deal with overlapping regions */
363           memmove(dest, src, 2*w);
364           src += bwidth;
365           dest += bwidth;
366         }
367     }
368   else
369     {
370       OFFSET( x,  y + h - 1, src,  2);
371       OFFSET(dx, dy + h - 1, dest, 2);
372       for (i = 0; i < h; i++)
373         {
374           /* memmove can deal with overlapping regions */
375           memmove(dest, src, 2*w);
376           src -= bwidth;
377           dest -= bwidth;
378         }
379     }
380 }
381
382 static inline void
383 _copy24(l4_uint8_t *dest,
384         l4_uint8_t *src,
385         l4_int16_t x, l4_int16_t y,
386         l4_int16_t dx, l4_int16_t dy,
387         l4_uint32_t w, l4_uint32_t h,
388         l4_uint32_t bwidth)
389 {
390    l4_uint32_t i;
391
392    if (y >= dy) {
393       if (y == dy && dx >= x) { /* tricky */
394          int j;
395          if (x == dx)
396             return;
397          /* my way: start right go left */
398          OFFSET( x,  y, src,  3);
399          OFFSET(dx, dy, dest, 3);
400          for (i = 0; i < h; i++) {
401             for (j = w; j >= 0; --j) {
402                 *(l4_uint16_t*) (&dest[3*j]) = *(l4_uint16_t*) (&src[3*j]);
403                 dest[3*j+2] = src[3*j+2];
404             }
405             src += bwidth;
406             dest += bwidth;
407          }
408
409       }
410       else {            /* copy from top to bottom */
411          l4_uint32_t j;
412          OFFSET( x,  y, src,  3);
413          OFFSET(dx, dy, dest, 3);
414          for (i = 0; i < h; i++) {
415             for (j = 0; j < w; j++) {
416                *(l4_uint16_t*) (&dest[3*j]) = *(l4_uint16_t*) (&src[3*j]);
417                dest[3*j+2] = src[3*j+2];
418             }
419             src += bwidth;
420             dest += bwidth;
421          }
422       }
423    }
424    else {               /* copy from bottom to top */
425       OFFSET( x,  y + h, src,  3);
426       OFFSET(dx, dy + h, dest, 3);
427       for (i = 0; i < h; i++) {
428          l4_uint32_t j;
429          src -= bwidth;
430          dest -= bwidth;
431          for (j = 0; j < w; j++) {
432             *(l4_uint16_t*) (&dest[3*j]) = *(l4_uint16_t*) (&src[3*j]);
433             dest[3*j+2] = src[3*j+2];
434          }
435       }
436    }
437 }
438
439 static inline void
440 _copy32(l4_uint8_t *dest,
441         l4_uint8_t *src,
442         l4_int16_t x, l4_int16_t y,
443         l4_int16_t dx, l4_int16_t dy,
444         l4_uint32_t w, l4_uint32_t h,
445         l4_uint32_t bwidth)
446 {
447    l4_uint32_t i;
448
449    if (y >= dy) {
450       if (y == dy && dx >= x) { /* tricky */
451          int j;
452          if (x == dx)
453             return;
454          /* my way: start right go left */
455          OFFSET( x,  y, src,  4);
456          OFFSET(dx, dy, dest, 4);
457          for (i = 0; i < h; i++) {
458             for (j = w; j >= 0; --j)
459                *(l4_uint32_t*) (&dest[4*j]) = *(l4_uint32_t*) (&src[4*j]);
460             src += bwidth;
461             dest += bwidth;
462          }
463
464       }
465       else {            /* copy from top to bottom */
466          l4_uint32_t j;
467          OFFSET( x,  y, src,  4);
468          OFFSET(dx, dy, dest, 4);
469          for (i = 0; i < h; i++) {
470             for (j = 0; j < w; j++)
471                *(l4_uint32_t*) (&dest[4*j]) = *(l4_uint32_t*) (&src[4*j]);
472             src += bwidth;
473             dest += bwidth;
474          }
475       }
476    }
477    else {               /* copy from bottom to top */
478       l4_uint32_t j;
479       OFFSET( x,  y + h, src,  4);
480       OFFSET(dx, dy + h, dest, 4);
481       for (i = 0; i < h; i++) {
482          src -= bwidth;
483          dest -= bwidth;
484          for (j = 0; j < w; j++)
485             *(l4_uint32_t*) (&dest[4*j]) = *(l4_uint32_t*) (&src[4*j]);
486       }
487    }
488 }
489
490 static inline void
491 _fill16(l4_uint8_t *vfb,
492         l4_uint32_t w, l4_uint32_t h,
493         l4_uint32_t color,
494         l4_uint32_t bwidth)
495 {
496   l4_uint32_t i,j;
497
498   for (i = 0; i < h; i++)
499     {
500       for (j = 0; j < w; j++)
501         *(l4_uint16_t*) (&vfb[2*j]) = (l4_uint16_t)color;
502       vfb += bwidth;
503     }
504 }
505
506 static inline void
507 _fill24(l4_uint8_t *vfb,
508         l4_uint32_t w, l4_uint32_t h,
509         l4_uint32_t color,
510         l4_uint32_t bwidth)
511 {
512    l4_uint32_t i,j;
513
514    for (i = 0; i < h; i++) {
515       for (j = 0; j < w; j++) {
516          *(l4_uint16_t*) (&vfb[3*j  ]) = (l4_uint16_t)color;
517                            vfb[3*j+2]  = (l4_uint8_t) (color >> 16);
518       }
519       vfb += bwidth;
520    }
521 }
522
523 static inline void
524 _fill32(l4_uint8_t *vfb,
525         l4_uint32_t w, l4_uint32_t h,
526         l4_uint32_t color,
527         l4_uint32_t bwidth)
528 {
529    l4_uint32_t i,j;
530
531    for (i = 0; i < h; i++) {
532       for (j = 0; j < w; j++)
533          *(l4_uint32_t*) (&vfb[4*j]) = (l4_uint32_t)color;
534       vfb += bwidth;
535    }
536 }
537
538 void
539 gfxbitmap_fill(l4_uint8_t *vfb, l4re_video_view_info_t *vi,
540                int x, int y, int w, int h, unsigned color)
541 {
542   unsigned bwidth = vi->bytes_per_line;
543   OFFSET(x, y, vfb, vi->pixel_info.bytes_per_pixel);
544
545   switch (vi->pixel_info.bytes_per_pixel)
546     {
547     case 4:
548       _fill32(vfb, w, h, color, vi->bytes_per_line);
549       break;
550     case 3:
551       _fill24(vfb, w, h, color, vi->bytes_per_line);
552       break;
553     case 2:
554     default:
555       _fill16(vfb, w, h, color, vi->bytes_per_line);
556     }
557 }
558
559 void
560 gfxbitmap_bmap(l4_uint8_t *vfb, l4re_video_view_info_t *vi,
561                l4_int16_t x, l4_int16_t y, l4_uint32_t w,
562                l4_uint32_t h, l4_uint8_t *bmap, l4_uint32_t fgc, l4_uint32_t bgc,
563                struct gfxbitmap_offset* offset, l4_uint8_t mode)
564 {
565   l4_uint32_t bwidth = vi->bytes_per_line;
566   OFFSET(x, y, vfb, vi->pixel_info.bytes_per_pixel);
567
568   switch (mode)
569     {
570     case pSLIM_BMAP_START_MSB:
571       switch (vi->pixel_info.bytes_per_pixel)
572         {
573         case 4:
574           _bmap32msb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
575           break;
576         case 3:
577           _bmap24msb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
578           break;
579         case 2:
580         default:
581           _bmap16msb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
582         }
583       break;
584     case pSLIM_BMAP_START_LSB:
585     default:    /* `start at least significant' bit is default */
586       switch (vi->pixel_info.bytes_per_pixel)
587         {
588         case 4:
589           _bmap32lsb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
590           break;
591         case 3:
592           _bmap24lsb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
593           break;
594         case 2:
595         default:
596           _bmap16lsb(vfb, bmap, fgc, bgc, w, h, offset, bwidth);
597         }
598     }
599 }
600
601 void
602 gfxbitmap_set(l4_uint8_t *vfb, l4re_video_view_info_t *vi,
603               l4_int16_t x, l4_int16_t y, l4_uint32_t w,
604               l4_uint32_t h, l4_uint32_t xoffs, l4_uint32_t yoffs,
605               l4_uint8_t *pmap, struct gfxbitmap_offset* offset,
606               l4_uint32_t pwidth)
607 {
608   l4_uint32_t bwidth = vi->bytes_per_line;
609
610   OFFSET(x+xoffs, y+yoffs, vfb, vi->pixel_info.bytes_per_pixel);
611
612   switch (vi->pixel_info.bytes_per_pixel)
613     {
614     case 4:
615       _set32(vfb, pmap, w, h, offset, bwidth, pwidth);
616       break;
617     case 3:
618       _set24(vfb, pmap, w, h, offset, bwidth, pwidth);
619       break;
620     case 2:
621     default:
622       _set16(vfb, pmap, w, h, offset, bwidth, pwidth);
623     }
624 }
625
626 void
627 gfxbitmap_copy(l4_uint8_t *dest, l4_uint8_t *src, l4re_video_view_info_t *vi,
628                int x, int y, int w, int h, int dx, int dy)
629 {
630   switch (vi->pixel_info.bytes_per_pixel)
631     {
632     case 4:
633       _copy32(dest, src, x, y, dx, dy, w, h, vi->bytes_per_line);
634       break;
635     case 3:
636       _copy24(dest, src, x, y, dx, dy, w, h, vi->bytes_per_line);
637       break;
638     case 2:
639     default:
640       _copy16(dest, src, x, y, dx, dy, w, h, vi->bytes_per_line);
641     }
642 }
643
644 gfxbitmap_color_pix_t
645 gfxbitmap_convert_color(l4re_video_view_info_t *vi, gfxbitmap_color_t rgb)
646 {
647   switch (l4re_video_bits_per_pixel(&vi->pixel_info))
648   {
649     case 24:
650     case 32:
651       return rgb & 0x00FFFFFF;
652
653     case 15:
654       return (((rgb >> (16 + 8 - vi->pixel_info.r.size)) & ((1 << vi->pixel_info.r.size)-1)) << vi->pixel_info.r.shift)
655            | (((rgb >> ( 8 + 8 - vi->pixel_info.g.size)) & ((1 << vi->pixel_info.g.size)-1)) << vi->pixel_info.g.shift)
656            | (((rgb >> ( 0 + 8 - vi->pixel_info.b.size)) & ((1 << vi->pixel_info.b.size)-1)) << vi->pixel_info.b.shift);
657
658     case 16:
659     default:
660       return ((rgb & 0x00F80000) >> 8)
661            | ((rgb & 0x0000FC00) >> 5)
662            | ((rgb & 0x000000F8) >> 3);
663   }
664
665 }