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 DBG_DEFAULT_CHANNEL(EngPDev); 13 14 static PPDEVOBJ gppdevList = NULL; 15 static HSEMAPHORE ghsemPDEV; 16 17 BOOL 18 APIENTRY 19 MultiEnableDriver( 20 _In_ ULONG iEngineVersion, 21 _In_ ULONG cj, 22 _Inout_bytecount_(cj) PDRVENABLEDATA pded); 23 24 CODE_SEG("INIT") 25 NTSTATUS 26 NTAPI 27 InitPDEVImpl(VOID) 28 { 29 ghsemPDEV = EngCreateSemaphore(); 30 if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES; 31 return STATUS_SUCCESS; 32 } 33 34 #if DBG 35 PPDEVOBJ 36 NTAPI 37 DbgLookupDHPDEV(DHPDEV dhpdev) 38 { 39 PPDEVOBJ ppdev; 40 41 /* Lock PDEV list */ 42 EngAcquireSemaphoreShared(ghsemPDEV); 43 44 /* Walk through the list of PDEVs */ 45 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 46 { 47 /* Compare with the given DHPDEV */ 48 if (ppdev->dhpdev == dhpdev) break; 49 } 50 51 /* Unlock PDEV list */ 52 EngReleaseSemaphore(ghsemPDEV); 53 54 return ppdev; 55 } 56 #endif 57 58 PPDEVOBJ 59 PDEVOBJ_AllocPDEV(VOID) 60 { 61 PPDEVOBJ ppdev; 62 63 ppdev = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), GDITAG_PDEV); 64 if (!ppdev) 65 return NULL; 66 67 RtlZeroMemory(ppdev, sizeof(PDEVOBJ)); 68 69 ppdev->hsemDevLock = EngCreateSemaphore(); 70 if (ppdev->hsemDevLock == NULL) 71 { 72 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 73 return NULL; 74 } 75 76 /* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */ 77 ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV); 78 if (ppdev->pEDDgpl) 79 RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL)); 80 81 ppdev->cPdevRefs = 1; 82 83 return ppdev; 84 } 85 86 static 87 VOID 88 PDEVOBJ_vDeletePDEV( 89 PPDEVOBJ ppdev) 90 { 91 EngDeleteSemaphore(ppdev->hsemDevLock); 92 if (ppdev->pdmwDev) 93 ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE); 94 if (ppdev->pEDDgpl) 95 ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV); 96 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 97 } 98 99 VOID 100 NTAPI 101 PDEVOBJ_vRelease( 102 _Inout_ PPDEVOBJ ppdev) 103 { 104 /* Lock loader */ 105 EngAcquireSemaphore(ghsemPDEV); 106 107 /* Decrease reference count */ 108 InterlockedDecrement(&ppdev->cPdevRefs); 109 ASSERT(ppdev->cPdevRefs >= 0); 110 111 /* Check if references are left */ 112 if (ppdev->cPdevRefs == 0) 113 { 114 /* Do we have a surface? */ 115 if (ppdev->pSurface) 116 { 117 /* Release the surface and let the driver free it */ 118 SURFACE_ShareUnlockSurface(ppdev->pSurface); 119 TRACE("DrvDisableSurface(dhpdev %p)\n", ppdev->dhpdev); 120 ppdev->pfn.DisableSurface(ppdev->dhpdev); 121 } 122 123 /* Do we have a palette? */ 124 if (ppdev->ppalSurf) 125 { 126 PALETTE_ShareUnlockPalette(ppdev->ppalSurf); 127 } 128 129 /* Check if the PDEV was enabled */ 130 if (ppdev->dhpdev != NULL) 131 { 132 /* Disable the PDEV */ 133 TRACE("DrvDisablePDEV(dhpdev %p)\n", ppdev->dhpdev); 134 ppdev->pfn.DisablePDEV(ppdev->dhpdev); 135 } 136 137 /* Remove it from list */ 138 if (ppdev == gppdevList) 139 { 140 gppdevList = ppdev->ppdevNext; 141 } 142 else if (gppdevList) 143 { 144 PPDEVOBJ ppdevCurrent = gppdevList; 145 BOOL found = FALSE; 146 while (!found && ppdevCurrent->ppdevNext) 147 { 148 if (ppdevCurrent->ppdevNext == ppdev) 149 found = TRUE; 150 else 151 ppdevCurrent = ppdevCurrent->ppdevNext; 152 } 153 if (found) 154 ppdevCurrent->ppdevNext = ppdev->ppdevNext; 155 } 156 157 /* Unload display driver */ 158 EngUnloadImage(ppdev->pldev); 159 160 /* Free it */ 161 PDEVOBJ_vDeletePDEV(ppdev); 162 } 163 164 /* Unlock loader */ 165 EngReleaseSemaphore(ghsemPDEV); 166 } 167 168 BOOL 169 NTAPI 170 PDEVOBJ_bEnablePDEV( 171 _In_ PPDEVOBJ ppdev, 172 _In_ PDEVMODEW pdevmode, 173 _In_ PWSTR pwszLogAddress) 174 { 175 PFN_DrvEnablePDEV pfnEnablePDEV; 176 ULONG i; 177 178 /* Get the DrvEnablePDEV function */ 179 pfnEnablePDEV = ppdev->pldev->pfn.EnablePDEV; 180 181 /* Call the drivers DrvEnablePDEV function */ 182 TRACE("DrvEnablePDEV(pdevmode %p (%dx%dx%d %d Hz) hdev %p (%S))\n", 183 pdevmode, 184 ppdev->pGraphicsDevice ? pdevmode->dmPelsWidth : 0, 185 ppdev->pGraphicsDevice ? pdevmode->dmPelsHeight : 0, 186 ppdev->pGraphicsDevice ? pdevmode->dmBitsPerPel : 0, 187 ppdev->pGraphicsDevice ? pdevmode->dmDisplayFrequency : 0, 188 ppdev, 189 ppdev->pGraphicsDevice ? ppdev->pGraphicsDevice->szNtDeviceName : L""); 190 ppdev->dhpdev = pfnEnablePDEV(pdevmode, 191 pwszLogAddress, 192 HS_DDI_MAX, 193 ppdev->ahsurf, 194 sizeof(GDIINFO), 195 (PULONG)&ppdev->gdiinfo, 196 sizeof(DEVINFO), 197 &ppdev->devinfo, 198 (HDEV)ppdev, 199 ppdev->pGraphicsDevice ? ppdev->pGraphicsDevice->pwszDescription : NULL, 200 ppdev->pGraphicsDevice ? ppdev->pGraphicsDevice->DeviceObject : NULL); 201 TRACE("DrvEnablePDEV(pdevmode %p hdev %p) => dhpdev %p\n", pdevmode, ppdev, ppdev->dhpdev); 202 if (ppdev->dhpdev == NULL) 203 { 204 ERR("Failed to enable PDEV\n"); 205 return FALSE; 206 } 207 208 /* Fix up some values */ 209 if (ppdev->gdiinfo.ulLogPixelsX == 0) 210 ppdev->gdiinfo.ulLogPixelsX = 96; 211 212 if (ppdev->gdiinfo.ulLogPixelsY == 0) 213 ppdev->gdiinfo.ulLogPixelsY = 96; 214 215 /* Set raster caps */ 216 ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT; 217 if ((ppdev->gdiinfo.ulTechnology != DT_PLOTTER) && (ppdev->gdiinfo.ulTechnology != DT_CHARSTREAM)) 218 ppdev->gdiinfo.flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_DI_BITMAP | RC_BITMAP64 | RC_BITBLT; 219 if (ppdev->gdiinfo.ulTechnology == DT_RASDISPLAY) 220 ppdev->gdiinfo.flRaster |= RC_FLOODFILL; 221 if (ppdev->devinfo.flGraphicsCaps & GCAPS_PALMANAGED) 222 ppdev->gdiinfo.flRaster |= RC_PALETTE; 223 224 /* Setup Palette */ 225 ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); 226 227 /* Setup hatch brushes */ 228 for (i = 0; i < HS_DDI_MAX; i++) 229 { 230 if (ppdev->ahsurf[i] == NULL) 231 ppdev->ahsurf[i] = gahsurfHatch[i]; 232 } 233 234 TRACE("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev->dhpdev); 235 236 return TRUE; 237 } 238 239 VOID 240 NTAPI 241 PDEVOBJ_vCompletePDEV( 242 PPDEVOBJ ppdev) 243 { 244 /* Call the drivers DrvCompletePDEV function */ 245 TRACE("DrvCompletePDEV(dhpdev %p hdev %p)\n", ppdev->dhpdev, ppdev); 246 ppdev->pldev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 247 } 248 249 static 250 VOID 251 PDEVOBJ_vFilterDriverHooks( 252 _In_ PPDEVOBJ ppdev) 253 { 254 PLDEVOBJ pldev = ppdev->pldev; 255 ULONG dwAccelerationLevel = ppdev->dwAccelerationLevel; 256 257 if (!pldev->pGdiDriverInfo) 258 return; 259 if (pldev->ldevtype != LDEV_DEVICE_DISPLAY) 260 return; 261 262 if (dwAccelerationLevel >= 1) 263 { 264 ppdev->apfn[INDEX_DrvSetPointerShape] = NULL; 265 ppdev->apfn[INDEX_DrvCreateDeviceBitmap] = NULL; 266 } 267 268 if (dwAccelerationLevel >= 2) 269 { 270 /* Remove sophisticated display accelerations */ 271 ppdev->pSurface->flags &= ~(HOOK_STRETCHBLT | 272 HOOK_FILLPATH | 273 HOOK_GRADIENTFILL | 274 HOOK_LINETO | 275 HOOK_ALPHABLEND | 276 HOOK_TRANSPARENTBLT); 277 } 278 279 if (dwAccelerationLevel >= 3) 280 { 281 /* Disable DirectDraw and Direct3D accelerations */ 282 /* FIXME: need to call DxDdSetAccelLevel */ 283 UNIMPLEMENTED; 284 } 285 286 if (dwAccelerationLevel >= 4) 287 { 288 /* Remove almost all display accelerations */ 289 ppdev->pSurface->flags &= ~HOOK_FLAGS | 290 HOOK_BITBLT | 291 HOOK_COPYBITS | 292 HOOK_TEXTOUT | 293 HOOK_STROKEPATH | 294 HOOK_SYNCHRONIZE; 295 296 } 297 298 if (dwAccelerationLevel >= 5) 299 { 300 /* Disable all display accelerations */ 301 UNIMPLEMENTED; 302 } 303 } 304 305 PSURFACE 306 NTAPI 307 PDEVOBJ_pSurface( 308 PPDEVOBJ ppdev) 309 { 310 HSURF hsurf; 311 312 /* Check if there is no surface for this PDEV yet */ 313 if (ppdev->pSurface == NULL) 314 { 315 /* Call the drivers DrvEnableSurface */ 316 TRACE("DrvEnableSurface(dhpdev %p)\n", ppdev->dhpdev); 317 hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev); 318 TRACE("DrvEnableSurface(dhpdev %p) => hsurf %p\n", ppdev->dhpdev, hsurf); 319 if (hsurf== NULL) 320 { 321 ERR("Failed to create PDEV surface!\n"); 322 return NULL; 323 } 324 325 /* Get a reference to the surface */ 326 ppdev->pSurface = SURFACE_ShareLockSurface(hsurf); 327 NT_ASSERT(ppdev->pSurface != NULL); 328 } 329 330 /* Increment reference count */ 331 GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject); 332 333 return ppdev->pSurface; 334 } 335 336 VOID 337 PDEVOBJ_vEnableDisplay( 338 _Inout_ PPDEVOBJ ppdev) 339 { 340 BOOL assertVal; 341 342 if (!(ppdev->flFlags & PDEV_DISABLED)) 343 return; 344 345 /* Try to enable display until success */ 346 do 347 { 348 TRACE("DrvAssertMode(dhpdev %p, TRUE)\n", ppdev->dhpdev); 349 assertVal = ppdev->pfn.AssertMode(ppdev->dhpdev, TRUE); 350 TRACE("DrvAssertMode(dhpdev %p, TRUE) => %d\n", ppdev->dhpdev, assertVal); 351 } while (!assertVal); 352 353 ppdev->flFlags &= ~PDEV_DISABLED; 354 } 355 356 BOOL 357 PDEVOBJ_bDisableDisplay( 358 _Inout_ PPDEVOBJ ppdev) 359 { 360 BOOL assertVal; 361 362 if (ppdev->flFlags & PDEV_DISABLED) 363 return TRUE; 364 365 TRACE("DrvAssertMode(dhpdev %p, FALSE)\n", ppdev->dhpdev); 366 assertVal = ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE); 367 TRACE("DrvAssertMode(dhpdev %p, FALSE) => %d\n", ppdev->dhpdev, assertVal); 368 369 if (assertVal) 370 ppdev->flFlags |= PDEV_DISABLED; 371 372 return assertVal; 373 } 374 375 VOID 376 NTAPI 377 PDEVOBJ_vRefreshModeList( 378 PPDEVOBJ ppdev) 379 { 380 PGRAPHICS_DEVICE pGraphicsDevice; 381 PDEVMODEINFO pdminfo, pdmiNext; 382 383 /* Lock the PDEV */ 384 EngAcquireSemaphore(ppdev->hsemDevLock); 385 386 pGraphicsDevice = ppdev->pGraphicsDevice; 387 388 /* Clear out the modes */ 389 for (pdminfo = pGraphicsDevice->pdevmodeInfo; 390 pdminfo; 391 pdminfo = pdmiNext) 392 { 393 pdmiNext = pdminfo->pdmiNext; 394 ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE); 395 } 396 pGraphicsDevice->pdevmodeInfo = NULL; 397 ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE); 398 pGraphicsDevice->pDevModeList = NULL; 399 400 /* Update available display mode list */ 401 LDEVOBJ_bBuildDevmodeList(pGraphicsDevice); 402 403 /* Unlock PDEV */ 404 EngReleaseSemaphore(ppdev->hsemDevLock); 405 } 406 407 PPDEVOBJ 408 PDEVOBJ_Create( 409 _In_opt_ PGRAPHICS_DEVICE pGraphicsDevice, 410 _In_opt_ PDEVMODEW pdm, 411 _In_ ULONG dwAccelerationLevel, 412 _In_ ULONG ldevtype) 413 { 414 PPDEVOBJ ppdev, ppdevMatch = NULL; 415 PLDEVOBJ pldev; 416 PSURFACE pSurface; 417 418 TRACE("PDEVOBJ_Create(%p %p %d)\n", pGraphicsDevice, pdm, ldevtype); 419 420 if (ldevtype != LDEV_DEVICE_META) 421 { 422 ASSERT(pGraphicsDevice); 423 ASSERT(pdm); 424 /* Search if we already have a PPDEV with the required characteristics. 425 * We will compare the graphics device, the devmode and the desktop 426 */ 427 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 428 { 429 if (ppdev->pGraphicsDevice == pGraphicsDevice) 430 { 431 PDEVOBJ_vReference(ppdev); 432 433 if (RtlEqualMemory(pdm, ppdev->pdmwDev, sizeof(DEVMODEW)) && 434 ppdev->dwAccelerationLevel == dwAccelerationLevel) 435 { 436 PDEVOBJ_vReference(ppdev); 437 ppdevMatch = ppdev; 438 } 439 else 440 { 441 PDEVOBJ_bDisableDisplay(ppdev); 442 } 443 444 PDEVOBJ_vRelease(ppdev); 445 } 446 } 447 448 if (ppdevMatch) 449 { 450 PDEVOBJ_vEnableDisplay(ppdevMatch); 451 452 return ppdevMatch; 453 } 454 } 455 456 /* Try to get a display driver */ 457 if (ldevtype == LDEV_DEVICE_META) 458 pldev = LDEVOBJ_pLoadInternal(MultiEnableDriver, ldevtype); 459 else 460 pldev = LDEVOBJ_pLoadDriver(pdm->dmDeviceName, ldevtype); 461 if (!pldev) 462 { 463 ERR("Could not load display driver '%S'\n", 464 (ldevtype == LDEV_DEVICE_META) ? L"" : pdm->dmDeviceName); 465 return NULL; 466 } 467 468 /* Allocate a new PDEVOBJ */ 469 ppdev = PDEVOBJ_AllocPDEV(); 470 if (!ppdev) 471 { 472 ERR("failed to allocate a PDEV\n"); 473 return NULL; 474 } 475 476 if (ldevtype != LDEV_DEVICE_META) 477 { 478 ppdev->pGraphicsDevice = pGraphicsDevice; 479 480 // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field 481 ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject; 482 483 /* Keep selected resolution */ 484 if (ppdev->pdmwDev) 485 ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE); 486 ppdev->pdmwDev = ExAllocatePoolWithTag(PagedPool, pdm->dmSize + pdm->dmDriverExtra, GDITAG_DEVMODE); 487 if (ppdev->pdmwDev) 488 { 489 RtlCopyMemory(ppdev->pdmwDev, pdm, pdm->dmSize + pdm->dmDriverExtra); 490 /* FIXME: this must be done in a better way */ 491 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; 492 } 493 } 494 495 /* FIXME! */ 496 ppdev->flFlags = PDEV_DISPLAY; 497 498 /* HACK: Don't use the pointer */ 499 ppdev->Pointer.Exclude.right = -1; 500 501 /* Initialize PDEV */ 502 ppdev->pldev = pldev; 503 ppdev->dwAccelerationLevel = dwAccelerationLevel; 504 505 /* Call the driver to enable the PDEV */ 506 if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL)) 507 { 508 ERR("Failed to enable PDEV!\n"); 509 PDEVOBJ_vRelease(ppdev); 510 EngUnloadImage(pldev); 511 return NULL; 512 } 513 514 /* Copy the function table */ 515 ppdev->pfn = ppdev->pldev->pfn; 516 517 /* Tell the driver that the PDEV is ready */ 518 PDEVOBJ_vCompletePDEV(ppdev); 519 520 /* Create the initial surface */ 521 pSurface = PDEVOBJ_pSurface(ppdev); 522 if (!pSurface) 523 { 524 ERR("Failed to create surface\n"); 525 PDEVOBJ_vRelease(ppdev); 526 EngUnloadImage(pldev); 527 return NULL; 528 } 529 530 /* Remove some acceleration capabilities from driver */ 531 PDEVOBJ_vFilterDriverHooks(ppdev); 532 533 /* Set MovePointer function */ 534 ppdev->pfnMovePointer = ppdev->pfn.MovePointer; 535 if (!ppdev->pfnMovePointer) 536 ppdev->pfnMovePointer = EngMovePointer; 537 538 /* Insert the PDEV into the list */ 539 ppdev->ppdevNext = gppdevList; 540 gppdevList = ppdev; 541 542 /* Return the PDEV */ 543 return ppdev; 544 } 545 546 FORCEINLINE 547 VOID 548 SwitchPointer( 549 _Inout_ PVOID pvPointer1, 550 _Inout_ PVOID pvPointer2) 551 { 552 PVOID *ppvPointer1 = pvPointer1; 553 PVOID *ppvPointer2 = pvPointer2; 554 PVOID pvTemp; 555 556 pvTemp = *ppvPointer1; 557 *ppvPointer1 = *ppvPointer2; 558 *ppvPointer2 = pvTemp; 559 } 560 561 BOOL 562 NTAPI 563 PDEVOBJ_bDynamicModeChange( 564 PPDEVOBJ ppdev, 565 PPDEVOBJ ppdev2) 566 { 567 union 568 { 569 DRIVER_FUNCTIONS pfn; 570 GDIINFO gdiinfo; 571 DEVINFO devinfo; 572 DWORD StateFlags; 573 } temp; 574 575 /* Exchange driver functions */ 576 temp.pfn = ppdev->pfn; 577 ppdev->pfn = ppdev2->pfn; 578 ppdev2->pfn = temp.pfn; 579 580 /* Exchange LDEVs */ 581 SwitchPointer(&ppdev->pldev, &ppdev2->pldev); 582 583 /* Exchange DHPDEV */ 584 SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev); 585 586 /* Exchange surfaces and associate them with their new PDEV */ 587 SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface); 588 ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev; 589 ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2; 590 591 /* Exchange devinfo */ 592 temp.devinfo = ppdev->devinfo; 593 ppdev->devinfo = ppdev2->devinfo; 594 ppdev2->devinfo = temp.devinfo; 595 596 /* Exchange gdiinfo */ 597 temp.gdiinfo = ppdev->gdiinfo; 598 ppdev->gdiinfo = ppdev2->gdiinfo; 599 ppdev2->gdiinfo = temp.gdiinfo; 600 601 /* Exchange DEVMODE */ 602 SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev); 603 604 /* Exchange state flags */ 605 temp.StateFlags = ppdev->pGraphicsDevice->StateFlags; 606 ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags; 607 ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags; 608 609 /* Notify each driver instance of its new HDEV association */ 610 ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 611 ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2); 612 613 return TRUE; 614 } 615 616 617 BOOL 618 NTAPI 619 PDEVOBJ_bSwitchMode( 620 PPDEVOBJ ppdev, 621 PDEVMODEW pdm) 622 { 623 PPDEVOBJ ppdevTmp; 624 PSURFACE pSurface; 625 BOOL retval = FALSE; 626 627 /* Lock the PDEV */ 628 EngAcquireSemaphore(ppdev->hsemDevLock); 629 630 /* And everything else */ 631 EngAcquireSemaphore(ghsemPDEV); 632 633 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 634 635 // Lookup the GraphicsDevice + select DEVMODE 636 // pdm = LDEVOBJ_bProbeAndCaptureDevmode(ppdev, pdm); 637 638 /* 1. Temporarily disable the current PDEV and reset video to its default mode */ 639 if (!PDEVOBJ_bDisableDisplay(ppdev)) 640 { 641 DPRINT1("PDEVOBJ_bDisableDisplay() failed\n"); 642 goto leave; 643 } 644 645 /* 2. Create new PDEV */ 646 ppdevTmp = PDEVOBJ_Create(ppdev->pGraphicsDevice, pdm, 0, LDEV_DEVICE_DISPLAY); 647 if (!ppdevTmp) 648 { 649 DPRINT1("Failed to create a new PDEV\n"); 650 goto leave2; 651 } 652 653 /* 3. Create a new surface */ 654 pSurface = PDEVOBJ_pSurface(ppdevTmp); 655 if (!pSurface) 656 { 657 DPRINT1("PDEVOBJ_pSurface failed\n"); 658 PDEVOBJ_vRelease(ppdevTmp); 659 goto leave2; 660 } 661 662 /* 4. Get DirectDraw information */ 663 /* 5. Enable DirectDraw Not traced */ 664 /* 6. Copy old PDEV state to new PDEV instance */ 665 666 /* 7. Switch the PDEVs */ 667 if (!PDEVOBJ_bDynamicModeChange(ppdev, ppdevTmp)) 668 { 669 DPRINT1("PDEVOBJ_bDynamicModeChange() failed\n"); 670 PDEVOBJ_vRelease(ppdevTmp); 671 goto leave2; 672 } 673 674 /* 8. Disable DirectDraw */ 675 676 PDEVOBJ_vRelease(ppdevTmp); 677 678 /* Update primary display capabilities */ 679 if (ppdev == gpmdev->ppdevGlobal) 680 { 681 PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps); 682 } 683 684 /* Success! */ 685 retval = TRUE; 686 687 leave2: 688 /* Set the new video mode, or restore the original one in case of failure */ 689 PDEVOBJ_vEnableDisplay(ppdev); 690 691 leave: 692 /* Unlock everything else */ 693 EngReleaseSemaphore(ghsemPDEV); 694 /* Unlock the PDEV */ 695 EngReleaseSemaphore(ppdev->hsemDevLock); 696 697 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 698 699 return retval; 700 } 701 702 703 PPDEVOBJ 704 NTAPI 705 EngpGetPDEV( 706 _In_opt_ PUNICODE_STRING pustrDeviceName) 707 { 708 UNICODE_STRING ustrCurrent; 709 PPDEVOBJ ppdev = NULL; 710 PGRAPHICS_DEVICE pGraphicsDevice; 711 ULONG i; 712 713 /* Acquire PDEV lock */ 714 EngAcquireSemaphore(ghsemPDEV); 715 716 /* Did the caller pass a device name? */ 717 if (pustrDeviceName) 718 { 719 /* Loop all present PDEVs */ 720 for (i = 0; i < gpmdev->cDev; i++) 721 { 722 /* Get a pointer to the GRAPHICS_DEVICE */ 723 pGraphicsDevice = gpmdev->dev[i].ppdev->pGraphicsDevice; 724 725 /* Compare the name */ 726 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 727 if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE)) 728 { 729 /* Found! */ 730 ppdev = gpmdev->dev[i].ppdev; 731 break; 732 } 733 } 734 } 735 else if (gpmdev) 736 { 737 /* Otherwise use the primary PDEV */ 738 ppdev = gpmdev->ppdevGlobal; 739 } 740 741 /* Did we find one? */ 742 if (ppdev) 743 { 744 /* Yes, reference the PDEV */ 745 PDEVOBJ_vReference(ppdev); 746 } 747 748 /* Release PDEV lock */ 749 EngReleaseSemaphore(ghsemPDEV); 750 751 return ppdev; 752 } 753 754 LONG 755 PDEVOBJ_lChangeDisplaySettings( 756 _In_opt_ PUNICODE_STRING pustrDeviceName, 757 _In_opt_ PDEVMODEW RequestedMode, 758 _In_opt_ PMDEVOBJ pmdevOld, 759 _Out_ PMDEVOBJ *ppmdevNew, 760 _In_ BOOL bSearchClosestMode) 761 { 762 PGRAPHICS_DEVICE pGraphicsDevice = NULL; 763 PMDEVOBJ pmdev = NULL; 764 PDEVMODEW pdm = NULL; 765 ULONG lRet = DISP_CHANGE_SUCCESSFUL; 766 ULONG i, j; 767 768 TRACE("PDEVOBJ_lChangeDisplaySettings('%wZ' '%dx%dx%d (%d Hz)' %p %p)\n", 769 pustrDeviceName, 770 RequestedMode ? RequestedMode->dmPelsWidth : 0, 771 RequestedMode ? RequestedMode->dmPelsHeight : 0, 772 RequestedMode ? RequestedMode->dmBitsPerPel : 0, 773 RequestedMode ? RequestedMode->dmDisplayFrequency : 0, 774 pmdevOld, ppmdevNew); 775 776 if (pustrDeviceName) 777 { 778 pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0); 779 if (!pGraphicsDevice) 780 { 781 ERR("Wrong device name provided: '%wZ'\n", pustrDeviceName); 782 lRet = DISP_CHANGE_BADPARAM; 783 goto cleanup; 784 } 785 } 786 else if (RequestedMode) 787 { 788 pGraphicsDevice = gpPrimaryGraphicsDevice; 789 if (!pGraphicsDevice) 790 { 791 ERR("Wrong device'\n"); 792 lRet = DISP_CHANGE_BADPARAM; 793 goto cleanup; 794 } 795 } 796 797 if (pGraphicsDevice) 798 { 799 if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, RequestedMode, &pdm, bSearchClosestMode)) 800 { 801 ERR("DrvProbeAndCaptureDevmode() failed\n"); 802 lRet = DISP_CHANGE_BADMODE; 803 goto cleanup; 804 } 805 } 806 807 /* Here, we know that input parameters were correct */ 808 809 { 810 /* Create new MDEV. Note that if we provide a device name, 811 * MDEV will only contain one device. 812 * */ 813 814 if (pmdevOld) 815 { 816 /* Disable old MDEV */ 817 if (MDEVOBJ_bDisable(pmdevOld)) 818 { 819 /* Create new MDEV. On failure, reenable old MDEV */ 820 pmdev = MDEVOBJ_Create(pustrDeviceName, pdm); 821 if (!pmdev) 822 MDEVOBJ_vEnable(pmdevOld); 823 } 824 } 825 else 826 { 827 pmdev = MDEVOBJ_Create(pustrDeviceName, pdm); 828 } 829 830 if (!pmdev) 831 { 832 ERR("Failed to create new MDEV\n"); 833 lRet = DISP_CHANGE_FAILED; 834 goto cleanup; 835 } 836 837 lRet = DISP_CHANGE_SUCCESSFUL; 838 *ppmdevNew = pmdev; 839 840 /* We now have to do the mode switch */ 841 842 if (pustrDeviceName && pmdevOld) 843 { 844 /* We changed settings of one device. Add other devices which were already present */ 845 for (i = 0; i < pmdevOld->cDev; i++) 846 { 847 for (j = 0; j < pmdev->cDev; j++) 848 { 849 if (pmdev->dev[j].ppdev->pGraphicsDevice == pmdevOld->dev[i].ppdev->pGraphicsDevice) 850 { 851 if (PDEVOBJ_bDynamicModeChange(pmdevOld->dev[i].ppdev, pmdev->dev[j].ppdev)) 852 { 853 PPDEVOBJ tmp = pmdevOld->dev[i].ppdev; 854 pmdevOld->dev[i].ppdev = pmdev->dev[j].ppdev; 855 pmdev->dev[j].ppdev = tmp; 856 } 857 else 858 { 859 ERR("Failed to apply new settings\n"); 860 UNIMPLEMENTED; 861 ASSERT(FALSE); 862 } 863 break; 864 } 865 } 866 if (j == pmdev->cDev) 867 { 868 PDEVOBJ_vReference(pmdevOld->dev[i].ppdev); 869 pmdev->dev[pmdev->cDev].ppdev = pmdevOld->dev[i].ppdev; 870 pmdev->cDev++; 871 } 872 } 873 } 874 875 if (pmdev->cDev == 1) 876 { 877 pmdev->ppdevGlobal = pmdev->dev[0].ppdev; 878 } 879 else 880 { 881 /* Enable MultiDriver */ 882 pmdev->ppdevGlobal = PDEVOBJ_Create(NULL, (PDEVMODEW)pmdev, 0, LDEV_DEVICE_META); 883 if (!pmdev->ppdevGlobal) 884 { 885 WARN("Failed to create meta-device. Using only first display\n"); 886 PDEVOBJ_vReference(pmdev->dev[0].ppdev); 887 pmdev->ppdevGlobal = pmdev->dev[0].ppdev; 888 } 889 } 890 891 if (pmdevOld) 892 { 893 /* Search PDEVs which were in pmdevOld, but are not anymore in pmdev, and disable them */ 894 for (i = 0; i < pmdevOld->cDev; i++) 895 { 896 for (j = 0; j < pmdev->cDev; j++) 897 { 898 if (pmdev->dev[j].ppdev->pGraphicsDevice == pmdevOld->dev[i].ppdev->pGraphicsDevice) 899 break; 900 } 901 if (j == pmdev->cDev) 902 PDEVOBJ_bDisableDisplay(pmdevOld->dev[i].ppdev); 903 } 904 } 905 } 906 907 cleanup: 908 if (lRet != DISP_CHANGE_SUCCESSFUL) 909 { 910 *ppmdevNew = NULL; 911 if (pmdev) 912 MDEVOBJ_vDestroy(pmdev); 913 if (pdm && pdm != RequestedMode) 914 ExFreePoolWithTag(pdm, GDITAG_DEVMODE); 915 } 916 917 return lRet; 918 } 919 920 INT 921 NTAPI 922 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev) 923 { 924 INT ret = CM_NONE; 925 926 if (ppdev->flFlags & PDEV_DISPLAY) 927 { 928 if (ppdev->devinfo.iDitherFormat == BMF_8BPP || 929 ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP) 930 ret = CM_GAMMA_RAMP; 931 } 932 933 if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR) 934 ret |= CM_CMYK_COLOR; 935 if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM) 936 ret |= CM_DEVICE_ICM; 937 938 return ret; 939 } 940 941 VOID 942 NTAPI 943 PDEVOBJ_vGetDeviceCaps( 944 IN PPDEVOBJ ppdev, 945 OUT PDEVCAPS pDevCaps) 946 { 947 PGDIINFO pGdiInfo = &ppdev->gdiinfo; 948 949 pDevCaps->ulVersion = pGdiInfo->ulVersion; 950 pDevCaps->ulTechnology = pGdiInfo->ulTechnology; 951 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000; 952 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000; 953 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize; 954 pDevCaps->ulVertSize = pGdiInfo->ulVertSize; 955 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes; 956 pDevCaps->ulVertRes = pGdiInfo->ulVertRes; 957 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel; 958 if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16; 959 pDevCaps->ulPlanes = pGdiInfo->cPlanes; 960 pDevCaps->ulNumPens = pGdiInfo->ulNumColors; 961 if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5; 962 pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev); 963 pDevCaps->ulNumColors = pGdiInfo->ulNumColors; 964 pDevCaps->ulRasterCaps = pGdiInfo->flRaster; 965 pDevCaps->ulAspectX = pGdiInfo->ulAspectX; 966 pDevCaps->ulAspectY = pGdiInfo->ulAspectY; 967 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY; 968 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX; 969 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY; 970 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg; 971 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + 972 pGdiInfo->ulDACGreen + 973 pGdiInfo->ulDACBlue; 974 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx; 975 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy; 976 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x; 977 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y; 978 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps; 979 pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER); 980 if (pGdiInfo->ulTechnology != DT_PLOTTER) 981 pDevCaps->ulTextCaps |= TC_VA_ABLE; 982 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh; 983 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes; 984 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes; 985 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment; 986 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes; 987 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes; 988 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment; 989 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment; 990 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend; 991 pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev); 992 } 993 994 995 /** Exported functions ********************************************************/ 996 997 /* 998 * @implemented 999 */ 1000 BOOL 1001 APIENTRY 1002 EngQueryDeviceAttribute( 1003 _In_ HDEV hdev, 1004 _In_ ENG_DEVICE_ATTRIBUTE devAttr, 1005 _In_reads_bytes_(cjInSize) PVOID pvIn, 1006 _In_ ULONG cjInSize, 1007 _Out_writes_bytes_(cjOutSize) PVOID pvOut, 1008 _In_ ULONG cjOutSize) 1009 { 1010 PPDEVOBJ ppdev = (PPDEVOBJ)hdev; 1011 1012 if (devAttr != QDA_ACCELERATION_LEVEL) 1013 return FALSE; 1014 1015 if (cjOutSize >= sizeof(DWORD)) 1016 { 1017 /* Set all Accelerations Level Key to enabled Full 0 to 5 turned off. */ 1018 *(DWORD*)pvOut = ppdev->dwAccelerationLevel; 1019 return TRUE; 1020 } 1021 1022 return FALSE; 1023 } 1024 1025 _Must_inspect_result_ _Ret_z_ 1026 LPWSTR 1027 APIENTRY 1028 EngGetDriverName(_In_ HDEV hdev) 1029 { 1030 PPDEVOBJ ppdev = (PPDEVOBJ)hdev; 1031 1032 ASSERT(ppdev); 1033 ASSERT(ppdev->pldev); 1034 ASSERT(ppdev->pldev->pGdiDriverInfo); 1035 ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer); 1036 1037 return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer; 1038 } 1039 1040 1041 INT 1042 APIENTRY 1043 NtGdiGetDeviceCaps( 1044 HDC hdc, 1045 INT Index) 1046 { 1047 PDC pdc; 1048 DEVCAPS devcaps; 1049 1050 /* Lock the given DC */ 1051 pdc = DC_LockDc(hdc); 1052 if (!pdc) 1053 { 1054 EngSetLastError(ERROR_INVALID_HANDLE); 1055 return 0; 1056 } 1057 1058 /* Get the data */ 1059 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 1060 1061 /* Unlock the DC */ 1062 DC_UnlockDc(pdc); 1063 1064 /* Return capability */ 1065 switch (Index) 1066 { 1067 case DRIVERVERSION: 1068 return devcaps.ulVersion; 1069 1070 case TECHNOLOGY: 1071 return devcaps.ulTechnology; 1072 1073 case HORZSIZE: 1074 return devcaps.ulHorzSize; 1075 1076 case VERTSIZE: 1077 return devcaps.ulVertSize; 1078 1079 case HORZRES: 1080 return devcaps.ulHorzRes; 1081 1082 case VERTRES: 1083 return devcaps.ulVertRes; 1084 1085 case LOGPIXELSX: 1086 return devcaps.ulLogPixelsX; 1087 1088 case LOGPIXELSY: 1089 return devcaps.ulLogPixelsY; 1090 1091 case BITSPIXEL: 1092 return devcaps.ulBitsPixel; 1093 1094 case PLANES: 1095 return devcaps.ulPlanes; 1096 1097 case NUMBRUSHES: 1098 return -1; 1099 1100 case NUMPENS: 1101 return devcaps.ulNumPens; 1102 1103 case NUMFONTS: 1104 return devcaps.ulNumFonts; 1105 1106 case NUMCOLORS: 1107 return devcaps.ulNumColors; 1108 1109 case ASPECTX: 1110 return devcaps.ulAspectX; 1111 1112 case ASPECTY: 1113 return devcaps.ulAspectY; 1114 1115 case ASPECTXY: 1116 return devcaps.ulAspectXY; 1117 1118 case CLIPCAPS: 1119 return CP_RECTANGLE; 1120 1121 case SIZEPALETTE: 1122 return devcaps.ulSizePalette; 1123 1124 case NUMRESERVED: 1125 return 20; 1126 1127 case COLORRES: 1128 return devcaps.ulColorRes; 1129 1130 case DESKTOPVERTRES: 1131 return devcaps.ulVertRes; 1132 1133 case DESKTOPHORZRES: 1134 return devcaps.ulHorzRes; 1135 1136 case BLTALIGNMENT: 1137 return devcaps.ulBltAlignment; 1138 1139 case SHADEBLENDCAPS: 1140 return devcaps.ulShadeBlend; 1141 1142 case COLORMGMTCAPS: 1143 return devcaps.ulColorMgmtCaps; 1144 1145 case PHYSICALWIDTH: 1146 return devcaps.ulPhysicalWidth; 1147 1148 case PHYSICALHEIGHT: 1149 return devcaps.ulPhysicalHeight; 1150 1151 case PHYSICALOFFSETX: 1152 return devcaps.ulPhysicalOffsetX; 1153 1154 case PHYSICALOFFSETY: 1155 return devcaps.ulPhysicalOffsetY; 1156 1157 case VREFRESH: 1158 return devcaps.ulVRefresh; 1159 1160 case RASTERCAPS: 1161 return devcaps.ulRasterCaps; 1162 1163 case CURVECAPS: 1164 return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | 1165 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); 1166 1167 case LINECAPS: 1168 return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | 1169 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); 1170 1171 case POLYGONALCAPS: 1172 return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | 1173 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); 1174 1175 case TEXTCAPS: 1176 return devcaps.ulTextCaps; 1177 1178 case CAPS1: 1179 case PDEVICESIZE: 1180 case SCALINGFACTORX: 1181 case SCALINGFACTORY: 1182 default: 1183 return 0; 1184 } 1185 1186 return 0; 1187 } 1188 1189 _Success_(return!=FALSE) 1190 BOOL 1191 APIENTRY 1192 NtGdiGetDeviceCapsAll( 1193 IN HDC hDC, 1194 OUT PDEVCAPS pDevCaps) 1195 { 1196 PDC pdc; 1197 DEVCAPS devcaps; 1198 BOOL bResult = TRUE; 1199 1200 /* Lock the given DC */ 1201 pdc = DC_LockDc(hDC); 1202 if (!pdc) 1203 { 1204 EngSetLastError(ERROR_INVALID_HANDLE); 1205 return FALSE; 1206 } 1207 1208 /* Get the data */ 1209 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 1210 1211 /* Unlock the DC */ 1212 DC_UnlockDc(pdc); 1213 1214 /* Copy data to caller */ 1215 _SEH2_TRY 1216 { 1217 ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1); 1218 RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS)); 1219 } 1220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1221 { 1222 SetLastNtError(_SEH2_GetExceptionCode()); 1223 bResult = FALSE; 1224 } 1225 _SEH2_END; 1226 1227 return bResult; 1228 } 1229 1230 DHPDEV 1231 APIENTRY 1232 NtGdiGetDhpdev( 1233 IN HDEV hdev) 1234 { 1235 PPDEVOBJ ppdev; 1236 DHPDEV dhpdev = NULL; 1237 1238 /* Check parameter */ 1239 if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart) 1240 return NULL; 1241 1242 /* Lock PDEV list */ 1243 EngAcquireSemaphoreShared(ghsemPDEV); 1244 1245 /* Walk through the list of PDEVs */ 1246 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 1247 { 1248 /* Compare with the given HDEV */ 1249 if (ppdev == (PPDEVOBJ)hdev) 1250 { 1251 /* Found the PDEV! Get it's dhpdev and break */ 1252 dhpdev = ppdev->dhpdev; 1253 break; 1254 } 1255 } 1256 1257 /* Unlock PDEV list */ 1258 EngReleaseSemaphore(ghsemPDEV); 1259 1260 return dhpdev; 1261 } 1262 1263 PSIZEL 1264 FASTCALL 1265 PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl) 1266 { 1267 if (ppdev->flFlags & PDEV_META_DEVICE) 1268 { 1269 *psizl = ppdev->szlMetaRes; 1270 } 1271 else 1272 { 1273 psizl->cx = ppdev->gdiinfo.ulHorzRes; 1274 psizl->cy = ppdev->gdiinfo.ulVertRes; 1275 } 1276 return psizl; 1277 } 1278