]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/drivers/fblin16.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / drivers / fblin16.c
1 /*
2  * Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
3  *
4  * 16bpp Linear Video Driver for Microwindows
5  *
6  * Inspired from Ben Pfaff's BOGL <pfaffben@debian.org>
7  */
8 /*#define NDEBUG*/
9 #include <assert.h>
10 #include <stdlib.h>
11
12 /* We want to do string copying fast, so inline assembly if possible */
13 #ifndef __OPTIMIZE__
14 #define __OPTIMIZE__
15 #endif
16 #include <string.h>
17
18 #include "device.h"
19 #include "fb.h"
20
21 #define USE_DRAWAREA     0      /* =1 to implement temp removed DrawArea code*/
22 #define USE_16BIT_ACCESS 0      /* =1 to force 16 bit display access*/
23
24 #if USE_16BIT_ACCESS
25 #define memcpy(d,s,nbytes)      memcpy16(d,s,(nbytes)>>1)
26 #define memmove(d,s,nbytes)     memcpy16(d,s,(nbytes)>>1)
27 static void
28 memcpy16(unsigned short *dst, unsigned short *src, int nwords)
29 {
30         while (--nwords >= 0)
31                 *dst++ = *src++;
32 }
33 #endif
34
35 /* Calc linelen and mmap size, return 0 on fail*/
36 static int
37 linear16_init(PSD psd)
38 {
39         if (!psd->size) {
40                 psd->size = psd->yres * psd->linelen;
41                 /* convert linelen from byte to pixel len for bpp 16, 24, 32*/
42                 psd->linelen /= 2;
43         }
44         return 1;
45 }
46
47 /* Set pixel at x, y, to pixelval c*/
48 static void
49 linear16_drawpixel(PSD psd, MWCOORD x, MWCOORD y, MWPIXELVAL c)
50 {
51         ADDR16  addr = psd->addr;
52
53         assert (addr != 0);
54         assert (x >= 0 && x < psd->xres);
55         assert (y >= 0 && y < psd->yres);
56         assert (c < psd->ncolors);
57
58         DRAWON;
59         if(gr_mode == MWMODE_COPY)
60                 addr[x + y * psd->linelen] = c;
61         else
62                 applyOp(gr_mode, c, &addr[x + y * psd->linelen], ADDR16);
63         DRAWOFF;
64 }
65
66 /* Read pixel at x, y*/
67 static MWPIXELVAL
68 linear16_readpixel(PSD psd, MWCOORD x, MWCOORD y)
69 {
70         ADDR16  addr = psd->addr;
71
72         assert (addr != 0);
73         assert (x >= 0 && x < psd->xres);
74         assert (y >= 0 && y < psd->yres);
75
76         return addr[x + y * psd->linelen];
77 }
78
79 /* Draw horizontal line from x1,y to x2,y including final point*/
80 static void
81 linear16_drawhorzline(PSD psd, MWCOORD x1, MWCOORD x2, MWCOORD y, MWPIXELVAL c)
82 {
83         ADDR16  addr = psd->addr;
84
85         assert (addr != 0);
86         assert (x1 >= 0 && x1 < psd->xres);
87         assert (x2 >= 0 && x2 < psd->xres);
88         assert (x2 >= x1);
89         assert (y >= 0 && y < psd->yres);
90         assert (c < psd->ncolors);
91
92         DRAWON;
93         addr += x1 + y * psd->linelen;
94         if(gr_mode == MWMODE_COPY) {
95                 /* FIXME: memsetw(dst, c, x2-x1+1)*/
96                 while(x1++ <= x2)
97                         *addr++ = c;
98         } else {
99                 while (x1++ <= x2) {
100                         applyOp(gr_mode, c, addr, ADDR16);
101                         ++addr;
102                 }
103         }
104         DRAWOFF;
105 }
106
107 /* Draw a vertical line from x,y1 to x,y2 including final point*/
108 static void
109 linear16_drawvertline(PSD psd, MWCOORD x, MWCOORD y1, MWCOORD y2, MWPIXELVAL c)
110 {
111         ADDR16  addr = psd->addr;
112         int     linelen = psd->linelen;
113
114         assert (addr != 0);
115         assert (x >= 0 && x < psd->xres);
116         assert (y1 >= 0 && y1 < psd->yres);
117         assert (y2 >= 0 && y2 < psd->yres);
118         assert (y2 >= y1);
119         assert (c < psd->ncolors);
120
121         DRAWON;
122         addr += x + y1 * linelen;
123         if(gr_mode == MWMODE_COPY) {
124                 while(y1++ <= y2) {
125                         *addr = c;
126                         addr += linelen;
127                 }
128         } else {
129                 while (y1++ <= y2) {
130                         applyOp(gr_mode, c, addr, ADDR16);
131                         addr += linelen;
132                 }
133         }
134         DRAWOFF;
135 }
136
137 /* srccopy bitblt*/
138 static void
139 linear16_blit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD w, MWCOORD h,
140         PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long op)
141 {
142         ADDR16  dst = dstpsd->addr;
143         ADDR16  src = srcpsd->addr;
144         int     i;
145         int     dlinelen = dstpsd->linelen;
146         int     slinelen = srcpsd->linelen;
147 #if ALPHABLEND
148         unsigned int alpha;
149 #endif
150
151         assert (dst != 0);
152         assert (dstx >= 0 && dstx < dstpsd->xres);
153         assert (dsty >= 0 && dsty < dstpsd->yres);
154         assert (w > 0);
155         assert (h > 0);
156         assert (src != 0);
157         assert (srcx >= 0 && srcx < srcpsd->xres);
158         assert (srcy >= 0 && srcy < srcpsd->yres);
159         assert (dstx+w <= dstpsd->xres);
160         assert (dsty+h <= dstpsd->yres);
161         assert (srcx+w <= srcpsd->xres);
162         assert (srcy+h <= srcpsd->yres);
163
164         DRAWON;
165         dst += dstx + dsty * dlinelen;
166         src += srcx + srcy * slinelen;
167
168 #if ALPHABLEND
169         if((op & MWROP_EXTENSION) != MWROP_BLENDCONSTANT)
170                 goto stdblit;
171         alpha = op & 0xff;
172
173         if (dstpsd->pixtype == MWPF_TRUECOLOR565) {
174                 while(--h >= 0) {
175                         for(i=0; i<w; ++i) {
176                                 unsigned int s = *src++;
177                                 unsigned int d = *dst;
178                                 unsigned int t = d & 0xf800;
179                                 unsigned int m1, m2, m3;
180                                 m1 = (((((s & 0xf800) - t)*alpha)>>8) & 0xf800) + t;
181                                 t = d & 0x07e0;
182                                 m2 = (((((s & 0x07e0) - t)*alpha)>>8) & 0x07e0) + t;
183                                 t = d & 0x001f;
184                                 m3 = (((((s & 0x001f) - t)*alpha)>>8) & 0x001f) + t;
185                                 *dst++ = m1 | m2 | m3;
186                         }
187                         dst += dlinelen - w;
188                         src += slinelen - w;
189                 }
190         } else {
191                 /* 5/5/5 format*/
192                 while(--h >= 0) {
193                         for(i=0; i<w; ++i) {
194                                 unsigned int s = *src++;
195                                 unsigned int d = *dst;
196                                 unsigned int t = d & 0x7c00;
197                                 unsigned int m1, m2, m3;
198                                 m1 = (((((s & 0x7c00) - t)*alpha)>>8) & 0x7c00) + t;
199                                 t = d & 0x03e0;
200                                 m2 = (((((s & 0x03e0) - t)*alpha)>>8) & 0x03e0) + t;
201                                 t = d & 0x001f;
202                                 m3 = (((((s & 0x001f) - t)*alpha)>>8) & 0x001f) + t;
203                                 *dst++ = m1 | m2 | m3;
204                         }
205                         dst += dlinelen - w;
206                         src += slinelen - w;
207                 }
208         }
209         DRAWOFF;
210         return;
211 stdblit:
212 #endif
213
214         if (op == MWROP_COPY) {
215                 /* copy from bottom up if dst in src rectangle*/
216                 /* memmove is used to handle x case*/
217                 if (srcy < dsty) {
218                         src += (h-1) * slinelen;
219                         dst += (h-1) * dlinelen;
220                         slinelen *= -1;
221                         dlinelen *= -1;
222                 }
223                 while (--h >= 0) {
224                         /* a _fast_ memcpy is a _must_ in this routine*/
225                         memmove(dst, src, w<<1);
226                         dst += dlinelen;
227                         src += slinelen;
228                 }
229         } else {
230                 while (--h >= 0) {
231                         for (i=0; i<w; i++) {
232                                 applyOp(MWROP_TO_MODE(op), *src, dst, ADDR16);
233                                 ++src;
234                                 ++dst;
235                         }
236                         dst += dlinelen - w;
237                         src += slinelen - w;
238                 }
239         }
240         DRAWOFF;
241 }
242
243 /* VERY experimental globals for debugging stretchblit off-by-some bug*/
244 extern int g_row_inc, g_col_inc;
245
246 /* srccopy stretchblt*/
247 static void
248 linear16_stretchblit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD dstw,
249         MWCOORD dsth, PSD srcpsd, MWCOORD srcx, MWCOORD srcy, MWCOORD srcw,
250         MWCOORD srch, long op)
251 {
252         ADDR16  dst;
253         ADDR16  src;
254         int     dlinelen = dstpsd->linelen;
255         int     slinelen = srcpsd->linelen;
256         int     i, ymax;
257         int     row_pos, row_inc;
258         int     col_pos, col_inc;
259         unsigned short pixel = 0;
260
261         assert (dstpsd->addr != 0);
262         assert (dstx >= 0 && dstx < dstpsd->xres);
263         assert (dsty >= 0 && dsty < dstpsd->yres);
264         assert (dstw > 0);
265         assert (dsth > 0);
266         assert (srcpsd->addr != 0);
267         assert (srcx >= 0 && srcx < srcpsd->xres);
268         assert (srcy >= 0 && srcy < srcpsd->yres);
269         assert (srcw > 0);
270         assert (srch > 0);
271         assert (dstx+dstw <= dstpsd->xres);
272         assert (dsty+dsth <= dstpsd->yres);
273         assert (srcx+srcw <= srcpsd->xres);
274         assert (srcy+srch <= srcpsd->yres);
275
276         DRAWON;
277         row_pos = 0x10000;
278 if (g_row_inc) row_inc = g_row_inc; else
279         row_inc = (srch << 16) / dsth;
280
281         /* stretch blit using integer ratio between src/dst height/width*/
282         for (ymax = dsty+dsth; dsty<ymax; ++dsty) {
283
284                 /* find source y position*/
285                 while (row_pos >= 0x10000L) {
286                         ++srcy;
287                         row_pos -= 0x10000L;
288                 }
289
290                 dst = (ADDR16)dstpsd->addr + dstx + dsty*dlinelen;
291                 src = (ADDR16)srcpsd->addr + srcx + (srcy-1)*slinelen;
292
293                 /* copy a row of pixels*/
294                 col_pos = 0x10000;
295 if (g_col_inc) col_inc = g_col_inc; else
296                 col_inc = (srcw << 16) / dstw;
297                 for (i=0; i<dstw; ++i) {
298                         /* get source x pixel*/
299                         while (col_pos >= 0x10000L) {
300                                 pixel = *src++;
301                                 col_pos -= 0x10000L;
302                         }
303                         *dst++ = pixel;
304                         col_pos += col_inc;
305                 }
306
307                 row_pos += row_inc;
308         }
309         DRAWOFF;
310 }
311
312 #if USE_DRAWAREA
313 /* temporarily removed DrawArea entry point code*/
314 static void init_alpha_lookup(unsigned short **low, unsigned short **high)
315 {
316         unsigned short a, x, *lo, *hi;
317         unsigned short r, g, b;
318         unsigned short idx;
319
320         lo = *low = malloc(32*256*2);
321         hi = *high = malloc(32*256*2);
322
323         if ( hi == 0 || lo == 0 )
324                 exit(17);
325
326         for ( a=0; a < 32; a++ )
327                 for ( x=0; x < 256; x++ ) {
328                         idx = (a << 8) | x;
329                         /* High byte */
330                         r = (x >> 3) * a / 31;
331                         g = ((x << 3) & 0x38) * a / 31;
332                         hi[idx] = (r << 11) | (g << 5);
333                         /* Low byte */
334                         b = (x & 0x1f) * a / 31;
335                         g = ((x >> 5) & 0x7) * a / 31;
336                         lo[idx] = (g << 5) | b;
337                 }
338 }
339
340 static void init_wordmask_lookup(unsigned short **byte2wordmask)
341 {
342         unsigned short *maskp, *b2wm;
343         int t, x, u;
344
345         b2wm = *byte2wordmask = malloc(256*8*2);
346         if ( b2wm == 0 )
347                 exit(17);
348         for ( t=0; t < 256; t++ ) {
349                 maskp = b2wm + 8 * t;
350                 x = t;
351                 for ( u=1; u < 256; u <<= 1 )
352                         if ( x & u )
353                                 *maskp++ = 0xffff;
354                         else
355                                 *maskp++ = 0x0000;
356         }
357 }
358
359 /* psd->DrawArea operation PSDOP_PIXMAP_COPYALL which takes a
360  * pixmap, each line is byte aligned, and copies it to the
361  * screen using fg_color and bg_color to replace a 1 and 0 in
362  * the pixmap.  This pixmap is ordered the wrong way around;
363  * it has the leftmost pixel (on the screen) in LSB (Bit 0)
364  * of the bytes.
365  *
366  * The reason why this non-intuitive bit ordering is used is
367  * to match the bit ordering used in the T1lib font rendering
368  * library.
369  *
370  * Variables used in the gc:
371  *       dstx, dsty, dsth, dstw   Destination rectangle
372  *       srcx, srcy               Source rectangle
373  *       src_linelen              Linesize in bytes of source
374  *       pixels                   Pixmap data
375  *       fg_color                 Color of a '1' bit
376  *       bg_color                 Color of a '0' bit
377  */
378
379 static void pixmap_copyall(PSD psd, driver_gc_t *gc)
380 {
381         int first_byte, last_byte;
382         int hard_prefix, hard_postfix;
383         unsigned short prefixbits, postfixbits, *maskp;
384         unsigned short xor_color, m;
385         unsigned short prefix_mask = 0, prefix_last = 0;
386         unsigned short postfix_mask = 0, postfix_last = 0;
387         int size_main, t, y;
388         unsigned int advance_src, advance_dst;
389         ADDR8 src;
390         ADDR16 dst;
391
392         static unsigned short *byte2wordmask = 0;
393
394         prefixbits = gc->srcx & 7;
395         postfixbits = (gc->srcx + gc->dstw - 1) & 7;
396         first_byte = gc->srcx >> 3;
397         last_byte = (gc->srcx + gc->dstw - 1) >> 3;
398
399         src = ((ADDR8)gc->pixels) + gc->src_linelen * gc->srcy + first_byte;
400         dst = ((ADDR16)psd->addr) + psd->linelen * gc->dsty + gc->dstx;
401         xor_color = gc->fg_color ^ gc->bg_color;
402
403         if ( first_byte != last_byte ) {
404                 if ( prefixbits == 0 ) {
405                         /* All bits of first byte used */
406                         hard_prefix = 0;
407                         size_main = last_byte - first_byte;
408                 } else {
409                         /* Needs to do a few odd bits first */
410                         hard_prefix = 1;
411                         size_main = last_byte - first_byte - 1;
412                         prefix_mask = 1 << prefixbits;
413                         prefix_last = 256;
414                 }
415                 if ( postfixbits != 7 ) {
416                         /* Last byte in source contains a few odd bits */
417                         hard_postfix = 1;
418                         postfix_mask = 1;
419                         postfix_last = 2 << postfixbits;
420                 } else {
421                         /* Last byte in source is used completely */
422                         hard_postfix = 0;
423                         size_main++;
424                 }
425         } else {
426                 /* Very narrow pixmap, fits in single first byte */
427                 hard_prefix = 1;
428                 hard_postfix = 0;
429                 size_main = 0;
430                 prefix_mask = 1 << prefixbits;
431                 prefix_last = 1 << (prefixbits + gc->dstw);
432         }
433
434         advance_src = gc->src_linelen - last_byte + first_byte - 1;
435         advance_dst = psd->linelen - gc->dstw;
436
437         if ( byte2wordmask == 0 )
438                 init_wordmask_lookup(&byte2wordmask);
439
440         DRAWON;
441         for ( y=0; y < gc->dsth; y++ ) {
442
443                 /* Do pixels of partial first byte */
444                 if ( hard_prefix ) {
445                         for ( m=prefix_mask; m < prefix_last; m <<= 1 ) {
446                                 if ( m & *src )
447                                         *dst++ = gc->fg_color;
448                                 else
449                                         *dst++ = gc->bg_color;
450                         }
451                         src++;
452                 }
453
454                 /* Do all pixles of main part one byte at a time */
455                 for ( t=0; t < size_main; t++ ) {       
456                         maskp = byte2wordmask + 8 * (*src++);
457
458                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
459                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
460                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
461                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
462                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
463                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
464                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
465                         *dst++ = gc->bg_color ^ (*maskp++ & xor_color);
466                 }
467
468                 /* Do last few bits of line */
469                 if ( hard_postfix ) {
470                         for ( m=postfix_mask; m < postfix_last; m <<= 1 ) {
471                                 if ( *src & m )
472                                         *dst++ = gc->fg_color;
473                                 else
474                                         *dst++ = gc->bg_color;
475                         }
476                         src++;
477                 }
478
479                 src += advance_src;
480                 dst += advance_dst;
481         }
482         DRAWOFF;
483 }
484
485
486 static unsigned short *low2scale = 0, *high2scale = 0;
487
488 static void drawarea_alphamap(PSD psd, driver_gc_t *gc)
489 {
490         ADDR8 src, dst, alpha;
491         unsigned short psl, psh, pd;
492         unsigned char as, ad;
493         int x, y;
494
495         if ( low2scale == 0 )
496                 init_alpha_lookup(&low2scale,&high2scale);
497
498         src = (ADDR8)(((ADDR16)gc->pixels) + gc->srcx +
499                       gc->src_linelen * gc->srcy);
500         dst = (ADDR8)(((ADDR16)psd->addr) +
501                       psd->linelen * gc->dsty + gc->dstx);
502         alpha = ((ADDR8)gc->misc) + gc->src_linelen * gc->srcy + gc->srcx;
503
504         DRAWON;
505         for ( y=0; y < gc->dsth; y++ ) {
506                 for ( x=0; x < gc->dstw; x++ ) {
507                         as = (*alpha++) >> 3;
508                         ad = 31 - as;
509                         psl = low2scale[(as<<8)|*src++];
510                         psh = high2scale[(as<<8)|*src++];
511                         pd = low2scale[(ad<<8)|dst[0]] +
512                                 high2scale[(ad<<8)|dst[1]];
513                         *((unsigned short *)dst)++ = psl + psh + pd;
514                 }
515         }
516         DRAWOFF;
517 }
518
519 static void drawarea_alphacol(PSD psd, driver_gc_t *gc)
520 {
521         ADDR8 dst, alpha;
522         unsigned short col_low, col_high, psl, psh, pd;
523         unsigned char as, ad;
524         int x, y;
525
526         if ( low2scale == 0 )
527                 init_alpha_lookup(&low2scale,&high2scale);
528
529         dst = (ADDR8)(((ADDR16)psd->addr) +
530                       psd->linelen * gc->dsty + gc->dstx);
531         alpha = ((ADDR8)gc->misc) + gc->src_linelen * gc->srcy + gc->srcx;
532         col_low = gc->bg_color & 0xff;
533         col_high = ( gc->bg_color >> 8 ) & 0xff;
534
535         DRAWON;
536         for ( y=0; y < gc->dsth; y++ ) {
537                 for ( x=0; x < gc->dstw; x++ ) {
538                         as = (*alpha++) >> 3;
539                         if ( as ) {
540                                 if ( (ad = 31 - as) ) {
541                                         psl = low2scale[(as<<8)|col_low];
542                                         psh = high2scale[(as<<8)|col_high];
543                                         pd = low2scale[(ad<<8)|dst[0]] +
544                                                 high2scale[(ad<<8)|dst[1]];
545                                         *((unsigned short *)dst)++ = psl + psh + pd;
546                                 } else {
547                                         *((unsigned short *)dst)++ = gc->bg_color;
548                                 }
549                         }
550                 }
551         }
552         DRAWOFF;
553 }
554
555 static void linear16_drawarea(PSD psd, driver_gc_t *gc, int op)
556 {
557         ADDR16  src16, dst, rsrc, rdst;
558         int linesize, x, y;
559         unsigned short pcol;
560
561         assert(psd->addr != 0);
562         /*assert(gc->dstw <= gc->srcw);*/
563         assert(gc->dstx >= 0 && gc->dstx+gc->dstw <= psd->xres);
564         /*assert(gc->dsty >= 0 && gc->dsty+gc->dsth <= psd->yres);*/
565         /*assert(gc->srcx >= 0 && gc->srcx+gc->dstw <= gc->srcw);*/
566         assert(gc->srcy >= 0);
567
568 #if 0
569         op = GD_AREA_COPY;
570         printf("DrawArea op=%d x=%d y=%d\n",op,gc->x,gc->y);
571 #endif
572
573         if ( op == PSDOP_COPY )
574                 op = gc->gr_usebg ? PSDOP_COPYALL : PSDOP_COPYTRANS;
575
576         switch ( op ) {
577                 case PSDOP_COPYALL:
578                         linesize = 2 * gc->dstw;
579                         src16 = ((ADDR16)gc->pixels) + gc->srcx +
580                                 gc->src_linelen * gc->srcy;
581                         dst = ((ADDR16)psd->addr) + gc->dstx + 
582                                 psd->linelen * gc->dsty;
583
584                         DRAWON;
585                         for ( y=1; y < gc->dsth; y++ ) {
586                                 memcpy(dst,src16,linesize);
587                                 src16 += gc->src_linelen;
588                                 dst += psd->linelen;
589                         }
590                         memcpy(dst,src16,linesize);     /* To be seriously ANSI */
591                         DRAWOFF;
592                         break;
593
594                 case PSDOP_COPYTRANS:
595                         src16 = ((ADDR16)gc->pixels) + gc->srcx +
596                                 gc->src_linelen * gc->srcy;
597                         dst = ((ADDR16)psd->addr) + gc->dstx +
598                                 psd->linelen * gc->dsty;
599
600                         DRAWON;
601                         for ( y=0; y < gc->dsth; y++ ) {
602                                 rdst = dst;
603                                 rsrc = src16;
604                                 for ( x=0; x < gc->dstw; x++ ) {
605                                         pcol = *rsrc++;
606                                         if ( pcol == gc->bg_color )
607                                                 rdst++;
608                                         else
609                                                 *rdst++ = pcol;
610                                 }
611                                 dst += psd->linelen;
612                                 src16 += gc->src_linelen;
613                         }
614                         DRAWOFF;
615                         break;
616
617                 case PSDOP_ALPHAMAP:
618                         drawarea_alphamap(psd,gc);
619                         break;
620
621                 case PSDOP_ALPHACOL:
622                         drawarea_alphacol(psd,gc);
623                         break;
624
625                 case PSDOP_PIXMAP_COPYALL:
626                         pixmap_copyall(psd,gc);
627                         break;
628
629         }
630 }
631 #endif /* USE_DRAWAREA*/
632
633 SUBDRIVER fblinear16 = {
634         linear16_init,
635         linear16_drawpixel,
636         linear16_readpixel,
637         linear16_drawhorzline,
638         linear16_drawvertline,
639         gen_fillrect,
640         linear16_blit,
641 #if USE_DRAWAREA
642         linear16_drawarea,
643 #else
644         NULL,
645 #endif
646         linear16_stretchblit
647 };