1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: GDI Driver Surace Functions 5 * FILE: win32ss/gdi/eng/surface.c 6 * PROGRAMERS: Jason Filby 7 * Timo Kreuzer 8 * TESTING TO BE DONE: 9 * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface 10 * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats 11 */ 12 13 #include <win32k.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 LONG giUniqueSurface = 0; 19 20 UCHAR 21 gajBitsPerFormat[11] = 22 { 23 0, /* 0: unused */ 24 1, /* 1: BMF_1BPP */ 25 4, /* 2: BMF_4BPP */ 26 8, /* 3: BMF_8BPP */ 27 16, /* 4: BMF_16BPP */ 28 24, /* 5: BMF_24BPP */ 29 32, /* 6: BMF_32BPP */ 30 4, /* 7: BMF_4RLE */ 31 8, /* 8: BMF_8RLE */ 32 0, /* 9: BMF_JPEG */ 33 0, /* 10: BMF_PNG */ 34 }; 35 36 37 ULONG 38 FASTCALL 39 BitmapFormat(ULONG cBits, ULONG iCompression) 40 { 41 switch (iCompression) 42 { 43 case BI_RGB: 44 /* Fall through */ 45 case BI_BITFIELDS: 46 if (cBits <= 1) return BMF_1BPP; 47 if (cBits <= 4) return BMF_4BPP; 48 if (cBits <= 8) return BMF_8BPP; 49 if (cBits <= 16) return BMF_16BPP; 50 if (cBits <= 24) return BMF_24BPP; 51 if (cBits <= 32) return BMF_32BPP; 52 return 0; 53 54 case BI_RLE4: 55 return BMF_4RLE; 56 57 case BI_RLE8: 58 return BMF_8RLE; 59 60 default: 61 return 0; 62 } 63 } 64 65 VOID 66 NTAPI 67 SURFACE_vCleanup(PVOID ObjectBody) 68 { 69 PSURFACE psurf = (PSURFACE)ObjectBody; 70 PVOID pvBits = psurf->SurfObj.pvBits; 71 72 /* Check if the surface has bits */ 73 if (pvBits) 74 { 75 /* Only bitmaps can have bits */ 76 ASSERT(psurf->SurfObj.iType == STYPE_BITMAP); 77 78 /* Check if it is a DIB section */ 79 if (psurf->hDIBSection) 80 { 81 /* Unmap the section view */ 82 EngUnmapSectionView(pvBits, psurf->dwOffset, psurf->hSecure); 83 } 84 else if (psurf->SurfObj.fjBitmap & BMF_USERMEM) 85 { 86 /* Bitmap was allocated from usermode memory */ 87 EngFreeUserMem(pvBits); 88 } 89 else if (psurf->SurfObj.fjBitmap & BMF_KMSECTION) 90 { 91 /* Bitmap was allocated from a kernel section */ 92 if (!EngFreeSectionMem(NULL, pvBits)) 93 { 94 DPRINT1("EngFreeSectionMem failed for %p!\n", pvBits); 95 // Should we BugCheck here? 96 ASSERT(FALSE); 97 } 98 } 99 else if (psurf->SurfObj.fjBitmap & BMF_POOLALLOC) 100 { 101 /* Free a pool allocation */ 102 EngFreeMem(pvBits); 103 } 104 } 105 106 /* Free palette */ 107 if(psurf->ppal) 108 { 109 PALETTE_ShareUnlockPalette(psurf->ppal); 110 } 111 } 112 113 114 PSURFACE 115 NTAPI 116 SURFACE_AllocSurface( 117 _In_ USHORT iType, 118 _In_ ULONG cx, 119 _In_ ULONG cy, 120 _In_ ULONG iFormat, 121 _In_ ULONG fjBitmap, 122 _In_opt_ ULONG cjWidth, 123 _In_opt_ ULONG cjBufSize, 124 _In_opt_ PVOID pvBits) 125 { 126 ULONG cBitsPixel, cjBits, cjObject; 127 PSURFACE psurf; 128 SURFOBJ *pso; 129 PVOID pvSection; 130 131 NT_ASSERT(!pvBits || (iType == STYPE_BITMAP)); 132 NT_ASSERT((iFormat <= BMF_32BPP) || (cjBufSize != 0)); 133 NT_ASSERT((LONG)cy > 0); 134 135 /* Verify format */ 136 if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG)) 137 { 138 DPRINT1("Invalid bitmap format: %lu\n", iFormat); 139 return NULL; 140 } 141 142 /* Get bits per pixel from the format */ 143 cBitsPixel = gajBitsPerFormat[iFormat]; 144 145 /* Are bits and a width in bytes given? */ 146 if (pvBits && cjWidth) 147 { 148 /* Align the width (Windows compatibility, drivers expect that) */ 149 cjWidth = WIDTH_BYTES_ALIGN32((cjWidth << 3) / cBitsPixel, cBitsPixel); 150 } 151 else 152 { 153 /* Calculate width from the bitmap width in pixels */ 154 cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel); 155 } 156 157 /* Is this an uncompressed format? */ 158 if (iFormat <= BMF_32BPP) 159 { 160 /* Calculate the correct bitmap size in bytes */ 161 if (!NT_SUCCESS(RtlULongMult(cjWidth, cy, &cjBits))) 162 { 163 DPRINT1("Overflow calculating size: cjWidth %lu, cy %lu\n", 164 cjWidth, cy); 165 return NULL; 166 } 167 168 /* Did we get a buffer and size? */ 169 if ((pvBits != NULL) && (cjBufSize != 0)) 170 { 171 /* Make sure the buffer is large enough */ 172 if (cjBufSize < cjBits) 173 { 174 DPRINT1("Buffer is too small, required: %lu, got %lu\n", 175 cjBits, cjBufSize); 176 return NULL; 177 } 178 } 179 } 180 else 181 { 182 /* Compressed format, use the provided size */ 183 NT_ASSERT(cjBufSize != 0); 184 cjBits = cjBufSize; 185 } 186 187 /* Check if we need an extra large object */ 188 if ((iType == STYPE_BITMAP) && (pvBits == NULL) && 189 !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION)) 190 { 191 /* Allocate an object large enough to hold the bits */ 192 cjObject = sizeof(SURFACE) + cjBits; 193 } 194 else 195 { 196 /* Otherwise just allocate the SURFACE structure */ 197 cjObject = sizeof(SURFACE); 198 } 199 200 /* Check for arithmetic overflow */ 201 if (cjObject < sizeof(SURFACE)) 202 { 203 /* Fail! */ 204 DPRINT1("Overflow calculating cjObject: cjBits %lu\n", cjBits); 205 return NULL; 206 } 207 208 /* Allocate a SURFACE object */ 209 psurf = (PSURFACE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_BITMAP, cjObject); 210 if (!psurf) 211 { 212 return NULL; 213 } 214 215 /* Initialize the basic fields */ 216 pso = &psurf->SurfObj; 217 pso->hsurf = psurf->BaseObject.hHmgr; 218 pso->sizlBitmap.cx = cx; 219 pso->sizlBitmap.cy = cy; 220 pso->iBitmapFormat = iFormat; 221 pso->iType = iType; 222 pso->fjBitmap = (USHORT)fjBitmap; 223 pso->iUniq = InterlockedIncrement(&giUniqueSurface); 224 pso->cjBits = cjBits; 225 226 /* Check if we need a bitmap buffer */ 227 if (iType == STYPE_BITMAP) 228 { 229 /* Check if we got one or if we need to allocate one */ 230 if (pvBits != NULL) 231 { 232 /* Use the caller provided buffer */ 233 pso->pvBits = pvBits; 234 } 235 else if (fjBitmap & BMF_USERMEM) 236 { 237 /* User mode memory was requested */ 238 pso->pvBits = EngAllocUserMem(cjBits, 0); 239 240 /* Check for failure */ 241 if (!pso->pvBits) 242 { 243 GDIOBJ_vDeleteObject(&psurf->BaseObject); 244 return NULL; 245 } 246 } 247 else if (fjBitmap & BMF_KMSECTION) 248 { 249 /* Use a kernel mode section */ 250 pso->pvBits = EngAllocSectionMem(&pvSection, 251 (fjBitmap & BMF_NOZEROINIT) ? 252 0 : FL_ZERO_MEMORY, 253 cjBits, TAG_DIB); 254 255 /* Check for failure */ 256 if (!pso->pvBits) 257 { 258 GDIOBJ_vDeleteObject(&psurf->BaseObject); 259 return NULL; 260 } 261 262 /* Free the section already, but keep the mapping */ 263 EngFreeSectionMem(pvSection, NULL); 264 } 265 else 266 { 267 /* Buffer is after the object */ 268 pso->pvBits = psurf + 1; 269 270 /* Zero the buffer, except requested otherwise */ 271 if (!(fjBitmap & BMF_NOZEROINIT)) 272 { 273 RtlZeroMemory(pso->pvBits, cjBits); 274 } 275 } 276 277 /* Set pvScan0 and lDelta */ 278 if (fjBitmap & BMF_TOPDOWN) 279 { 280 /* Topdown is the normal way */ 281 pso->pvScan0 = pso->pvBits; 282 pso->lDelta = cjWidth; 283 } 284 else 285 { 286 /* Inversed bitmap (bottom up) */ 287 pso->pvScan0 = ((PCHAR)pso->pvBits + pso->cjBits - cjWidth); 288 pso->lDelta = -(LONG)cjWidth; 289 } 290 } 291 else 292 { 293 /* There are no bitmap bits */ 294 pso->pvScan0 = pso->pvBits = NULL; 295 pso->lDelta = 0; 296 } 297 298 /* Assign a default palette and increment its reference count */ 299 SURFACE_vSetPalette(psurf, appalSurfaceDefault[iFormat]); 300 301 return psurf; 302 } 303 304 HBITMAP 305 APIENTRY 306 EngCreateBitmap( 307 _In_ SIZEL sizl, 308 _In_ LONG lWidth, 309 _In_ ULONG iFormat, 310 _In_ ULONG fl, 311 _In_opt_ PVOID pvBits) 312 { 313 PSURFACE psurf; 314 HBITMAP hbmp; 315 316 /* Allocate a surface */ 317 psurf = SURFACE_AllocSurface(STYPE_BITMAP, 318 sizl.cx, 319 sizl.cy, 320 iFormat, 321 fl, 322 lWidth, 323 0, 324 pvBits); 325 if (!psurf) 326 { 327 DPRINT1("SURFACE_AllocSurface failed. (STYPE_BITMAP, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu, fl=%lu, lWidth=%ld, pvBits=0x%p)\n", 328 sizl.cx, sizl.cy, iFormat, fl, lWidth, pvBits); 329 return NULL; 330 } 331 332 /* Get the handle for the bitmap */ 333 hbmp = (HBITMAP)psurf->SurfObj.hsurf; 334 335 /* Mark as API bitmap */ 336 psurf->flags = API_BITMAP; 337 338 /* Set public ownership */ 339 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); 340 341 /* Unlock the surface and return */ 342 SURFACE_UnlockSurface(psurf); 343 return hbmp; 344 } 345 346 /* 347 * @implemented 348 */ 349 HBITMAP 350 APIENTRY 351 EngCreateDeviceBitmap( 352 _In_ DHSURF dhsurf, 353 _In_ SIZEL sizl, 354 _In_ ULONG iFormat) 355 { 356 PSURFACE psurf; 357 HBITMAP hbmp; 358 359 /* Allocate a surface */ 360 psurf = SURFACE_AllocSurface(STYPE_DEVBITMAP, 361 sizl.cx, 362 sizl.cy, 363 iFormat, 364 0, 365 0, 366 0, 367 NULL); 368 if (!psurf) 369 { 370 DPRINT1("SURFACE_AllocSurface failed. (STYPE_DEVBITMAP, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu)\n", 371 sizl.cx, sizl.cy, iFormat); 372 return NULL; 373 } 374 375 /* Set the device handle */ 376 psurf->SurfObj.dhsurf = dhsurf; 377 378 /* Set public ownership */ 379 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); 380 381 /* Get the handle for the bitmap */ 382 hbmp = (HBITMAP)psurf->SurfObj.hsurf; 383 384 /* Unlock the surface and return */ 385 SURFACE_UnlockSurface(psurf); 386 return hbmp; 387 } 388 389 HSURF 390 APIENTRY 391 EngCreateDeviceSurface( 392 _In_ DHSURF dhsurf, 393 _In_ SIZEL sizl, 394 _In_ ULONG iFormat) 395 { 396 PSURFACE psurf; 397 HSURF hsurf; 398 399 /* Allocate a surface */ 400 psurf = SURFACE_AllocSurface(STYPE_DEVICE, 401 sizl.cx, 402 sizl.cy, 403 iFormat, 404 0, 405 0, 406 0, 407 NULL); 408 if (!psurf) 409 { 410 DPRINT1("SURFACE_AllocSurface failed. (STYPE_DEVICE, sizl.cx=%ld, sizl.cy=%ld, iFormat=%lu)\n", 411 sizl.cx, sizl.cy, iFormat); 412 return NULL; 413 } 414 415 /* Set the device handle */ 416 psurf->SurfObj.dhsurf = dhsurf; 417 418 /* Set public ownership */ 419 GDIOBJ_vSetObjectOwner(&psurf->BaseObject, GDI_OBJ_HMGR_PUBLIC); 420 421 /* Get the handle for the surface */ 422 hsurf = psurf->SurfObj.hsurf; 423 424 /* Unlock the surface and return */ 425 SURFACE_UnlockSurface(psurf); 426 return hsurf; 427 } 428 429 BOOL 430 APIENTRY 431 EngAssociateSurface( 432 _In_ HSURF hsurf, 433 _In_ HDEV hdev, 434 _In_ FLONG flHooks) 435 { 436 SURFOBJ *pso; 437 PSURFACE psurf; 438 PDEVOBJ* ppdev; 439 PPALETTE ppal; 440 441 ppdev = (PDEVOBJ*)hdev; 442 443 /* Lock the surface */ 444 psurf = SURFACE_ShareLockSurface(hsurf); 445 if (!psurf) 446 { 447 return FALSE; 448 } 449 pso = &psurf->SurfObj; 450 451 /* Associate the hdev */ 452 pso->hdev = hdev; 453 pso->dhpdev = ppdev->dhpdev; 454 455 /* Hook up specified functions */ 456 psurf->flags &= ~HOOK_FLAGS; 457 psurf->flags |= (flHooks & HOOK_FLAGS); 458 459 /* Assign the PDEV's palette */ 460 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); 461 SURFACE_vSetPalette(psurf, ppal); 462 PALETTE_ShareUnlockPalette(ppal); 463 464 SURFACE_ShareUnlockSurface(psurf); 465 466 return TRUE; 467 } 468 469 BOOL 470 APIENTRY 471 EngModifySurface( 472 _In_ HSURF hsurf, 473 _In_ HDEV hdev, 474 _In_ FLONG flHooks, 475 _In_ FLONG flSurface, 476 _In_ DHSURF dhsurf, 477 _In_ PVOID pvScan0, 478 _In_ LONG lDelta, 479 _Reserved_ PVOID pvReserved) 480 { 481 SURFOBJ *pso; 482 PSURFACE psurf; 483 PDEVOBJ* ppdev; 484 PPALETTE ppal; 485 486 /* Lock the surface */ 487 psurf = SURFACE_ShareLockSurface(hsurf); 488 if (psurf == NULL) 489 { 490 DPRINT1("Failed to reference surface %p\n", hsurf); 491 return FALSE; 492 } 493 494 ppdev = (PDEVOBJ*)hdev; 495 pso = &psurf->SurfObj; 496 pso->dhsurf = dhsurf; 497 498 /* Associate the hdev */ 499 pso->hdev = hdev; 500 pso->dhpdev = ppdev->dhpdev; 501 502 /* Hook up specified functions */ 503 psurf->flags &= ~HOOK_FLAGS; 504 psurf->flags |= (flHooks & HOOK_FLAGS); 505 506 /* Assign the PDEV's palette */ 507 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); 508 SURFACE_vSetPalette(psurf, ppal); 509 PALETTE_ShareUnlockPalette(ppal); 510 511 /* Update surface flags */ 512 if (flSurface & MS_NOTSYSTEMMEMORY) 513 pso->fjBitmap |= BMF_NOTSYSMEM; 514 else 515 pso->fjBitmap &= ~BMF_NOTSYSMEM; 516 if (flSurface & MS_SHAREDACCESS) 517 psurf->flags |= SHAREACCESS_SURFACE; 518 else 519 psurf->flags &= ~SHAREACCESS_SURFACE; 520 521 /* Check if the caller passed bitmap bits */ 522 if ((pvScan0 != NULL) && (lDelta != 0)) 523 { 524 /* Update the fields */ 525 pso->pvScan0 = pvScan0; 526 pso->lDelta = lDelta; 527 528 /* This is a bitmap now! */ 529 pso->iType = STYPE_BITMAP; 530 531 /* Check memory layout */ 532 if (lDelta > 0) 533 { 534 /* Topdown is the normal way */ 535 pso->cjBits = lDelta * pso->sizlBitmap.cy; 536 pso->pvBits = pso->pvScan0; 537 pso->fjBitmap |= BMF_TOPDOWN; 538 } 539 else 540 { 541 /* Inversed bitmap (bottom up) */ 542 pso->cjBits = (-lDelta) * pso->sizlBitmap.cy; 543 pso->pvBits = (PCHAR)pso->pvScan0 - pso->cjBits - lDelta; 544 pso->fjBitmap &= ~BMF_TOPDOWN; 545 } 546 } 547 else 548 { 549 /* Set bits to NULL */ 550 pso->pvBits = NULL; 551 pso->pvScan0 = NULL; 552 pso->lDelta = 0; 553 554 /* Set appropriate surface type */ 555 if (pso->iType != STYPE_DEVICE) 556 pso->iType = STYPE_DEVBITMAP; 557 } 558 559 SURFACE_ShareUnlockSurface(psurf); 560 561 return TRUE; 562 } 563 564 565 BOOL 566 APIENTRY 567 EngDeleteSurface( 568 _In_ _Post_ptr_invalid_ HSURF hsurf) 569 { 570 PSURFACE psurf; 571 572 psurf = SURFACE_ShareLockSurface(hsurf); 573 if (!psurf) 574 { 575 DPRINT1("Could not reference surface %p to delete\n", hsurf); 576 return FALSE; 577 } 578 579 GDIOBJ_vDeleteObject(&psurf->BaseObject); 580 return TRUE; 581 } 582 583 BOOL 584 APIENTRY 585 EngEraseSurface( 586 _In_ SURFOBJ *pso, 587 _In_ RECTL *prcl, 588 _In_ ULONG iColor) 589 { 590 ASSERT(pso); 591 ASSERT(prcl); 592 return FillSolid(pso, prcl, iColor); 593 } 594 595 /* 596 * @implemented 597 */ 598 SURFOBJ * APIENTRY 599 NtGdiEngLockSurface(IN HSURF hsurf) 600 { 601 return EngLockSurface(hsurf); 602 } 603 604 605 SURFOBJ * 606 APIENTRY 607 EngLockSurface( 608 _In_ HSURF hsurf) 609 { 610 SURFACE *psurf = SURFACE_ShareLockSurface(hsurf); 611 612 return psurf ? &psurf->SurfObj : NULL; 613 } 614 615 __kernel_entry 616 NTSTATUS 617 APIENTRY 618 NtGdiEngUnlockSurface( 619 _In_ SURFOBJ *pso) 620 { 621 UNIMPLEMENTED; 622 ASSERT(FALSE); 623 return STATUS_NOT_IMPLEMENTED; 624 } 625 626 VOID 627 APIENTRY 628 EngUnlockSurface( 629 _In_ _Post_ptr_invalid_ SURFOBJ *pso) 630 { 631 if (pso != NULL) 632 { 633 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj); 634 SURFACE_ShareUnlockSurface(psurf); 635 } 636 } 637 638 /* EOF */ 639