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