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