1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Support for physical devices 5 * FILE: win32ss/gdi/eng/pdevobj.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org) 7 */ 8 9 #include <win32k.h> 10 #define NDEBUG 11 #include <debug.h> 12 13 PPDEVOBJ gppdevPrimary = NULL; 14 15 static PPDEVOBJ gppdevList = NULL; 16 static HSEMAPHORE ghsemPDEV; 17 18 CODE_SEG("INIT") 19 NTSTATUS 20 NTAPI 21 InitPDEVImpl(VOID) 22 { 23 ghsemPDEV = EngCreateSemaphore(); 24 if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES; 25 return STATUS_SUCCESS; 26 } 27 28 #if DBG 29 PPDEVOBJ 30 NTAPI 31 DbgLookupDHPDEV(DHPDEV dhpdev) 32 { 33 PPDEVOBJ ppdev; 34 35 /* Lock PDEV list */ 36 EngAcquireSemaphoreShared(ghsemPDEV); 37 38 /* Walk through the list of PDEVs */ 39 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 40 { 41 /* Compare with the given DHPDEV */ 42 if (ppdev->dhpdev == dhpdev) break; 43 } 44 45 /* Unlock PDEV list */ 46 EngReleaseSemaphore(ghsemPDEV); 47 48 return ppdev; 49 } 50 #endif 51 52 PPDEVOBJ 53 PDEVOBJ_AllocPDEV(VOID) 54 { 55 PPDEVOBJ ppdev; 56 57 ppdev = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), GDITAG_PDEV); 58 if (!ppdev) 59 return NULL; 60 61 RtlZeroMemory(ppdev, sizeof(PDEVOBJ)); 62 63 ppdev->hsemDevLock = EngCreateSemaphore(); 64 if (ppdev->hsemDevLock == NULL) 65 { 66 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 67 return NULL; 68 } 69 70 /* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */ 71 ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV); 72 if (ppdev->pEDDgpl) 73 RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL)); 74 75 ppdev->cPdevRefs = 1; 76 77 return ppdev; 78 } 79 80 static 81 VOID 82 PDEVOBJ_vDeletePDEV( 83 PPDEVOBJ ppdev) 84 { 85 EngDeleteSemaphore(ppdev->hsemDevLock); 86 if (ppdev->pEDDgpl) 87 ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV); 88 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 89 } 90 91 VOID 92 NTAPI 93 PDEVOBJ_vRelease( 94 _Inout_ PPDEVOBJ ppdev) 95 { 96 /* Lock loader */ 97 EngAcquireSemaphore(ghsemPDEV); 98 99 /* Decrease reference count */ 100 InterlockedDecrement(&ppdev->cPdevRefs); 101 ASSERT(ppdev->cPdevRefs >= 0); 102 103 /* Check if references are left */ 104 if (ppdev->cPdevRefs == 0) 105 { 106 /* Do we have a surface? */ 107 if (ppdev->pSurface) 108 { 109 /* Release the surface and let the driver free it */ 110 SURFACE_ShareUnlockSurface(ppdev->pSurface); 111 ppdev->pfn.DisableSurface(ppdev->dhpdev); 112 } 113 114 /* Do we have a palette? */ 115 if (ppdev->ppalSurf) 116 { 117 PALETTE_ShareUnlockPalette(ppdev->ppalSurf); 118 } 119 120 /* Check if the PDEV was enabled */ 121 if (ppdev->dhpdev != NULL) 122 { 123 /* Disable the PDEV */ 124 ppdev->pfn.DisablePDEV(ppdev->dhpdev); 125 } 126 127 /* Remove it from list */ 128 if (ppdev == gppdevList) 129 { 130 gppdevList = ppdev->ppdevNext; 131 } 132 else 133 { 134 PPDEVOBJ ppdevCurrent = gppdevList; 135 BOOL found = FALSE; 136 while (!found && ppdevCurrent->ppdevNext) 137 { 138 if (ppdevCurrent->ppdevNext == ppdev) 139 found = TRUE; 140 else 141 ppdevCurrent = ppdevCurrent->ppdevNext; 142 } 143 if (found) 144 ppdevCurrent->ppdevNext = ppdev->ppdevNext; 145 } 146 147 /* Is this the primary one ? */ 148 if (ppdev == gppdevPrimary) 149 gppdevPrimary = NULL; 150 151 /* Free it */ 152 PDEVOBJ_vDeletePDEV(ppdev); 153 } 154 155 /* Unlock loader */ 156 EngReleaseSemaphore(ghsemPDEV); 157 } 158 159 BOOL 160 NTAPI 161 PDEVOBJ_bEnablePDEV( 162 PPDEVOBJ ppdev, 163 PDEVMODEW pdevmode, 164 PWSTR pwszLogAddress) 165 { 166 PFN_DrvEnablePDEV pfnEnablePDEV; 167 ULONG i; 168 169 DPRINT("PDEVOBJ_bEnablePDEV()\n"); 170 171 /* Get the DrvEnablePDEV function */ 172 pfnEnablePDEV = ppdev->pldev->pfn.EnablePDEV; 173 174 /* Call the drivers DrvEnablePDEV function */ 175 ppdev->dhpdev = pfnEnablePDEV(pdevmode, 176 pwszLogAddress, 177 HS_DDI_MAX, 178 ppdev->ahsurf, 179 sizeof(GDIINFO), 180 (PULONG)&ppdev->gdiinfo, 181 sizeof(DEVINFO), 182 &ppdev->devinfo, 183 (HDEV)ppdev, 184 ppdev->pGraphicsDevice->pwszDescription, 185 ppdev->pGraphicsDevice->DeviceObject); 186 if (ppdev->dhpdev == NULL) 187 { 188 DPRINT1("Failed to enable PDEV\n"); 189 return FALSE; 190 } 191 192 /* Fix up some values */ 193 if (ppdev->gdiinfo.ulLogPixelsX == 0) 194 ppdev->gdiinfo.ulLogPixelsX = 96; 195 196 if (ppdev->gdiinfo.ulLogPixelsY == 0) 197 ppdev->gdiinfo.ulLogPixelsY = 96; 198 199 /* Set raster caps */ 200 ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT; 201 if ((ppdev->gdiinfo.ulTechnology != DT_PLOTTER) && (ppdev->gdiinfo.ulTechnology != DT_CHARSTREAM)) 202 ppdev->gdiinfo.flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_DI_BITMAP | RC_BITMAP64 | RC_BITBLT; 203 if (ppdev->gdiinfo.ulTechnology == DT_RASDISPLAY) 204 ppdev->gdiinfo.flRaster |= RC_FLOODFILL; 205 if (ppdev->devinfo.flGraphicsCaps & GCAPS_PALMANAGED) 206 ppdev->gdiinfo.flRaster |= RC_PALETTE; 207 208 /* Setup Palette */ 209 ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); 210 211 /* Setup hatch brushes */ 212 for (i = 0; i < HS_DDI_MAX; i++) 213 { 214 if (ppdev->ahsurf[i] == NULL) 215 ppdev->ahsurf[i] = gahsurfHatch[i]; 216 } 217 218 DPRINT("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev->dhpdev); 219 220 return TRUE; 221 } 222 223 VOID 224 NTAPI 225 PDEVOBJ_vCompletePDEV( 226 PPDEVOBJ ppdev) 227 { 228 /* Call the drivers DrvCompletePDEV function */ 229 ppdev->pldev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 230 } 231 232 PSURFACE 233 NTAPI 234 PDEVOBJ_pSurface( 235 PPDEVOBJ ppdev) 236 { 237 HSURF hsurf; 238 239 /* Check if there is no surface for this PDEV yet */ 240 if (ppdev->pSurface == NULL) 241 { 242 /* Call the drivers DrvEnableSurface */ 243 hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev); 244 if (hsurf== NULL) 245 { 246 DPRINT1("Failed to create PDEV surface!\n"); 247 return NULL; 248 } 249 250 /* Get a reference to the surface */ 251 ppdev->pSurface = SURFACE_ShareLockSurface(hsurf); 252 NT_ASSERT(ppdev->pSurface != NULL); 253 } 254 255 /* Increment reference count */ 256 GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject); 257 258 DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev->pSurface); 259 return ppdev->pSurface; 260 } 261 262 VOID 263 NTAPI 264 PDEVOBJ_vRefreshModeList( 265 PPDEVOBJ ppdev) 266 { 267 PGRAPHICS_DEVICE pGraphicsDevice; 268 PDEVMODEINFO pdminfo, pdmiNext; 269 DEVMODEW dmDefault; 270 DEVMODEW dmCurrent; 271 272 /* Lock the PDEV */ 273 EngAcquireSemaphore(ppdev->hsemDevLock); 274 275 pGraphicsDevice = ppdev->pGraphicsDevice; 276 277 /* Remember our default mode */ 278 dmDefault = *pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm; 279 dmCurrent = *ppdev->pdmwDev; 280 281 /* Clear out the modes */ 282 for (pdminfo = pGraphicsDevice->pdevmodeInfo; 283 pdminfo; 284 pdminfo = pdmiNext) 285 { 286 pdmiNext = pdminfo->pdmiNext; 287 ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE); 288 } 289 pGraphicsDevice->pdevmodeInfo = NULL; 290 ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE); 291 pGraphicsDevice->pDevModeList = NULL; 292 293 /* Now re-populate the list */ 294 if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault)) 295 { 296 DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a perfectly good mode list\n"); 297 } 298 299 ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, &dmCurrent); 300 301 /* Unlock PDEV */ 302 EngReleaseSemaphore(ppdev->hsemDevLock); 303 } 304 305 PDEVMODEW 306 NTAPI 307 PDEVOBJ_pdmMatchDevMode( 308 PPDEVOBJ ppdev, 309 PDEVMODEW pdm) 310 { 311 PGRAPHICS_DEVICE pGraphicsDevice; 312 PDEVMODEW pdmCurrent; 313 ULONG i; 314 DWORD dwFields; 315 316 pGraphicsDevice = ppdev->pGraphicsDevice; 317 318 for (i = 0; i < pGraphicsDevice->cDevModes; i++) 319 { 320 pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm; 321 322 /* Compare asked DEVMODE fields 323 * Only compare those that are valid in both DEVMODE structs */ 324 dwFields = pdmCurrent->dmFields & pdm->dmFields; 325 326 /* For now, we only need those */ 327 if ((dwFields & DM_BITSPERPEL) && 328 (pdmCurrent->dmBitsPerPel != pdm->dmBitsPerPel)) continue; 329 if ((dwFields & DM_PELSWIDTH) && 330 (pdmCurrent->dmPelsWidth != pdm->dmPelsWidth)) continue; 331 if ((dwFields & DM_PELSHEIGHT) && 332 (pdmCurrent->dmPelsHeight != pdm->dmPelsHeight)) continue; 333 if ((dwFields & DM_DISPLAYFREQUENCY) && 334 (pdmCurrent->dmDisplayFrequency != pdm->dmDisplayFrequency)) continue; 335 336 /* Match! Return the DEVMODE */ 337 return pdmCurrent; 338 } 339 340 /* Nothing found */ 341 return NULL; 342 } 343 344 static 345 PPDEVOBJ 346 EngpCreatePDEV( 347 PUNICODE_STRING pustrDeviceName, 348 PDEVMODEW pdm) 349 { 350 PGRAPHICS_DEVICE pGraphicsDevice; 351 PPDEVOBJ ppdev; 352 353 DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm); 354 355 /* Try to find the GRAPHICS_DEVICE */ 356 if (pustrDeviceName) 357 { 358 pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0, 0); 359 if (!pGraphicsDevice) 360 { 361 DPRINT1("No GRAPHICS_DEVICE found for %ls!\n", 362 pustrDeviceName ? pustrDeviceName->Buffer : 0); 363 return NULL; 364 } 365 } 366 else 367 { 368 pGraphicsDevice = gpPrimaryGraphicsDevice; 369 } 370 371 /* Allocate a new PDEVOBJ */ 372 ppdev = PDEVOBJ_AllocPDEV(); 373 if (!ppdev) 374 { 375 DPRINT1("failed to allocate a PDEV\n"); 376 return NULL; 377 } 378 379 /* If no DEVMODEW is given, ... */ 380 if (!pdm) 381 { 382 /* ... use the device's default one */ 383 pdm = pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm; 384 DPRINT("Using iDefaultMode = %lu\n", pGraphicsDevice->iDefaultMode); 385 } 386 387 /* Try to get a diplay driver */ 388 ppdev->pldev = EngLoadImageEx(pdm->dmDeviceName, LDEV_DEVICE_DISPLAY); 389 if (!ppdev->pldev) 390 { 391 DPRINT1("Could not load display driver '%ls', '%ls'\n", 392 pGraphicsDevice->pDiplayDrivers, 393 pdm->dmDeviceName); 394 PDEVOBJ_vRelease(ppdev); 395 return NULL; 396 } 397 398 /* Copy the function table */ 399 ppdev->pfn = ppdev->pldev->pfn; 400 401 /* Set MovePointer function */ 402 ppdev->pfnMovePointer = ppdev->pfn.MovePointer; 403 if (!ppdev->pfnMovePointer) 404 ppdev->pfnMovePointer = EngMovePointer; 405 406 ppdev->pGraphicsDevice = pGraphicsDevice; 407 408 // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field 409 ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject; 410 411 // Should we change the ative mode of pGraphicsDevice ? 412 ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm); 413 414 /* FIXME! */ 415 ppdev->flFlags = PDEV_DISPLAY; 416 417 /* HACK: Don't use the pointer */ 418 ppdev->Pointer.Exclude.right = -1; 419 420 /* Call the driver to enable the PDEV */ 421 if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL)) 422 { 423 DPRINT1("Failed to enable PDEV!\n"); 424 PDEVOBJ_vRelease(ppdev); 425 return NULL; 426 } 427 428 /* FIXME: this must be done in a better way */ 429 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; 430 431 /* Tell the driver that the PDEV is ready */ 432 PDEVOBJ_vCompletePDEV(ppdev); 433 434 /* Return the PDEV */ 435 return ppdev; 436 } 437 438 FORCEINLINE 439 VOID 440 SwitchPointer( 441 _Inout_ PVOID pvPointer1, 442 _Inout_ PVOID pvPointer2) 443 { 444 PVOID *ppvPointer1 = pvPointer1; 445 PVOID *ppvPointer2 = pvPointer2; 446 PVOID pvTemp; 447 448 pvTemp = *ppvPointer1; 449 *ppvPointer1 = *ppvPointer2; 450 *ppvPointer2 = pvTemp; 451 } 452 453 VOID 454 NTAPI 455 PDEVOBJ_vSwitchPdev( 456 PPDEVOBJ ppdev, 457 PPDEVOBJ ppdev2) 458 { 459 union 460 { 461 DRIVER_FUNCTIONS pfn; 462 GDIINFO gdiinfo; 463 DEVINFO devinfo; 464 DWORD StateFlags; 465 } temp; 466 467 /* Exchange driver functions */ 468 temp.pfn = ppdev->pfn; 469 ppdev->pfn = ppdev2->pfn; 470 ppdev2->pfn = temp.pfn; 471 472 /* Exchange LDEVs */ 473 SwitchPointer(&ppdev->pldev, &ppdev2->pldev); 474 475 /* Exchange DHPDEV */ 476 SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev); 477 478 /* Exchange surfaces and associate them with their new PDEV */ 479 SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface); 480 ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev; 481 ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2; 482 483 /* Exchange devinfo */ 484 temp.devinfo = ppdev->devinfo; 485 ppdev->devinfo = ppdev2->devinfo; 486 ppdev2->devinfo = temp.devinfo; 487 488 /* Exchange gdiinfo */ 489 temp.gdiinfo = ppdev->gdiinfo; 490 ppdev->gdiinfo = ppdev2->gdiinfo; 491 ppdev2->gdiinfo = temp.gdiinfo; 492 493 /* Exchange DEVMODE */ 494 SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev); 495 496 /* Exchange state flags */ 497 temp.StateFlags = ppdev->pGraphicsDevice->StateFlags; 498 ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags; 499 ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags; 500 501 /* Notify each driver instance of its new HDEV association */ 502 ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 503 ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2); 504 } 505 506 507 BOOL 508 NTAPI 509 PDEVOBJ_bSwitchMode( 510 PPDEVOBJ ppdev, 511 PDEVMODEW pdm) 512 { 513 UNICODE_STRING ustrDevice; 514 PPDEVOBJ ppdevTmp; 515 PSURFACE pSurface; 516 BOOL retval = FALSE; 517 518 /* Lock the PDEV */ 519 EngAcquireSemaphore(ppdev->hsemDevLock); 520 521 /* And everything else */ 522 EngAcquireSemaphore(ghsemPDEV); 523 524 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 525 526 // Lookup the GraphicsDevice + select DEVMODE 527 // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm); 528 529 /* 1. Temporarily disable the current PDEV and reset video to its default mode */ 530 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE)) 531 { 532 DPRINT1("DrvAssertMode(FALSE) failed\n"); 533 goto leave; 534 } 535 536 /* 2. Create new PDEV */ 537 RtlInitUnicodeString(&ustrDevice, ppdev->pGraphicsDevice->szWinDeviceName); 538 ppdevTmp = EngpCreatePDEV(&ustrDevice, pdm); 539 if (!ppdevTmp) 540 { 541 DPRINT1("Failed to create a new PDEV\n"); 542 goto leave2; 543 } 544 545 /* 3. Create a new surface */ 546 pSurface = PDEVOBJ_pSurface(ppdevTmp); 547 if (!pSurface) 548 { 549 DPRINT1("PDEVOBJ_pSurface failed\n"); 550 PDEVOBJ_vRelease(ppdevTmp); 551 goto leave2; 552 } 553 554 /* 4. Get DirectDraw information */ 555 /* 5. Enable DirectDraw Not traced */ 556 /* 6. Copy old PDEV state to new PDEV instance */ 557 558 /* 7. Switch the PDEVs */ 559 PDEVOBJ_vSwitchPdev(ppdev, ppdevTmp); 560 561 /* 8. Disable DirectDraw */ 562 563 PDEVOBJ_vRelease(ppdevTmp); 564 565 /* Update primary display capabilities */ 566 if (ppdev == gppdevPrimary) 567 { 568 PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps); 569 } 570 571 /* Success! */ 572 retval = TRUE; 573 574 leave2: 575 /* Set the new video mode, or restore the original one in case of failure */ 576 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, TRUE)) 577 { 578 DPRINT1("DrvAssertMode(TRUE) failed\n"); 579 } 580 581 leave: 582 /* Unlock everything else */ 583 EngReleaseSemaphore(ghsemPDEV); 584 /* Unlock the PDEV */ 585 EngReleaseSemaphore(ppdev->hsemDevLock); 586 587 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 588 589 return retval; 590 } 591 592 593 PPDEVOBJ 594 NTAPI 595 EngpGetPDEV( 596 _In_opt_ PUNICODE_STRING pustrDeviceName) 597 { 598 UNICODE_STRING ustrCurrent; 599 PPDEVOBJ ppdev; 600 PGRAPHICS_DEVICE pGraphicsDevice; 601 602 /* Acquire PDEV lock */ 603 EngAcquireSemaphore(ghsemPDEV); 604 605 /* Did the caller pass a device name? */ 606 if (pustrDeviceName) 607 { 608 /* Loop all present PDEVs */ 609 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 610 { 611 /* Get a pointer to the GRAPHICS_DEVICE */ 612 pGraphicsDevice = ppdev->pGraphicsDevice; 613 614 /* Compare the name */ 615 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 616 if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE)) 617 { 618 /* Found! */ 619 break; 620 } 621 } 622 } 623 else 624 { 625 /* Otherwise use the primary PDEV */ 626 ppdev = gppdevPrimary; 627 } 628 629 /* Did we find one? */ 630 if (ppdev) 631 { 632 /* Yes, reference the PDEV */ 633 PDEVOBJ_vReference(ppdev); 634 } 635 else 636 { 637 /* No, create a new PDEV for the given device */ 638 ppdev = EngpCreatePDEV(pustrDeviceName, NULL); 639 if (ppdev) 640 { 641 /* Insert the PDEV into the list */ 642 ppdev->ppdevNext = gppdevList; 643 gppdevList = ppdev; 644 645 /* Set as primary PDEV, if we don't have one yet */ 646 if (!gppdevPrimary) 647 { 648 gppdevPrimary = ppdev; 649 ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; 650 } 651 } 652 } 653 654 /* Release PDEV lock */ 655 EngReleaseSemaphore(ghsemPDEV); 656 657 return ppdev; 658 } 659 660 INT 661 NTAPI 662 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev) 663 { 664 INT ret = CM_NONE; 665 666 if (ppdev->flFlags & PDEV_DISPLAY) 667 { 668 if (ppdev->devinfo.iDitherFormat == BMF_8BPP || 669 ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP) 670 ret = CM_GAMMA_RAMP; 671 } 672 673 if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR) 674 ret |= CM_CMYK_COLOR; 675 if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM) 676 ret |= CM_DEVICE_ICM; 677 678 return ret; 679 } 680 681 VOID 682 NTAPI 683 PDEVOBJ_vGetDeviceCaps( 684 IN PPDEVOBJ ppdev, 685 OUT PDEVCAPS pDevCaps) 686 { 687 PGDIINFO pGdiInfo = &ppdev->gdiinfo; 688 689 pDevCaps->ulVersion = pGdiInfo->ulVersion; 690 pDevCaps->ulTechnology = pGdiInfo->ulTechnology; 691 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000; 692 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000; 693 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize; 694 pDevCaps->ulVertSize = pGdiInfo->ulVertSize; 695 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes; 696 pDevCaps->ulVertRes = pGdiInfo->ulVertRes; 697 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel; 698 if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16; 699 pDevCaps->ulPlanes = pGdiInfo->cPlanes; 700 pDevCaps->ulNumPens = pGdiInfo->ulNumColors; 701 if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5; 702 pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev); 703 pDevCaps->ulNumColors = pGdiInfo->ulNumColors; 704 pDevCaps->ulRasterCaps = pGdiInfo->flRaster; 705 pDevCaps->ulAspectX = pGdiInfo->ulAspectX; 706 pDevCaps->ulAspectY = pGdiInfo->ulAspectY; 707 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY; 708 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX; 709 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY; 710 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg; 711 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + 712 pGdiInfo->ulDACGreen + 713 pGdiInfo->ulDACBlue; 714 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx; 715 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy; 716 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x; 717 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y; 718 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps; 719 pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER); 720 if (pGdiInfo->ulTechnology != DT_PLOTTER) 721 pDevCaps->ulTextCaps |= TC_VA_ABLE; 722 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh; 723 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes; 724 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes; 725 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment; 726 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes; 727 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes; 728 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment; 729 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment; 730 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend; 731 pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev); 732 } 733 734 735 /** Exported functions ********************************************************/ 736 737 _Must_inspect_result_ _Ret_z_ 738 LPWSTR 739 APIENTRY 740 EngGetDriverName(_In_ HDEV hdev) 741 { 742 PPDEVOBJ ppdev = (PPDEVOBJ)hdev; 743 744 ASSERT(ppdev); 745 ASSERT(ppdev->pldev); 746 ASSERT(ppdev->pldev->pGdiDriverInfo); 747 ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer); 748 749 return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer; 750 } 751 752 753 INT 754 APIENTRY 755 NtGdiGetDeviceCaps( 756 HDC hdc, 757 INT Index) 758 { 759 PDC pdc; 760 DEVCAPS devcaps; 761 762 /* Lock the given DC */ 763 pdc = DC_LockDc(hdc); 764 if (!pdc) 765 { 766 EngSetLastError(ERROR_INVALID_HANDLE); 767 return 0; 768 } 769 770 /* Get the data */ 771 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 772 773 /* Unlock the DC */ 774 DC_UnlockDc(pdc); 775 776 /* Return capability */ 777 switch (Index) 778 { 779 case DRIVERVERSION: 780 return devcaps.ulVersion; 781 782 case TECHNOLOGY: 783 return devcaps.ulTechnology; 784 785 case HORZSIZE: 786 return devcaps.ulHorzSize; 787 788 case VERTSIZE: 789 return devcaps.ulVertSize; 790 791 case HORZRES: 792 return devcaps.ulHorzRes; 793 794 case VERTRES: 795 return devcaps.ulVertRes; 796 797 case LOGPIXELSX: 798 return devcaps.ulLogPixelsX; 799 800 case LOGPIXELSY: 801 return devcaps.ulLogPixelsY; 802 803 case BITSPIXEL: 804 return devcaps.ulBitsPixel; 805 806 case PLANES: 807 return devcaps.ulPlanes; 808 809 case NUMBRUSHES: 810 return -1; 811 812 case NUMPENS: 813 return devcaps.ulNumPens; 814 815 case NUMFONTS: 816 return devcaps.ulNumFonts; 817 818 case NUMCOLORS: 819 return devcaps.ulNumColors; 820 821 case ASPECTX: 822 return devcaps.ulAspectX; 823 824 case ASPECTY: 825 return devcaps.ulAspectY; 826 827 case ASPECTXY: 828 return devcaps.ulAspectXY; 829 830 case CLIPCAPS: 831 return CP_RECTANGLE; 832 833 case SIZEPALETTE: 834 return devcaps.ulSizePalette; 835 836 case NUMRESERVED: 837 return 20; 838 839 case COLORRES: 840 return devcaps.ulColorRes; 841 842 case DESKTOPVERTRES: 843 return devcaps.ulVertRes; 844 845 case DESKTOPHORZRES: 846 return devcaps.ulHorzRes; 847 848 case BLTALIGNMENT: 849 return devcaps.ulBltAlignment; 850 851 case SHADEBLENDCAPS: 852 return devcaps.ulShadeBlend; 853 854 case COLORMGMTCAPS: 855 return devcaps.ulColorMgmtCaps; 856 857 case PHYSICALWIDTH: 858 return devcaps.ulPhysicalWidth; 859 860 case PHYSICALHEIGHT: 861 return devcaps.ulPhysicalHeight; 862 863 case PHYSICALOFFSETX: 864 return devcaps.ulPhysicalOffsetX; 865 866 case PHYSICALOFFSETY: 867 return devcaps.ulPhysicalOffsetY; 868 869 case VREFRESH: 870 return devcaps.ulVRefresh; 871 872 case RASTERCAPS: 873 return devcaps.ulRasterCaps; 874 875 case CURVECAPS: 876 return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | 877 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); 878 879 case LINECAPS: 880 return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | 881 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); 882 883 case POLYGONALCAPS: 884 return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | 885 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); 886 887 case TEXTCAPS: 888 return devcaps.ulTextCaps; 889 890 case CAPS1: 891 case PDEVICESIZE: 892 case SCALINGFACTORX: 893 case SCALINGFACTORY: 894 default: 895 return 0; 896 } 897 898 return 0; 899 } 900 901 _Success_(return!=FALSE) 902 BOOL 903 APIENTRY 904 NtGdiGetDeviceCapsAll( 905 IN HDC hDC, 906 OUT PDEVCAPS pDevCaps) 907 { 908 PDC pdc; 909 DEVCAPS devcaps; 910 BOOL bResult = TRUE; 911 912 /* Lock the given DC */ 913 pdc = DC_LockDc(hDC); 914 if (!pdc) 915 { 916 EngSetLastError(ERROR_INVALID_HANDLE); 917 return FALSE; 918 } 919 920 /* Get the data */ 921 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 922 923 /* Unlock the DC */ 924 DC_UnlockDc(pdc); 925 926 /* Copy data to caller */ 927 _SEH2_TRY 928 { 929 ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1); 930 RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS)); 931 } 932 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 933 { 934 SetLastNtError(_SEH2_GetExceptionCode()); 935 bResult = FALSE; 936 } 937 _SEH2_END; 938 939 return bResult; 940 } 941 942 DHPDEV 943 APIENTRY 944 NtGdiGetDhpdev( 945 IN HDEV hdev) 946 { 947 PPDEVOBJ ppdev; 948 DHPDEV dhpdev = NULL; 949 950 /* Check parameter */ 951 if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart) 952 return NULL; 953 954 /* Lock PDEV list */ 955 EngAcquireSemaphoreShared(ghsemPDEV); 956 957 /* Walk through the list of PDEVs */ 958 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 959 { 960 /* Compare with the given HDEV */ 961 if (ppdev == (PPDEVOBJ)hdev) 962 { 963 /* Found the PDEV! Get it's dhpdev and break */ 964 dhpdev = ppdev->dhpdev; 965 break; 966 } 967 } 968 969 /* Unlock PDEV list */ 970 EngReleaseSemaphore(ghsemPDEV); 971 972 return dhpdev; 973 } 974 975 PSIZEL 976 FASTCALL 977 PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl) 978 { 979 if (ppdev->flFlags & PDEV_META_DEVICE) 980 { 981 psizl->cx = ppdev->ulHorzRes; 982 psizl->cy = ppdev->ulVertRes; 983 } 984 else 985 { 986 psizl->cx = ppdev->gdiinfo.ulHorzRes; 987 psizl->cy = ppdev->gdiinfo.ulVertRes; 988 } 989 return psizl; 990 } 991