branch update for HEAD-2003050101
[reactos.git] / drivers / dd / vga / display / vgavideo / vgavideo.c
1 #include <ddk/ntddk.h>
2 #include <ddk/ntddvid.h>
3 #include <ddk/winddi.h>
4 #include <ntos/minmax.h>
5 #include "vgavideo.h"
6
7 UCHAR PreCalcReverseByte[256];
8 int maskbit[640];
9 int y80[480];
10 int xconv[640];
11 int bit8[640];
12 int startmasks[8];
13 int endmasks[8];
14 char* vidmem;
15
16 static unsigned char saved_SEQ_mask;    /* 0x02 */
17 static unsigned char saved_GC_eSR;      /* 0x01 */
18 static unsigned char saved_GC_fun;      /* 0x03 */
19 static unsigned char saved_GC_rmap;     /* 0x04 */
20 static unsigned char saved_GC_mode;     /* 0x05 */
21 static unsigned char saved_GC_mask;     /* 0x08 */
22 static unsigned char leftMask;
23 static int byteCounter;
24 static unsigned char rightMask;
25
26 INT abs(INT nm)
27 {
28   if(nm<0)
29   {
30     return nm * -1;
31   } else
32   {
33     return nm;
34   }
35 }
36
37 div_t div(int num, int denom)
38 {
39   div_t r;
40   if (num > 0 && denom < 0) {
41     num = -num;
42     denom = -denom;
43   }
44   r.quot = num / denom;
45   r.rem = num % denom;
46   if (num < 0 && denom > 0)
47   {
48     if (r.rem > 0)
49     {
50       r.quot++;
51       r.rem -= denom;
52     }
53   }
54   return r;
55 }
56
57 int mod(int num, int denom)
58 {
59   div_t dvt = div(num, denom);
60   return dvt.rem;
61 }
62
63 BYTE bytesPerPixel(ULONG Format)
64 {
65   // This function is taken from /subsys/win32k/eng/surface.c
66   // FIXME: GDI bitmaps are supposed to be pixel-packed. Right now if the
67   // pixel size if < 1 byte we expand it to 1 byte for simplicities sake
68
69   if(Format==BMF_1BPP)
70   {
71     return 1;
72   } else
73   if((Format==BMF_4BPP) || (Format==BMF_4RLE))
74   {
75     return 1;
76   } else
77   if((Format==BMF_8BPP) || (Format==BMF_8RLE))
78   {
79     return 1;
80   } else
81   if(Format==BMF_16BPP)
82   {
83     return 2;
84   } else
85   if(Format==BMF_24BPP)
86   {
87     return 3;
88   } else
89   if(Format==BMF_32BPP)
90   {
91     return 4;
92   }
93
94   return 0;
95 }
96
97 VOID vgaPreCalc()
98 {
99   ULONG j;
100
101   startmasks[0] = 255;
102   startmasks[1] = 1;
103   startmasks[2] = 3;
104   startmasks[3] = 7;
105   startmasks[4] = 15;
106   startmasks[5] = 31;
107   startmasks[6] = 63;
108   startmasks[7] = 127;
109   startmasks[8] = 255;
110
111   endmasks[0] = 128;
112   endmasks[1] = 192;
113   endmasks[2] = 224;
114   endmasks[3] = 240;
115   endmasks[4] = 248;
116   endmasks[5] = 252;
117   endmasks[6] = 254;
118   endmasks[7] = 255;
119   endmasks[8] = 255;
120
121   for(j=0; j<80; j++)
122   {
123     maskbit[j*8]   = 128;
124     maskbit[j*8+1] = 64;
125     maskbit[j*8+2] = 32;
126     maskbit[j*8+3] = 16;
127     maskbit[j*8+4] = 8;
128     maskbit[j*8+5] = 4;
129     maskbit[j*8+6] = 2;
130     maskbit[j*8+7] = 1;
131
132     bit8[j*8]   = 7;
133     bit8[j*8+1] = 6;
134     bit8[j*8+2] = 5;
135     bit8[j*8+3] = 4;
136     bit8[j*8+4] = 3;
137     bit8[j*8+5] = 2;
138     bit8[j*8+6] = 1;
139     bit8[j*8+7] = 0;
140   }
141   for(j=0; j<480; j++)
142   {
143     y80[j]  = j*80;
144   }
145   for(j=0; j<640; j++)
146   {
147     xconv[j] = j >> 3;
148   }
149
150   for (j = 0; j < 256; j++)
151     {
152       PreCalcReverseByte[j] = 
153         (((j >> 0) & 0x1) << 7) |
154         (((j >> 1) & 0x1) << 6) |
155         (((j >> 2) & 0x1) << 5) |
156         (((j >> 3) & 0x1) << 4) |
157         (((j >> 4) & 0x1) << 3) |
158         (((j >> 5) & 0x1) << 2) |
159         (((j >> 6) & 0x1) << 1) |
160         (((j >> 7) & 0x1) << 0);
161     }
162 }
163
164 void
165 get_masks(int x, int w)
166 {
167   register int tmp;
168
169   leftMask = rightMask = 0;
170   byteCounter = w;
171   /* right margin */
172   tmp = (x+w) & 7;
173   if (tmp) {
174     byteCounter -= tmp;
175     rightMask = (unsigned char)(0xff00 >> tmp);
176   }
177   /* left margin */
178   tmp = x & 7;
179   if (tmp) {
180     byteCounter -= (8 - tmp);
181     leftMask = (0xff >> tmp);
182   }
183   /* too small ? */
184   if (byteCounter < 0) {
185     leftMask &= rightMask;
186     rightMask = 0;
187     byteCounter = 0;
188   }
189   byteCounter /= 8;
190 }
191
192 VOID vgaPutPixel(INT x, INT y, UCHAR c)
193 {
194   ULONG offset;
195   UCHAR a;
196
197   offset = xconv[x]+y80[y];
198
199   WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);
200   WRITE_PORT_UCHAR((PUCHAR)0x3cf,maskbit[x]);
201
202   a = READ_REGISTER_UCHAR(vidmem + offset);
203   WRITE_REGISTER_UCHAR(vidmem + offset, c);
204 }
205
206 VOID vgaPutByte(INT x, INT y, UCHAR c)
207 {
208   ULONG offset;
209
210   offset = xconv[x]+y80[y];
211
212   // Set the write mode
213   WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);
214   WRITE_PORT_UCHAR((PUCHAR)0x3cf,0xff);
215
216   WRITE_REGISTER_UCHAR(vidmem + offset, c);
217 }
218
219 VOID vgaGetByte(ULONG offset,
220                 UCHAR *b, UCHAR *g,
221                 UCHAR *r, UCHAR *i)
222 {
223   WRITE_PORT_USHORT((PUSHORT)0x03ce, 0x0304);
224   *i = READ_REGISTER_UCHAR(vidmem + offset);
225   WRITE_PORT_USHORT((PUSHORT)0x03ce, 0x0204);
226   *r = READ_REGISTER_UCHAR(vidmem + offset);
227   WRITE_PORT_USHORT((PUSHORT)0x03ce, 0x0104);
228   *g = READ_REGISTER_UCHAR(vidmem + offset);
229   WRITE_PORT_USHORT((PUSHORT)0x03ce, 0x0004);
230   *b = READ_REGISTER_UCHAR(vidmem + offset);
231 }
232
233 INT vgaGetPixel(INT x, INT y)
234 {
235   UCHAR mask, b, g, r, i;
236   ULONG offset;
237
238   offset = xconv[x]+y80[y];
239   vgaGetByte(offset, &b, &g, &r, &i);
240
241   mask=maskbit[x];
242   b=b&mask;
243   g=g&mask;
244   r=r&mask;
245   i=i&mask;
246
247   mask=bit8[x];
248   g=g>>mask;
249   b=b>>mask;
250   r=r>>mask;
251   i=i>>mask;
252
253   return(b+2*g+4*r+8*i);
254 }
255
256 BOOL vgaHLine(INT x, INT y, INT len, UCHAR c)
257 {
258   UCHAR a;
259   ULONG pre1, i;
260   ULONG orgpre1, orgx, midpre1;
261   ULONG ileftpix, imidpix, irightpix;
262
263   orgx=x;
264
265   if(len<8)
266   {
267     for (i=x; i<x+len; i++)
268       vgaPutPixel(i, y, c);
269
270    return TRUE;
271   }
272
273   // Calculate the left mask pixels, middle bytes and right mask pixel
274   ileftpix = 8-mod(x, 8);
275   irightpix = mod(x+len, 8);
276   imidpix = (len-ileftpix-irightpix) / 8;
277
278   if(ileftpix == 8)
279   {
280     ileftpix = 0;
281     imidpix++;
282   }
283
284   pre1=xconv[x-(8-ileftpix)]+y80[y];
285   orgpre1=pre1;
286
287   // Left
288   if(ileftpix>0)
289   {
290     // Write left pixels
291     WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);     // set the mask
292     WRITE_PORT_UCHAR((PUCHAR)0x3cf,startmasks[ileftpix]);
293
294     a = READ_REGISTER_UCHAR(vidmem + pre1);
295     WRITE_REGISTER_UCHAR(vidmem + pre1, c);
296
297     // Prepare new x for the middle
298     x=orgx+8;
299   }
300
301   if(imidpix>0)
302   {
303     midpre1=xconv[x]+y80[y];
304
305     // Set mask to all pixels in byte
306     WRITE_PORT_UCHAR((PUCHAR)0x3ce, 0x08);
307     WRITE_PORT_UCHAR((PUCHAR)0x3cf, 0xff);
308     memset(vidmem+midpre1, c, imidpix); // write middle pixels, no need to read in latch because of the width
309   }
310
311   if(irightpix>0)
312   {
313     x=orgx+len-irightpix;
314
315     for(i=x; i<x+irightpix; i++)
316     {
317       vgaPutPixel(i, y, c);
318     }
319
320 /*  pre1=xconv[x]+y80[y];
321
322     // Write right pixels
323     WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);     // set the mask bits
324     WRITE_PORT_UCHAR((PUCHAR)0x3cf, endmasks[irightpix]);
325
326     a = READ_REGISTER_UCHAR(vidmem + pre1);
327     WRITE_REGISTER_UCHAR(vidmem + pre1, c); */
328   }
329
330   return TRUE;
331 }
332
333 BOOL vgaVLine(INT x, INT y, INT len, UCHAR c)
334 {
335   ULONG offset, i;
336   UCHAR a;
337
338   offset = xconv[x]+y80[y];
339
340   WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);       // set the mask
341   WRITE_PORT_UCHAR((PUCHAR)0x3cf,maskbit[x]);
342
343   for(i=y; i<y+len; i++)
344   {
345     a = READ_REGISTER_UCHAR(vidmem + offset);
346     WRITE_REGISTER_UCHAR(vidmem + offset, c);
347     offset+=80;
348   }
349
350   return TRUE;
351 }
352
353 static const RECTL rclEmpty = { 0, 0, 0, 0 };
354
355 BOOL VGADDIIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
356 {
357   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
358   prcDst->right = min(prcSrc1->right, prcSrc2->right);
359
360   if (prcDst->left < prcDst->right) {
361       prcDst->top = max(prcSrc1->top, prcSrc2->top);
362       prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
363
364      if (prcDst->top < prcDst->bottom)
365      {
366        return TRUE;
367      }
368   }
369
370   *prcDst = rclEmpty;
371
372   return FALSE;
373 }
374
375 void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
376
377 //  DIB blt from the VGA.
378 //  For now we just do slow reads -- pixel by pixel, packing each one into the correct 4BPP format.
379 {
380   PBYTE  pb = b, opb = b;
381   BOOLEAN  edgePixel = FALSE;
382   ULONG  i, j;
383   ULONG  x2 = x + w;
384   ULONG  y2 = y + h;
385   BYTE  b1, b2;
386
387   // Check if the width is odd
388   if(mod(w, 2)>0)
389   {
390     edgePixel = TRUE;
391     x2 -= 1;
392   }
393
394   for (j=y; j<y2; j++)
395   {
396     for (i=x; i<x2; i+=2)
397     {
398       b1 = vgaGetPixel(i,  j);
399       b2 = vgaGetPixel(i+1,  j);
400       *pb = b2 | (b1 << 4);
401       pb++;
402     }
403
404     if(edgePixel == TRUE)
405     {
406       b1 = vgaGetPixel(x2, j);
407       *pb = b1;
408       pb++;
409     }
410
411     opb += Dest_lDelta; // new test code
412     pb = opb; // new test code
413   }
414 }
415
416 void DIB_BltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta)
417
418 //  DIB blt to the VGA.
419 //  For now we just do slow writes -- pixel by pixel, packing each one into the correct 4BPP format.
420 {
421   PBYTE  pb = b, opb = b;
422   BOOLEAN  edgePixel = FALSE;
423   ULONG  i, j;
424   ULONG  x2 = x + w;
425   ULONG  y2 = y + h;
426   BYTE  b1, b2;
427
428   // Check if the width is odd
429   if(mod(w, 2)>0)
430   {
431     edgePixel = TRUE;
432     x2 -= 1;
433   }
434
435   for (j=y; j<y2; j++)
436   {
437     for (i=x; i<x2; i+=2)
438     {
439       b1 = (*pb & 0xf0) >> 4;
440       b2 = *pb & 0x0f;
441       vgaPutPixel(i,   j, b1);
442       vgaPutPixel(i+1, j, b2);
443       pb++;
444     }
445
446     if(edgePixel == TRUE)
447     {
448       b1 = *pb;
449       vgaPutPixel(x2, j, b1);
450       pb++;
451     }
452
453     opb += Source_lDelta;
454
455     pb = opb;
456
457   }
458 }
459
460 void DIB_TransparentBltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, ULONG trans)
461
462 //  DIB blt to the VGA.
463 //  For now we just do slow writes -- pixel by pixel, packing each one into the correct 4BPP format.
464 {
465   PBYTE  pb = b, opb = b;
466   BOOLEAN  edgePixel = FALSE;
467   ULONG  i, j;
468   ULONG  x2 = x + w;
469   ULONG  y2 = y + h;
470   BYTE  b1, b2;
471
472   // Check if the width is odd
473   if(mod(w, 2)>0)
474   {
475     edgePixel = TRUE;
476     x2 -= 1;
477   }
478
479   for (j=y; j<y2; j++)
480   {
481     for (i=x; i<x2; i+=2)
482     {
483       b1 = (*pb & 0xf0) >> 4;
484       b2 = *pb & 0x0f;
485       if(b1 != trans) vgaPutPixel(i,   j, b1);
486       if(b2 != trans) vgaPutPixel(i+1, j, b2);
487       pb++;
488     }
489
490     if(edgePixel == TRUE)
491     {
492       b1 = *pb;
493       if(b1 != trans) vgaPutPixel(x2, j, b1);
494       pb++;
495     }
496
497     opb += Source_lDelta;
498     pb = opb; // new test code
499
500   }
501 }
502
503 void DFB_BltFromVGA(int x, int y, int w, int h, void *b, int bw)
504
505 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
506 //  It also stores each 4BPP pixel in an entire byte.
507 {
508   unsigned char *vp, *vpY, *vpP;
509   unsigned char data, mask, maskP;
510   unsigned char *bp, *bpY;
511   unsigned char plane_mask;
512   int byte_per_line = SCREEN_X >> 3;
513   int plane, i, j;
514
515   ASSIGNVP4(x, y, vpP)
516   ASSIGNMK4(x, y, maskP)
517   get_masks(x, w);
518   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);  // read mode 0
519   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
520   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);  // read map select
521
522   // clear buffer
523   bp=b;
524   for (j=h; j>0; j--) {
525     memset(bp, 0, w);
526     bp += bw;
527   }
528
529   for (plane=0, plane_mask=1; plane<4; plane++, plane_mask<<=1) {
530     WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);  // read map select
531     vpY = vpP;
532     bpY = b;
533     for (j=h; j>0; j--) {
534       vp = vpY;
535       bp = bpY;
536       if (leftMask) {
537         mask = maskP;
538         data = *vp++;
539         do {
540           if (data & mask) *bp |= plane_mask;
541           bp++;
542           mask >>= 1;
543         } while (mask & leftMask);
544
545       }
546       if (byteCounter) {
547         for (i=byteCounter; i>0; i--) {
548           data = *vp++;
549           if (data & 0x80) *bp |= plane_mask;
550           bp++;
551           if (data & 0x40) *bp |= plane_mask;
552           bp++;
553           if (data & 0x20) *bp |= plane_mask;
554           bp++;
555           if (data & 0x10) *bp |= plane_mask;
556           bp++;
557           if (data & 0x08) *bp |= plane_mask;
558           bp++;
559           if (data & 0x04) *bp |= plane_mask;
560           bp++;
561           if (data & 0x02) *bp |= plane_mask;
562           bp++;
563           if (data & 0x01) *bp |= plane_mask;
564           bp++;
565         }
566       }
567       if (rightMask) {
568         mask = 0x80;
569         data = *vp;
570         do {
571           if (data & mask) *bp |= plane_mask;
572           bp++;
573           mask >>= 1;
574         } while (mask & rightMask);
575       }
576       bpY += bw;
577       vpY += byte_per_line;
578     }
579   }
580
581   // We don't need this if the next call is a DFB blt to VGA (as in the case of moving the mouse pointer)
582   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
583   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
584   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
585   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
586 }
587
588 void DFB_BltToVGA(int x, int y, int w, int h, void *b, int bw)
589
590 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
591 //  It also stores each 4BPP pixel in an entire byte.
592 {
593   unsigned char *bp, *bpX;
594   unsigned char *vp, *vpX;
595   unsigned char mask;
596   volatile unsigned char dummy;
597   int byte_per_line;
598   int i, j;
599
600   bpX = b;
601   ASSIGNVP4(x, y, vpX)
602   ASSIGNMK4(x, y, mask)
603   byte_per_line = SCREEN_X >> 3;
604
605   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
606   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
607   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
608   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
609   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
610
611   for (i=w; i>0; i--) {
612     WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
613     bp = bpX;
614     vp = vpX;
615     for (j=h; j>0; j--) {
616       dummy = *vp;
617       *vp = *bp;
618       bp += bw;
619       vp += byte_per_line;
620     }
621     bpX++;
622     if ((mask >>= 1) == 0) {
623       vpX++;
624       mask = 0x80;
625     }
626   }
627 }
628
629 void DFB_BltToVGA_Transparent(int x, int y, int w, int h, void *b, int bw, char Trans)
630
631 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
632 //  It also stores each 4BPP pixel in an entire byte.
633 {
634   unsigned char *bp, *bpX;
635   unsigned char *vp, *vpX;
636   unsigned char mask;
637   volatile unsigned char dummy;
638   int byte_per_line;
639   int i, j;
640
641   bpX = b;
642   ASSIGNVP4(x, y, vpX)
643   ASSIGNMK4(x, y, mask)
644   byte_per_line = SCREEN_X >> 3;
645
646   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
647   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
648   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
649   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
650   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
651
652   for (i=w; i>0; i--) {
653     WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
654     bp = bpX;
655     vp = vpX;
656     for (j=h; j>0; j--) {
657       if (*bp != Trans)
658       {
659         dummy = *vp;
660         *vp = *bp;
661       }
662       bp += bw;
663       vp += byte_per_line;
664     }
665     bpX++;
666     if ((mask >>= 1) == 0) {
667       vpX++;
668       mask = 0x80;
669     }
670   }
671 }
672
673 void DFB_BltToDIB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
674
675 // This algorithm converts a DFB into a DIB
676 // WARNING: This algorithm is buggy
677 {
678   unsigned char *bp, *bpX, *dib, *dibTmp;
679   int i, j, dib_shift;
680
681   bpX = b;
682   dib = bdib + y * dibw + (x / 2);
683
684   for (i=w; i>0; i--) {
685
686     // determine the bit shift for the DIB pixel
687     dib_shift = mod(w-i, 2);
688     if(dib_shift > 0) dib_shift = 4;
689     dibTmp = dib;
690
691     bp = bpX;
692     for (j=h; j>0; j--) {
693       *dibTmp = *bp << dib_shift | *(bp + 1);
694       dibTmp += dibw;
695       bp += bw;
696     }
697     bpX++;
698     if(dib_shift == 0) dib++;
699   }
700 }
701
702
703 void DIB_BltToDFB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
704
705 // This algorithm converts a DIB into a DFB
706 {
707   unsigned char *bp, *bpX, *dib, *dibTmp;
708   int i, j, dib_shift, dib_and;
709
710   bpX = b;
711   dib = bdib + y * dibw + (x / 2);
712
713   for (i=w; i>0; i--) {
714
715     // determine the bit shift for the DIB pixel
716     dib_shift = mod(w-i, 2);
717     if(dib_shift > 0) {
718       dib_shift = 0;
719       dib_and = 0x0f;
720     } else {
721       dib_shift = 4;
722       dib_and = 0xf0;
723     }
724
725     dibTmp = dib;
726     bp = bpX;
727
728     for (j=h; j>0; j--) {
729       *bp = (*dibTmp & dib_and) >> dib_shift;
730       dibTmp += dibw;
731       bp += bw;
732     }
733
734     bpX++;
735     if(dib_shift == 0) dib++;
736   }
737 }