2 * PROJECT: ReactOS VGA display driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/video/displays/vga/vgavideo/vgavideo.c
11 UCHAR PreCalcReverseByte
[256];
19 static ULONG UnpackPixel
[256];
21 static unsigned char leftMask
;
22 static int byteCounter
;
23 static unsigned char rightMask
;
25 UCHAR
bytesPerPixel(ULONG Format
)
27 /* This function is taken from /subsys/win32k/eng/surface.c
28 * FIXME: GDI bitmaps are supposed to be pixel-packed. Right now if the
29 * pixel size if < 1 byte we expand it to 1 byte for simplicities sake */
80 for (j
= 0; j
< 80; j
++)
100 for (j
= 0; j
< SCREEN_Y
; j
++)
102 for (j
= 0; j
< SCREEN_X
; j
++)
105 for (j
= 0; j
< 256; j
++)
107 PreCalcReverseByte
[j
] =
108 (((j
>> 0) & 0x1) << 7) |
109 (((j
>> 1) & 0x1) << 6) |
110 (((j
>> 2) & 0x1) << 5) |
111 (((j
>> 3) & 0x1) << 4) |
112 (((j
>> 4) & 0x1) << 3) |
113 (((j
>> 5) & 0x1) << 2) |
114 (((j
>> 6) & 0x1) << 1) |
115 (((j
>> 7) & 0x1) << 0);
118 for (j
= 0; j
< 256; j
++)
121 (((j
>> 0) & 0x1) << 4) |
122 (((j
>> 1) & 0x1) << 0) |
123 (((j
>> 2) & 0x1) << 12) |
124 (((j
>> 3) & 0x1) << 8) |
125 (((j
>> 4) & 0x1) << 20) |
126 (((j
>> 5) & 0x1) << 16) |
127 (((j
>> 6) & 0x1) << 28) |
128 (((j
>> 7) & 0x1) << 24);
133 get_masks(int x
, int w
)
137 leftMask
= rightMask
= 0;
144 rightMask
= (unsigned char)(0xff00 >> tmp
);
150 byteCounter
-= (8 - tmp
);
151 leftMask
= (0xff >> tmp
);
156 leftMask
&= rightMask
;
163 VOID
vgaPutPixel(INT x
, INT y
, UCHAR c
)
167 offset
= xconv
[x
]+y80
[y
];
169 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08);
170 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
,maskbit
[x
]);
172 READ_REGISTER_UCHAR(vidmem
+ offset
);
173 WRITE_REGISTER_UCHAR(vidmem
+ offset
, c
);
176 VOID
vgaPutByte(INT x
, INT y
, UCHAR c
)
180 offset
= xconv
[x
]+y80
[y
];
182 /* Set the write mode */
183 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08);
184 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
,0xff);
186 WRITE_REGISTER_UCHAR(vidmem
+ offset
, c
);
196 WRITE_PORT_USHORT((PUSHORT
)GRA_I
, 0x0304);
197 *i
= READ_REGISTER_UCHAR(vidmem
+ offset
);
198 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x02);
199 *r
= READ_REGISTER_UCHAR(vidmem
+ offset
);
200 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x01);
201 *g
= READ_REGISTER_UCHAR(vidmem
+ offset
);
202 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
203 *b
= READ_REGISTER_UCHAR(vidmem
+ offset
);
210 UCHAR mask
, b
, g
, r
, i
;
213 offset
= xconv
[x
] + y80
[y
];
214 vgaGetByte(offset
, &b
, &g
, &r
, &i
);
228 return (b
+ 2 * g
+ 4 * r
+ 8 * i
);
231 BOOL
vgaHLine(INT x
, INT y
, INT len
, UCHAR c
)
233 ULONG orgx
, pre1
, midpre1
;
235 LONG ileftpix
, imidpix
, irightpix
;
241 for (i = x; i < x+len; i++ )
242 vgaPutPixel ( i, y, c );
247 /* Calculate the left mask pixels, middle bytes and right mask pixel */
248 ileftpix
= 7 - mod8(x
-1);
249 irightpix
= mod8(x
+len
);
250 imidpix
= (len
-ileftpix
-irightpix
) / 8;
252 pre1
= xconv
[(x
-1)&~7] + y80
[y
];
255 /* check for overlap ( very short line ) */
256 if ( (ileftpix
+irightpix
) > len
)
258 int mask
= startmasks
[ileftpix
] & endmasks
[irightpix
];
259 /* Write left pixels */
260 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08); // set the mask
261 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
,mask
);
263 READ_REGISTER_UCHAR(vidmem
+ pre1
);
264 WRITE_REGISTER_UCHAR(vidmem
+ pre1
, c
);
272 /* Write left pixels */
273 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08); // set the mask
274 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
,startmasks
[ileftpix
]);
276 READ_REGISTER_UCHAR(vidmem
+ pre1
);
277 WRITE_REGISTER_UCHAR(vidmem
+ pre1
, c
);
279 /* Prepare new x for the middle */
285 midpre1
= xconv
[x
] + y80
[y
];
287 /* Set mask to all pixels in byte */
288 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08);
289 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0xff);
290 memset(vidmem
+midpre1
, c
, imidpix
); // write middle pixels, no need to read in latch because of the width
295 x
= orgx
+ len
- irightpix
;
296 pre1
= xconv
[x
] + y80
[y
];
298 /* Write right pixels */
299 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08); // set the mask bits
300 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, endmasks
[irightpix
]);
301 READ_REGISTER_UCHAR(vidmem
+ pre1
);
302 WRITE_REGISTER_UCHAR(vidmem
+ pre1
, c
);
308 BOOL
vgaVLine(INT x
, INT y
, INT len
, UCHAR c
)
312 offset
= xconv
[x
]+y80
[y
];
315 vgaSetBitMaskRegister ( maskbit
[x
] );
317 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
,0x08); // set the mask
318 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
,maskbit
[x
]);
321 for(i
=y
; i
<y
+len
; i
++)
323 READ_REGISTER_UCHAR(vidmem
+ offset
);
324 WRITE_REGISTER_UCHAR(vidmem
+ offset
, c
);
331 static const RECTL rclEmpty
= { 0, 0, 0, 0 };
333 BOOL
VGADDIIntersectRect(PRECTL prcDst
, PRECTL prcSrc1
, PRECTL prcSrc2
)
335 prcDst
->left
= max(prcSrc1
->left
, prcSrc2
->left
);
336 prcDst
->right
= min(prcSrc1
->right
, prcSrc2
->right
);
338 if (prcDst
->left
< prcDst
->right
)
340 prcDst
->top
= max(prcSrc1
->top
, prcSrc2
->top
);
341 prcDst
->bottom
= min(prcSrc1
->bottom
, prcSrc2
->bottom
);
343 if (prcDst
->top
< prcDst
->bottom
)
352 void DIB_BltFromVGA(int x
, int y
, int w
, int h
, void *b
, int Dest_lDelta
)
356 ULONG shift
= x
- (x
& ~0x7);
357 UCHAR pixel
, nextpixel
;
360 LONG stride
= w
>> 3;
362 /* Calculate the number of rightmost bytes not in a dword block. */
373 /* Reset the destination. */
374 for (j
= 0; j
< h
; j
++)
375 memset((PVOID
)((ULONG_PTR
)b
+ (j
* Dest_lDelta
)), 0, abs(Dest_lDelta
));
377 for (plane
= 0; plane
< 4; plane
++)
381 /* Select the plane we are reading in this iteration. */
382 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x04);
383 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, plane
);
385 for (j
= 0; j
< h
; j
++)
387 PULONG destline
= (PULONG
)dest
;
388 PUCHAR src
= vidmem
+ (y
+ j
) * SCREEN_STRIDE
+ left
;
389 /* Read the data for one plane for an eight aligned pixel block. */
390 nextpixel
= PreCalcReverseByte
[READ_REGISTER_UCHAR(src
)];
391 for (i
= 0; i
< stride
; i
++, src
++, destline
++)
393 /* Form the data for one plane for an aligned block in the destination. */
397 nextpixel
= PreCalcReverseByte
[READ_REGISTER_UCHAR(src
+ 1)];
398 pixel
|= (nextpixel
<< (8 - shift
));
400 /* Expand the plane data to 'chunky' format and store. */
401 *destline
|= (UnpackPixel
[pixel
] << plane
);
403 /* Handle any pixels not falling into a full block. */
408 /* Form the data for a complete block. */
412 nextpixel
= PreCalcReverseByte
[READ_REGISTER_UCHAR(src
+ 1)];
413 pixel
|= (nextpixel
<< (8 - shift
));
415 row
= UnpackPixel
[pixel
] << plane
;
417 /* Store the data for each pixel in the destination. */
418 for (i
= 0; i
< rightcount
; i
++)
420 ((PUCHAR
)destline
)[i
] |= (row
& 0xFF);
429 for (j
= 0; j
< h
; j
++)
431 for (i
= 0; i
< w
; i
+= 2)
434 ULONG mask
= (i
< (w
- 1)) ? 0xFF : 0xF0;
436 c1
= (vgaGetPixel(x
+ i
, y
+ j
) << 4) | (vgaGetPixel(x
+ i
+ 1, y
+ j
));
437 c2
= ((PUCHAR
)b
)[(j
* Dest_lDelta
) + (i
>> 1)];
438 if ((c1
& mask
) != (c2
& mask
))
442 #endif /* VGA_VERIFY */
445 /* DIB blt to the VGA. */
446 void DIB_BltToVGA(int x
, int y
, int w
, int h
, void *b
, int Source_lDelta
, int StartMod
)
454 for (i
= x
; i
< x2
; i
++)
457 offset
= xconv
[i
] + y80
[y
];
459 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08); // set the mask
460 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, maskbit
[i
]);
462 if (StartMod
== ((i
- x
) % 2))
464 for (j
= y
; j
< y2
; j
++)
466 READ_REGISTER_UCHAR(vidmem
+ offset
);
467 WRITE_REGISTER_UCHAR(vidmem
+ offset
, (*pb
& 0xf0) >> 4);
474 for (j
= y
; j
< y2
; j
++)
476 READ_REGISTER_UCHAR(vidmem
+ offset
);
477 WRITE_REGISTER_UCHAR(vidmem
+ offset
, *pb
& 0x0f);
483 if (StartMod
!= ((i
- x
) % 2))
489 /* DIB blt to the VGA. */
490 void DIB_BltToVGAWithXlate(int x
, int y
, int w
, int h
, void *b
, int Source_lDelta
, XLATEOBJ
* Xlate
)
498 for (i
= x
; i
< x2
; i
++)
501 offset
= xconv
[i
] + y80
[y
];
503 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08); // set the mask
504 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, maskbit
[i
]);
506 if (0 == ((i
- x
) % 2))
508 for (j
= y
; j
< y2
; j
++)
510 READ_REGISTER_UCHAR(vidmem
+ offset
);
511 WRITE_REGISTER_UCHAR(vidmem
+ offset
, XLATEOBJ_iXlate(Xlate
, (*pb
& 0xf0) >> 4));
518 for (j
= y
; j
< y2
; j
++)
520 READ_REGISTER_UCHAR(vidmem
+ offset
);
521 WRITE_REGISTER_UCHAR(vidmem
+ offset
, XLATEOBJ_iXlate(Xlate
, *pb
& 0x0f));
527 if (0 != ((i
- x
) % 2))
532 /* DIB blt to the VGA.
533 * For now we just do slow writes -- pixel by pixel,
534 * packing each one into the correct 4BPP format. */
535 void DIB_TransparentBltToVGA(int x
, int y
, int w
, int h
, void *b
, int Source_lDelta
, ULONG trans
)
538 PUCHAR pb
= b
, opb
= b
;
539 BOOLEAN edgePixel
= FALSE
;
545 /* Check if the width is odd */
554 for (i
=x
; i
<x2
; i
+=2)
556 b1
= (*pb
& 0xf0) >> 4;
558 if(b1
!= trans
) vgaPutPixel(i
, j
, b1
);
559 if(b2
!= trans
) vgaPutPixel(i
+1, j
, b2
);
566 if(b1
!= trans
) vgaPutPixel(x2
, j
, b1
);
570 opb
+= Source_lDelta
;
571 pb
= opb
; // new test code
575 // This algorithm goes from left to right, storing each 4BPP pixel
576 // in an entire byte.
578 vgaReadScan( int x
, int y
, int w
, void *b
)
580 unsigned char *vp
, *vpP
;
581 unsigned char data
, mask
, maskP
;
583 unsigned char plane_mask
;
587 ASSIGNMK4(x
, y
, maskP
)
589 WRITE_PORT_USHORT((PUSHORT
)GRA_I
, 0x0005); // read mode 0
590 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x04); // read map select
594 for ( plane
=0, plane_mask
=1; plane
< 4; plane
++, plane_mask
<<=1 )
596 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, plane
); // read map select
610 } while (mask
& leftMask
);
614 for (i
=byteCounter
; i
>0; i
--)
617 if (data
& 0x80) *bp
|= plane_mask
;
620 if (data
& 0x40) *bp
|= plane_mask
;
622 if (data
& 0x20) *bp
|= plane_mask
;
624 if (data
& 0x10) *bp
|= plane_mask
;
626 if (data
& 0x08) *bp
|= plane_mask
;
628 if (data
& 0x04) *bp
|= plane_mask
;
630 if (data
& 0x02) *bp
|= plane_mask
;
632 if (data
& 0x01) *bp
|= plane_mask
;
646 } while (mask
& rightMask
);
651 /* This algorithm goes from left to right
652 * It stores each 4BPP pixel in an entire byte. */
654 vgaWriteScan ( int x
, int y
, int w
, void *b
)
658 //unsigned char init_mask;
659 volatile unsigned char dummy
;
661 int i
, j
, off
, init_off
= x
&7;
665 //ASSIGNMK4(x, y, init_mask)
666 //byte_per_line = SCREEN_X >> 3;
668 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x05); // write mode 2
669 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x02);
670 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x03); // replace
671 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
672 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08); // bit mask
674 for ( j
= 0; j
< 8; j
++)
676 unsigned int mask
= 0x80 >> j
;
677 WRITE_PORT_UCHAR ( (PUCHAR
)GRA_D
, (unsigned char)mask
);
693 /* This algorithm goes from left to right, and inside that loop, top to bottom.
694 * It also stores each 4BPP pixel in an entire byte. */
695 void DFB_BltFromVGA(int x
, int y
, int w
, int h
, void *b
, int bw
)
697 unsigned char *vp
, *vpY
, *vpP
;
698 unsigned char data
, mask
, maskP
;
699 unsigned char *bp
, *bpY
;
700 unsigned char plane_mask
;
701 int byte_per_line
= SCREEN_X
>> 3;
705 ASSIGNMK4(x
, y
, maskP
)
707 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x05); // read mode 0
708 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
709 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x04); // read map select
713 for (j
= h
; j
> 0; j
--)
719 for (plane
= 0, plane_mask
= 1; plane
< 4; plane
++, plane_mask
<<= 1)
721 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, plane
); // read map select
724 for (j
= h
; j
> 0; j
--)
738 } while (mask
& leftMask
);
742 for (i
=byteCounter
; i
>0; i
--)
745 if (data
& 0x80) *bp
|= plane_mask
;
747 if (data
& 0x40) *bp
|= plane_mask
;
749 if (data
& 0x20) *bp
|= plane_mask
;
751 if (data
& 0x10) *bp
|= plane_mask
;
753 if (data
& 0x08) *bp
|= plane_mask
;
755 if (data
& 0x04) *bp
|= plane_mask
;
757 if (data
& 0x02) *bp
|= plane_mask
;
759 if (data
& 0x01) *bp
|= plane_mask
;
769 if (data
& mask
) *bp
|= plane_mask
;
772 } while (mask
& rightMask
);
775 vpY
+= byte_per_line
;
779 // We don't need this if the next call is a DFB blt to VGA (as in the case of moving the mouse pointer)
780 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x05); // write mode 2
781 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x02);
782 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x03); // replace
783 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
786 /* This algorithm goes from left to right, and inside that loop, top to bottom.
787 * It also stores each 4BPP pixel in an entire byte. */
788 void DFB_BltToVGA(int x
, int y
, int w
, int h
, void *b
, int bw
)
790 unsigned char *bp
, *bpX
;
791 unsigned char *vp
, *vpX
;
793 //volatile unsigned char dummy;
799 ASSIGNMK4(x
, y
, mask
)
800 byte_per_line
= SCREEN_X
>> 3;
802 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x05); // write mode 2
803 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x02);
804 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x03); // replace
805 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
806 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08); // bit mask
810 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, mask
);
813 for (j
= h
; j
> 0; j
--)
821 if ((mask
>>= 1) == 0)
829 /* This algorithm goes from goes from left to right, and inside that loop, top to bottom.
830 * It also stores each 4BPP pixel in an entire byte. */
831 void DFB_BltToVGA_Transparent(int x
, int y
, int w
, int h
, void *b
, int bw
, char Trans
)
833 unsigned char *bp
, *bpX
;
834 unsigned char *vp
, *vpX
;
836 //volatile unsigned char dummy;
842 ASSIGNMK4(x
, y
, mask
)
843 byte_per_line
= SCREEN_X
>> 3;
845 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x05); // write mode 2
846 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x02);
847 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x03); // replace
848 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, 0x00);
849 WRITE_PORT_UCHAR((PUCHAR
)GRA_I
, 0x08); // bit mask
853 WRITE_PORT_UCHAR((PUCHAR
)GRA_D
, mask
);
867 if ((mask
>>= 1) == 0)
875 /* This algorithm converts a DFB into a DIB
876 * WARNING: This algorithm is buggy */
877 void DFB_BltToDIB(int x
, int y
, int w
, int h
, void *b
, int bw
, void *bdib
, int dibw
)
879 unsigned char *bp
, *bpX
, *dib
, *dibTmp
;
883 dib
= (unsigned char *)bdib
+ y
* dibw
+ (x
/ 2);
887 /* determine the bit shift for the DIB pixel */
888 dib_shift
= mod2(w
-i
);
894 for (j
= h
; j
> 0; j
--)
896 *dibTmp
= *bp
<< dib_shift
| *(bp
+ 1);
906 /* This algorithm converts a DIB into a DFB */
907 void DIB_BltToDFB(int x
, int y
, int w
, int h
, void *b
, int bw
, void *bdib
, int dibw
)
909 unsigned char *bp
, *bpX
, *dib
, *dibTmp
;
910 int i
, j
, dib_shift
, dib_and
;
913 dib
= (unsigned char *)bdib
+ y
* dibw
+ (x
/ 2);
917 /* determine the bit shift for the DIB pixel */
918 dib_shift
= mod2(w
-i
);
935 *bp
= (*dibTmp
& dib_and
) >> dib_shift
;