:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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   } else {
270
271     // Calculate the left mask pixels, middle bytes and right mask pixel
272     ileftpix = 8-mod(x, 8);
273     irightpix = mod(x+len, 8);
274     imidpix = (len-ileftpix-irightpix) / 8;
275
276     pre1=xconv[x-(8-ileftpix)]+y80[y];
277     orgpre1=pre1;
278
279     // Left
280     if(ileftpix>0)
281     {
282       // Write left pixels
283       WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);     // set the mask
284       WRITE_PORT_UCHAR((PUCHAR)0x3cf,startmasks[ileftpix]);
285
286       a = READ_REGISTER_UCHAR(vidmem + pre1);
287       WRITE_REGISTER_UCHAR(vidmem + pre1, c);
288
289       // Prepare new x for the middle
290       x=orgx+8;
291     }
292
293     if(imidpix>0)
294     {
295       midpre1=xconv[x]+y80[y];
296
297       // Set mask to all pixels in byte
298       WRITE_PORT_UCHAR((PUCHAR)0x3ce, 0x08);
299       WRITE_PORT_UCHAR((PUCHAR)0x3cf, 0xff);
300       memset(vidmem+midpre1, c, imidpix); // write middle pixels, no need to read in latch because of the width
301     }
302
303     x=orgx+len-irightpix;
304     pre1=xconv[x]+y80[y];
305
306     // Write right pixels
307     WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);     // set the mask bits
308     WRITE_PORT_UCHAR((PUCHAR)0x3cf, endmasks[irightpix]);
309
310     a = READ_REGISTER_UCHAR(vidmem + pre1);
311     WRITE_REGISTER_UCHAR(vidmem + pre1, c);
312   }
313
314   return TRUE;
315 }
316
317 BOOL vgaVLine(INT x, INT y, INT len, UCHAR c)
318 {
319   ULONG offset, i;
320   UCHAR a;
321
322   offset = xconv[x]+y80[y];
323
324   WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);       // set the mask
325   WRITE_PORT_UCHAR((PUCHAR)0x3cf,maskbit[x]);
326
327   len++;
328
329   for(i=y; i<y+len; i++)
330   {
331     a = READ_REGISTER_UCHAR(vidmem + offset);
332     WRITE_REGISTER_UCHAR(vidmem + offset, c);
333     offset+=80;
334   }
335
336   return TRUE;
337 }
338
339 static const RECTL rclEmpty = { 0, 0, 0, 0 };
340
341 BOOL VGADDIIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
342 {
343   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
344   prcDst->right = min(prcSrc1->right, prcSrc2->right);
345
346   if (prcDst->left < prcDst->right) {
347       prcDst->top = max(prcSrc1->top, prcSrc2->top);
348       prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
349
350      if (prcDst->top < prcDst->bottom)
351      {
352        return TRUE;
353      }
354   }
355
356   *prcDst = rclEmpty;
357
358   return FALSE;
359 }
360
361 void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
362
363 //  DIB blt from the VGA.
364 //  For now we just do slow reads -- pixel by pixel, packing each one into the correct 4BPP format.
365 {
366   PBYTE  pb = b, opb = b;
367   BOOLEAN  edgePixel = FALSE;
368   ULONG  i, j;
369   ULONG  x2 = x + w;
370   ULONG  y2 = y + h;
371   BYTE  b1, b2;
372
373   // Check if the width is odd
374   if(mod(w, 2)>0)
375   {
376     edgePixel = TRUE;
377     x2 -= 1;
378   }
379
380   for (j=y; j<y2; j++)
381   {
382     for (i=x; i<x2; i+=2)
383     {
384       b1 = vgaGetPixel(i,  j);
385       b2 = vgaGetPixel(i+1,  j);
386       *pb = b2 | (b1 << 4);
387       pb++;
388     }
389
390     if(edgePixel == TRUE)
391     {
392       b1 = vgaGetPixel(x2, j);
393       *pb = b1;
394       pb++;
395     }
396
397     opb += Dest_lDelta; // new test code
398     pb = opb; // new test code
399   }
400 }
401
402 void DIB_BltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta)
403
404 //  DIB blt to the VGA.
405 //  For now we just do slow writes -- pixel by pixel, packing each one into the correct 4BPP format.
406 {
407   PBYTE  pb = b, opb = b;
408   BOOLEAN  edgePixel = FALSE;
409   ULONG  i, j;
410   ULONG  x2 = x + w;
411   ULONG  y2 = y + h;
412   BYTE  b1, b2;
413
414   // Check if the width is odd
415   if(mod(w, 2)>0)
416   {
417     edgePixel = TRUE;
418     x2 -= 1;
419   }
420
421   for (j=y; j<y2; j++)
422   {
423     for (i=x; i<x2; i+=2)
424     {
425       b1 = (*pb & 0xf0) >> 4;
426       b2 = *pb & 0x0f;
427       vgaPutPixel(i,   j, b1);
428       vgaPutPixel(i+1, j, b2);
429       pb++;
430     }
431
432     if(edgePixel == TRUE)
433     {
434       b1 = *pb;
435       vgaPutPixel(x2, j, b1);
436       pb++;
437     }
438
439     opb += Source_lDelta;
440
441     pb = opb;
442
443   }
444 }
445
446 void DIB_TransparentBltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, ULONG trans)
447
448 //  DIB blt to the VGA.
449 //  For now we just do slow writes -- pixel by pixel, packing each one into the correct 4BPP format.
450 {
451   PBYTE  pb = b, opb = b;
452   BOOLEAN  edgePixel = FALSE;
453   ULONG  i, j;
454   ULONG  x2 = x + w;
455   ULONG  y2 = y + h;
456   BYTE  b1, b2;
457
458   // Check if the width is odd
459   if(mod(w, 2)>0)
460   {
461     edgePixel = TRUE;
462     x2 -= 1;
463   }
464
465   for (j=y; j<y2; j++)
466   {
467     for (i=x; i<x2; i+=2)
468     {
469       b1 = (*pb & 0xf0) >> 4;
470       b2 = *pb & 0x0f;
471       if(b1 != trans) vgaPutPixel(i,   j, b1);
472       if(b2 != trans) vgaPutPixel(i+1, j, b2);
473       pb++;
474     }
475
476     if(edgePixel == TRUE)
477     {
478       b1 = *pb;
479       if(b1 != trans) vgaPutPixel(x2, j, b1);
480       pb++;
481     }
482
483     opb += Source_lDelta;
484     pb = opb; // new test code
485
486   }
487 }
488
489 void DFB_BltFromVGA(int x, int y, int w, int h, void *b, int bw)
490
491 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
492 //  It also stores each 4BPP pixel in an entire byte.
493 {
494   unsigned char *vp, *vpY, *vpP;
495   unsigned char data, mask, maskP;
496   unsigned char *bp, *bpY;
497   unsigned char plane_mask;
498   int byte_per_line = SCREEN_X >> 3;
499   int plane, i, j;
500
501   ASSIGNVP4(x, y, vpP)
502   ASSIGNMK4(x, y, maskP)
503   get_masks(x, w);
504   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);  // read mode 0
505   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
506   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);  // read map select
507
508   // clear buffer
509   bp=b;
510   for (j=h; j>0; j--) {
511     memset(bp, 0, w);
512     bp += bw;
513   }
514
515   for (plane=0, plane_mask=1; plane<4; plane++, plane_mask<<=1) {
516     WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);  // read map select
517     vpY = vpP;
518     bpY = b;
519     for (j=h; j>0; j--) {
520       vp = vpY;
521       bp = bpY;
522       if (leftMask) {
523         mask = maskP;
524         data = *vp++;
525         do {
526           if (data & mask) *bp |= plane_mask;
527           bp++;
528           mask >>= 1;
529         } while (mask & leftMask);
530
531       }
532       if (byteCounter) {
533         for (i=byteCounter; i>0; i--) {
534           data = *vp++;
535           if (data & 0x80) *bp |= plane_mask;
536           bp++;
537           if (data & 0x40) *bp |= plane_mask;
538           bp++;
539           if (data & 0x20) *bp |= plane_mask;
540           bp++;
541           if (data & 0x10) *bp |= plane_mask;
542           bp++;
543           if (data & 0x08) *bp |= plane_mask;
544           bp++;
545           if (data & 0x04) *bp |= plane_mask;
546           bp++;
547           if (data & 0x02) *bp |= plane_mask;
548           bp++;
549           if (data & 0x01) *bp |= plane_mask;
550           bp++;
551         }
552       }
553       if (rightMask) {
554         mask = 0x80;
555         data = *vp;
556         do {
557           if (data & mask) *bp |= plane_mask;
558           bp++;
559           mask >>= 1;
560         } while (mask & rightMask);
561       }
562       bpY += bw;
563       vpY += byte_per_line;
564     }
565   }
566
567   // We don't need this if the next call is a DFB blt to VGA (as in the case of moving the mouse pointer)
568   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
569   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
570   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
571   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
572 }
573
574 void DFB_BltToVGA(int x, int y, int w, int h, void *b, int bw)
575
576 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
577 //  It also stores each 4BPP pixel in an entire byte.
578 {
579   unsigned char *bp, *bpX;
580   unsigned char *vp, *vpX;
581   unsigned char mask;
582   volatile unsigned char dummy;
583   int byte_per_line;
584   int i, j;
585
586   bpX = b;
587   ASSIGNVP4(x, y, vpX)
588   ASSIGNMK4(x, y, mask)
589   byte_per_line = SCREEN_X >> 3;
590
591   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
592   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
593   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
594   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
595   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
596
597   for (i=w; i>0; i--) {
598     WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
599     bp = bpX;
600     vp = vpX;
601     for (j=h; j>0; j--) {
602       dummy = *vp;
603       *vp = *bp;
604       bp += bw;
605       vp += byte_per_line;
606     }
607     bpX++;
608     if ((mask >>= 1) == 0) {
609       vpX++;
610       mask = 0x80;
611     }
612   }
613 }
614
615 void DFB_BltToVGA_Transparent(int x, int y, int w, int h, void *b, int bw, char Trans)
616
617 //  This algorithm goes from goes from left to right, and inside that loop, top to bottom.
618 //  It also stores each 4BPP pixel in an entire byte.
619 {
620   unsigned char *bp, *bpX;
621   unsigned char *vp, *vpX;
622   unsigned char mask;
623   volatile unsigned char dummy;
624   int byte_per_line;
625   int i, j;
626
627   bpX = b;
628   ASSIGNVP4(x, y, vpX)
629   ASSIGNMK4(x, y, mask)
630   byte_per_line = SCREEN_X >> 3;
631
632   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
633   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
634   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
635   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
636   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
637
638   for (i=w; i>0; i--) {
639     WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
640     bp = bpX;
641     vp = vpX;
642     for (j=h; j>0; j--) {
643       if (*bp != Trans)
644       {
645         dummy = *vp;
646         *vp = *bp;
647       }
648       bp += bw;
649       vp += byte_per_line;
650     }
651     bpX++;
652     if ((mask >>= 1) == 0) {
653       vpX++;
654       mask = 0x80;
655     }
656   }
657 }
658
659 void DFB_BltToDIB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
660
661 // This algorithm converts a DFB into a DIB
662 // WARNING: This algorithm is buggy
663 {
664   unsigned char *bp, *bpX, *dib, *dibTmp;
665   int i, j, dib_shift;
666
667   bpX = b;
668   dib = bdib + y * dibw + (x / 2);
669
670   for (i=w; i>0; i--) {
671
672     // determine the bit shift for the DIB pixel
673     dib_shift = mod(w-i, 2);
674     if(dib_shift > 0) dib_shift = 4;
675     dibTmp = dib;
676
677     bp = bpX;
678     for (j=h; j>0; j--) {
679       *dibTmp = *bp << dib_shift | *(bp + 1);
680       dibTmp += dibw;
681       bp += bw;
682     }
683     bpX++;
684     if(dib_shift == 0) dib++;
685   }
686 }
687
688
689 void DIB_BltToDFB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
690
691 // This algorithm converts a DIB into a DFB
692 {
693   unsigned char *bp, *bpX, *dib, *dibTmp;
694   int i, j, dib_shift, dib_and;
695
696   bpX = b;
697   dib = bdib + y * dibw + (x / 2);
698
699   for (i=w; i>0; i--) {
700
701     // determine the bit shift for the DIB pixel
702     dib_shift = mod(w-i, 2);
703     if(dib_shift > 0) {
704       dib_shift = 0;
705       dib_and = 0x0f;
706     } else {
707       dib_shift = 4;
708       dib_and = 0xf0;
709     }
710
711     dibTmp = dib;
712     bp = bpX;
713
714     for (j=h; j>0; j--) {
715       *bp = (*dibTmp & dib_and) >> dib_shift;
716       dibTmp += dibw;
717       bp += bw;
718     }
719
720     bpX++;
721     if(dib_shift == 0) dib++;
722   }
723 }