1 /*
2  * PROJECT:         ReactOS VGA display driver
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            drivers/video/displays/vga/objects/bitblt.c
5  * PURPOSE:
6  * PROGRAMMERS:
7  */
8 
9 #include <vgaddi.h>
10 
11 #include "bitblt.h"
12 
13 typedef BOOL (*PFN_VGABlt)(SURFOBJ*, SURFOBJ*, XLATEOBJ*, RECTL*, POINTL*);
14 typedef BOOL  (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
15                                        SURFOBJ* InputObj,
16                                        SURFOBJ* Mask,
17                                        XLATEOBJ* ColorTranslation,
18                                        RECTL* OutputRect,
19                                        POINTL* InputPoint,
20                                        POINTL* MaskOrigin,
21                                        BRUSHOBJ* Brush,
22                                        POINTL* BrushOrigin,
23                                        ROP4 Rop4);
24 
25 static BOOL FASTCALL VGADDI_IntersectRect(
26     OUT RECTL* prcDst,
27     IN RECTL* prcSrc1,
28     IN RECTL* prcSrc2)
29 {
30     static const RECTL rclEmpty = { 0, 0, 0, 0 };
31 
32     prcDst->left  = max(prcSrc1->left, prcSrc2->left);
33     prcDst->right = min(prcSrc1->right, prcSrc2->right);
34 
35     if (prcDst->left < prcDst->right)
36     {
37         prcDst->top    = max(prcSrc1->top, prcSrc2->top);
38         prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
39 
40         if (prcDst->top < prcDst->bottom) return(TRUE);
41     }
42 
43     *prcDst = rclEmpty;
44 
45     return FALSE;
46 }
47 
48 void DIB_BltToVGA_Fixed(int x, int y, int w, int h, void *b, int Source_lDelta, int mod);
49 
50 BOOL
51 DIBtoVGA(
52     IN SURFOBJ *Dest,
53     IN SURFOBJ *Source,
54     IN XLATEOBJ *ColorTranslation,
55     IN RECTL *DestRect,
56     IN POINTL *SourcePoint)
57 {
58     LONG dx, dy;
59 
60     dx = DestRect->right  - DestRect->left;
61     dy = DestRect->bottom - DestRect->top;
62 
63     if (NULL == ColorTranslation || 0 != (ColorTranslation->flXlate & XO_TRIVIAL))
64     {
65         DIB_BltToVGA(DestRect->left, DestRect->top, dx, dy,
66                      (PVOID)((ULONG_PTR)Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1)),
67                      Source->lDelta, SourcePoint->x % 2);
68     }
69     else
70     {
71         /* Perform color translation */
72         DIB_BltToVGAWithXlate(DestRect->left, DestRect->top, dx, dy,
73                               (PVOID)((ULONG_PTR)Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1)),
74                               Source->lDelta, ColorTranslation);
75     }
76     return FALSE;
77 }
78 
79 BOOL
80 VGAtoDIB(
81     IN SURFOBJ *Dest,
82     IN SURFOBJ *Source,
83     IN XLATEOBJ *ColorTranslation,
84     IN RECTL *DestRect,
85     IN POINTL *SourcePoint)
86 {
87     LONG i, j, dx, dy;
88     UCHAR *GDIpos, *initial;
89 
90     /* Used by the temporary DFB */
91     //DEVSURF DestDevSurf;
92 
93     /* FIXME: Optimize to retrieve entire bytes at a time (see ../vgavideo/vgavideo.c:vgaGetByte) */
94 
95     GDIpos = Dest->pvScan0 /* + (DestRect->top * Dest->lDelta) + (DestRect->left >> 1) */ ;
96     dx = DestRect->right  - DestRect->left;
97     dy = DestRect->bottom - DestRect->top;
98 
99     if (ColorTranslation == NULL)
100     {
101         /* Prepare a Dest Dev Target and copy from the DFB to the DIB */
102         //DestDevSurf.NextScan = Dest->lDelta;
103         //DestDevSurf.StartBmp = Dest->pvScan0;
104 
105         DIB_BltFromVGA(SourcePoint->x, SourcePoint->y, dx, dy, Dest->pvScan0, Dest->lDelta);
106     }
107     else
108     {
109         /* Color translation */
110         for (j = SourcePoint->y; j < SourcePoint->y + dy; j++)
111         {
112             initial = GDIpos;
113             for (i = SourcePoint->x; i < SourcePoint->x + dx; i++)
114             {
115                 *GDIpos = XLATEOBJ_iXlate(ColorTranslation, vgaGetPixel(i, j));
116                 GDIpos++;
117             }
118             GDIpos = initial + Dest->lDelta;
119         }
120     }
121     return FALSE;
122 }
123 
124 BOOL
125 DFBtoVGA(
126     IN SURFOBJ *Dest,
127     IN SURFOBJ *Source,
128     IN XLATEOBJ *ColorTranslation,
129     IN RECTL *DestRect,
130     IN POINTL *SourcePoint)
131 {
132     /* Do DFBs need color translation?? */
133     return FALSE;
134 }
135 
136 BOOL
137 VGAtoDFB(
138     IN SURFOBJ *Dest,
139     IN SURFOBJ *Source,
140     IN XLATEOBJ *ColorTranslation,
141     IN RECTL *DestRect,
142     IN POINTL *SourcePoint)
143 {
144     /* Do DFBs need color translation?? */
145     return FALSE;
146 }
147 
148 BOOL
149 VGAtoVGA(
150     IN SURFOBJ *Dest,
151     IN SURFOBJ *Source,
152     IN XLATEOBJ *ColorTranslation,
153     IN RECTL *DestRect,
154     IN POINTL *SourcePoint)
155 {
156     LONG i, i2, j, dx, dy, alterx, altery;
157     static char buf[SCREEN_X];
158 
159     /* Calculate deltas */
160     dx = DestRect->right  - DestRect->left;
161     dy = DestRect->bottom - DestRect->top;
162 
163     alterx = DestRect->left - SourcePoint->x;
164     altery = DestRect->top - SourcePoint->y;
165 
166     i = SourcePoint->x;
167     i2 = i + alterx;
168 
169     if (SourcePoint->y >= DestRect->top)
170     {
171         for (j = SourcePoint->y; j < SourcePoint->y + dy; j++)
172         {
173             LONG j2 = j + altery;
174             vgaReadScan  ( i,  j,  dx, buf );
175             vgaWriteScan ( i2, j2, dx, buf );
176         }
177     }
178     else
179     {
180         for(j = (SourcePoint->y + dy - 1); j >= SourcePoint->y; j--)
181         {
182             LONG j2 = j + altery;
183             vgaReadScan  ( i,  j,  dx, buf );
184             vgaWriteScan ( i2, j2, dx, buf );
185         }
186     }
187 
188     return TRUE;
189 }
190 
191 BOOL APIENTRY
192 VGADDI_BltBrush(
193     IN SURFOBJ* Dest,
194     IN SURFOBJ* Source,
195     IN SURFOBJ* MaskSurf,
196     IN XLATEOBJ* ColorTranslation,
197     IN RECTL* DestRect,
198     IN POINTL* SourcePoint,
199     IN POINTL* MaskPoint,
200     IN BRUSHOBJ* Brush,
201     IN POINTL* BrushPoint,
202     IN ROP4 Rop4)
203 {
204     UCHAR SolidColor = 0;
205     LONG Left;
206     LONG Length;
207     PUCHAR Video;
208     UCHAR Mask;
209     INT i, j;
210     ULONG RasterOp = VGA_NORMAL;
211 
212     /* Punt brush blts to non-device surfaces. */
213     if (Dest->iType != STYPE_DEVICE)
214         return FALSE;
215 
216     /* Punt pattern fills. */
217     if ((GET_OPINDEX_FROM_ROP4(Rop4) == GET_OPINDEX_FROM_ROP3(PATCOPY)
218          || GET_OPINDEX_FROM_ROP4(Rop4) == GET_OPINDEX_FROM_ROP3(PATINVERT)) &&
219         Brush->iSolidColor == 0xFFFFFFFF)
220     {
221       return FALSE;
222     }
223 
224     /* Get the brush colour. */
225     switch (GET_OPINDEX_FROM_ROP4(Rop4))
226     {
227         case GET_OPINDEX_FROM_ROP3(PATCOPY): SolidColor = Brush->iSolidColor; break;
228         case GET_OPINDEX_FROM_ROP3(PATINVERT): SolidColor = Brush->iSolidColor; RasterOp = VGA_XOR; break;
229         case GET_OPINDEX_FROM_ROP3(WHITENESS): SolidColor = 0xF; break;
230         case GET_OPINDEX_FROM_ROP3(BLACKNESS): SolidColor = 0x0; break;
231         case GET_OPINDEX_FROM_ROP3(DSTINVERT): SolidColor = 0xF; RasterOp = VGA_XOR; break;
232     }
233 
234     /* Select write mode 3. */
235     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
236     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x03);
237 
238     /* Setup set/reset register. */
239     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x00);
240     WRITE_PORT_UCHAR((PUCHAR)GRA_D, (UCHAR)SolidColor);
241 
242     /* Enable writes to all pixels. */
243     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
244     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
245 
246     /* Set up data rotate. */
247     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
248     WRITE_PORT_UCHAR((PUCHAR)GRA_D, RasterOp);
249 
250     /* Fill any pixels on the left which don't fall into a full row of eight. */
251     if ((DestRect->left % 8) != 0)
252     {
253         /* Disable writes to pixels outside of the destination rectangle. */
254         Mask = (1 << (8 - (DestRect->left % 8))) - 1;
255         if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
256             Mask &= ~((1 << (8 - (DestRect->right % 8))) - 1);
257 
258         /* Write the same color to each pixel. */
259         Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->left >> 3);
260         for (i = DestRect->top; i < DestRect->bottom; i++, Video += 80)
261         {
262             (VOID)READ_REGISTER_UCHAR(Video);
263             WRITE_REGISTER_UCHAR(Video, Mask);
264         }
265 
266         /* Have we finished. */
267         if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
268         {
269             /* Restore write mode 2. */
270             WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
271             WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
272 
273             /* Set up data rotate. */
274             WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
275             WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
276 
277             return TRUE;
278         }
279     }
280 
281     /* Fill any whole rows of eight pixels. */
282     Left = (DestRect->left + 7) & ~0x7;
283     Length = (DestRect->right >> 3) - (Left >> 3);
284     for (i = DestRect->top; i < DestRect->bottom; i++)
285     {
286         Video = (PUCHAR)vidmem + i * 80 + (Left >> 3);
287         for (j = 0; j < Length; j++, Video++)
288         {
289 #if 0
290             (VOID)READ_REGISTER_UCHAR(Video);
291             WRITE_REGISTER_UCHAR(Video, 0xFF);
292 #else
293             char volatile Temp = *Video;
294             Temp |= 0;
295             *Video = 0xFF;
296 #endif
297         }
298     }
299 
300     /* Fill any pixels on the right which don't fall into a complete row. */
301     if ((DestRect->right % 8) != 0)
302     {
303         /* Disable writes to pixels outside the destination rectangle. */
304         Mask = ~((1 << (8 - (DestRect->right % 8))) - 1);
305 
306         Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->right >> 3);
307         for (i = DestRect->top; i < DestRect->bottom; i++, Video += 80)
308         {
309             (VOID)READ_REGISTER_UCHAR(Video);
310             WRITE_REGISTER_UCHAR(Video, Mask);
311         }
312     }
313 
314     /* Restore write mode 2. */
315     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
316     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
317 
318     /* Set up data rotate. */
319     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
320     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
321 
322     return TRUE;
323 }
324 
325 BOOL APIENTRY
326 VGADDI_BltSrc(
327     IN SURFOBJ* Dest,
328     IN SURFOBJ* Source,
329     IN SURFOBJ* Mask,
330     IN XLATEOBJ* ColorTranslation,
331     IN RECTL* DestRect,
332     IN POINTL* SourcePoint,
333     IN POINTL* MaskOrigin,
334     IN BRUSHOBJ* Brush,
335     IN POINTL* BrushOrigin,
336     IN ROP4 Rop4)
337 {
338     PFN_VGABlt BltOperation;
339     ULONG SourceType;
340 
341     SourceType = Source->iType;
342 
343     if (SourceType == STYPE_BITMAP && Dest->iType == STYPE_DEVICE)
344         BltOperation = DIBtoVGA;
345     else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_BITMAP)
346         BltOperation = VGAtoDIB;
347     else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVICE)
348         BltOperation = VGAtoVGA;
349     else if (SourceType == STYPE_DEVBITMAP && Dest->iType == STYPE_DEVICE)
350         BltOperation = DFBtoVGA;
351     else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVBITMAP)
352         BltOperation = VGAtoDFB;
353     else
354     {
355         /* Punt blts not involving a device or a device-bitmap. */
356         return FALSE;
357     }
358 
359     BltOperation(Dest, Source, ColorTranslation, DestRect, SourcePoint);
360     return TRUE;
361 }
362 
363 BOOL APIENTRY
364 VGADDI_BltMask(
365     IN SURFOBJ* Dest,
366     IN SURFOBJ* Source,
367     IN SURFOBJ* Mask,
368     IN XLATEOBJ* ColorTranslation,
369     IN RECTL* DestRect,
370     IN POINTL* SourcePoint,
371     IN POINTL* MaskPoint,
372     IN BRUSHOBJ* Brush,
373     IN POINTL* BrushPoint,
374     IN ROP4 Rop4)
375 {
376     LONG i, j, dx, dy, c8;
377     BYTE *tMask, *lMask;
378 
379     dx = DestRect->right  - DestRect->left;
380     dy = DestRect->bottom - DestRect->top;
381 
382     if (ColorTranslation == NULL)
383     {
384         if (Mask != NULL)
385         {
386             tMask = Mask->pvScan0;
387             for (j = 0; j < dy; j++)
388             {
389                 lMask = tMask;
390                 c8 = 0;
391                 for (i = 0; i < dx; i++)
392                 {
393                     if((*lMask & maskbit[c8]) != 0)
394                         vgaPutPixel(DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
395                     c8++;
396                      if(c8 == 8)
397                     {
398                         lMask++;
399                         c8=0;
400                     }
401                 }
402                 tMask += Mask->lDelta;
403             }
404         }
405     }
406     return TRUE;
407 }
408 
409 BOOL APIENTRY
410 DrvBitBlt(
411     IN SURFOBJ *Dest,
412     IN SURFOBJ *Source,
413     IN SURFOBJ *Mask,
414     IN CLIPOBJ *Clip,
415     IN XLATEOBJ *ColorTranslation,
416     IN RECTL *DestRect,
417     IN POINTL *SourcePoint,
418     IN POINTL *MaskPoint,
419     IN BRUSHOBJ *Brush,
420     IN POINTL *BrushPoint,
421     IN ROP4 rop4)
422 {
423     PBLTRECTFUNC BltRectFunc;
424     RECTL CombinedRect;
425     BOOL Ret = FALSE;
426     RECT_ENUM RectEnum;
427     BOOL EnumMore;
428     UINT i;
429     POINTL Pt;
430     ULONG Direction;
431     POINTL FinalSourcePoint;
432 
433     if (Source && SourcePoint)
434     {
435         FinalSourcePoint.x = SourcePoint->x;
436         FinalSourcePoint.y = SourcePoint->y;
437     }
438     else
439     {
440         FinalSourcePoint.x = 0;
441         FinalSourcePoint.y = 0;
442     }
443 
444     switch (rop4)
445     {
446         case ROP3_TO_ROP4(BLACKNESS):
447         case ROP3_TO_ROP4(PATCOPY):
448         case ROP3_TO_ROP4(WHITENESS):
449         case ROP3_TO_ROP4(PATINVERT):
450         case ROP3_TO_ROP4(DSTINVERT):
451             BltRectFunc = VGADDI_BltBrush;
452             break;
453 
454         case ROP3_TO_ROP4(SRCCOPY):
455             if (BMF_4BPP == Source->iBitmapFormat && BMF_4BPP == Dest->iBitmapFormat)
456                 BltRectFunc = VGADDI_BltSrc;
457             else
458                 return FALSE;
459             break;
460 
461         case R4_MASK:
462             BltRectFunc = VGADDI_BltMask;
463             break;
464 
465         default:
466             return FALSE;
467     }
468 
469     switch (NULL == Clip ? DC_TRIVIAL : Clip->iDComplexity)
470     {
471         case DC_TRIVIAL:
472             Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, DestRect,
473                                  SourcePoint, MaskPoint, Brush, BrushPoint,
474                                  rop4);
475             break;
476         case DC_RECT:
477             /* Clip the blt to the clip rectangle */
478             VGADDI_IntersectRect(&CombinedRect, DestRect, &(Clip->rclBounds));
479             Pt.x = FinalSourcePoint.x + CombinedRect.left - DestRect->left;
480             Pt.y = FinalSourcePoint.y + CombinedRect.top - DestRect->top;
481             Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
482                                  &Pt, MaskPoint, Brush, BrushPoint,
483                                  rop4);
484             break;
485         case DC_COMPLEX:
486             Ret = TRUE;
487             if (Dest == Source)
488             {
489                 if (DestRect->top <= FinalSourcePoint.y)
490                     Direction = DestRect->left < FinalSourcePoint.y ? CD_RIGHTDOWN : CD_LEFTDOWN;
491                 else
492                     Direction = DestRect->left < FinalSourcePoint.x ? CD_RIGHTUP : CD_LEFTUP;
493             }
494             else
495             {
496                 Direction = CD_ANY;
497             }
498             CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, 0);
499             do
500             {
501                 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
502 
503                 for (i = 0; i < RectEnum.c; i++)
504                 {
505                     VGADDI_IntersectRect(&CombinedRect, DestRect, RectEnum.arcl + i);
506                     Pt.x = FinalSourcePoint.x + CombinedRect.left - DestRect->left;
507                     Pt.y = FinalSourcePoint.y + CombinedRect.top - DestRect->top;
508                     Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
509                                          &Pt, MaskPoint, Brush, BrushPoint, rop4) &&
510                                          Ret;
511                 }
512             } while (EnumMore);
513             break;
514     }
515 
516     return Ret;
517 }
518