2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Support for physical devices
5 * FILE: subsystems/win32/win32k/eng/pdevobj.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
16 static PPDEVOBJ gppdevList
= NULL
;
17 PPDEVOBJ gppdevPrimary
= NULL
;
18 static HSEMAPHORE ghsemPDEV
;
24 ghsemPDEV
= EngCreateSemaphore();
34 ppdev
= ExAllocatePoolWithTag(PagedPool
, sizeof(PDEVOBJ
), GDITAG_PDEV
);
38 RtlZeroMemory(ppdev
, sizeof(PDEVOBJ
));
47 PDEVOBJ_vRelease(PPDEVOBJ ppdev
)
50 EngAcquireSemaphore(ghsemPDEV
);
52 /* Decrease reference count */
55 /* Check if references are left */
56 if (ppdev
->cPdevRefs
== 0)
61 SURFACE_ShareUnlockSurface(ppdev
->pSurface
);
62 ppdev
->pfn
.DisableSurface(ppdev
->dhpdev
);
66 ppdev
->pfn
.DisablePDEV(ppdev
->dhpdev
);
68 /* Remove it from list */
69 if( ppdev
== gppdevList
)
70 gppdevList
= ppdev
->ppdevNext
;
73 PPDEVOBJ ppdevCurrent
= gppdevList
;
75 while (!found
&& ppdevCurrent
->ppdevNext
)
77 if (ppdevCurrent
->ppdevNext
== ppdev
)
80 ppdevCurrent
= ppdevCurrent
->ppdevNext
;
83 ppdevCurrent
->ppdevNext
= ppdev
->ppdevNext
;
86 /* Is this the primary one ? */
87 if (ppdev
== gppdevPrimary
)
91 ExFreePoolWithTag(ppdev
, GDITAG_PDEV
);
95 EngReleaseSemaphore(ghsemPDEV
);
104 PWSTR pwszLogAddress
)
106 PFN_DrvEnablePDEV pfnEnablePDEV
;
108 DPRINT1("PDEVOBJ_bEnablePDEV()\n");
110 /* Get the DrvEnablePDEV function */
111 pfnEnablePDEV
= ppdev
->pldev
->pfn
.EnablePDEV
;
113 /* Call the drivers DrvEnablePDEV function */
114 ppdev
->dhpdev
= pfnEnablePDEV(pdevmode
,
123 ppdev
->pGraphicsDevice
->pwszDescription
,
124 ppdev
->pGraphicsDevice
->DeviceObject
);
126 DPRINT1("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev
->dhpdev
);
133 PDEVOBJ_vCompletePDEV(
136 /* Call the drivers DrvCompletePDEV function */
137 ppdev
->pldev
->pfn
.CompletePDEV(ppdev
->dhpdev
, (HDEV
)ppdev
);
147 DPRINT1("PDEVOBJ_pSurface()\n");
149 /* Check if we already have a surface */
152 /* Increment reference count */
153 GDIOBJ_IncrementShareCount(&ppdev
->pSurface
->BaseObject
);
157 /* Call the drivers DrvEnableSurface */
158 hsurf
= ppdev
->pldev
->pfn
.EnableSurface(ppdev
->dhpdev
);
160 /* Lock the surface */
161 ppdev
->pSurface
= SURFACE_ShareLockSurface(hsurf
);
164 DPRINT1("PDEVOBJ_pSurface() returning %p\n", ppdev
->pSurface
);
165 return ppdev
->pSurface
;
170 PDEVOBJ_pdmMatchDevMode(
174 PGRAPHICS_DEVICE pGraphicsDevice
;
175 PDEVMODEW pdmCurrent
;
178 pGraphicsDevice
= ppdev
->pGraphicsDevice
;
180 for (i
= 0; i
< pGraphicsDevice
->cDevModes
; i
++)
182 pdmCurrent
= pGraphicsDevice
->pDevModeList
[i
].pdm
;
184 /* Compare DEVMODE fields */
185 if (pdmCurrent
->dmBitsPerPel
== pdm
->dmBitsPerPel
&&
186 pdmCurrent
->dmPelsWidth
== pdm
->dmPelsWidth
&&
187 pdmCurrent
->dmPelsHeight
== pdm
->dmPelsHeight
&&
188 pdmCurrent
->dmDisplayFrequency
== pdm
->dmDisplayFrequency
)
190 /* Match! Return the DEVMODE */
203 PUNICODE_STRING pustrDeviceName
,
206 PGRAPHICS_DEVICE pGraphicsDevice
;
209 /* Try to find the GRAPHICS_DEVICE */
210 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDeviceName
, 0, 0);
211 if (!pGraphicsDevice
)
213 DPRINT1("No GRAPHICS_DEVICE found for %ls!\n",
214 pustrDeviceName
? pustrDeviceName
->Buffer
: 0);
218 /* Allocate a new PDEVOBJ */
219 ppdev
= PDEVOBJ_AllocPDEV();
222 DPRINT1("failed to allocate a PDEV\n");
226 /* If no DEVMODEW is given, ... */
229 /* ... use the device's default one */
230 pdm
= pGraphicsDevice
->pDevModeList
[pGraphicsDevice
->iDefaultMode
].pdm
;
231 DPRINT1("Using iDefaultMode = %ld\n", pGraphicsDevice
->iDefaultMode
);
234 /* Try to get a diplay driver */
235 ppdev
->pldev
= EngLoadDriver(pdm
->dmDeviceName
, LDEV_DEVICE_DISPLAY
);
238 DPRINT1("Could not load diplsay driver '%ls'\n", pGraphicsDevice
->pDiplayDrivers
);
239 ExFreePoolWithTag(ppdev
, GDITAG_PDEV
);
243 /* Copy the function table */
244 ppdev
->pfn
= ppdev
->pldev
->pfn
;
246 /* Set MovePointer function */
247 ppdev
->pfnMovePointer
= ppdev
->pfn
.MovePointer
;
248 if (!ppdev
->pfnMovePointer
)
249 ppdev
->pfnMovePointer
= EngMovePointer
;
251 ppdev
->pGraphicsDevice
= pGraphicsDevice
;
252 ppdev
->hsemDevLock
= EngCreateSemaphore();
253 ppdev
->pdmwDev
= pGraphicsDevice
->pDevModeList
[pGraphicsDevice
->iCurrentMode
].pdm
;
256 ppdev
->flFlags
= PDEV_DISPLAY
;
258 /* HACK: Don't use the pointer */
259 ppdev
->Pointer
.Exclude
.right
= -1;
261 /* Call the driver to enable the PDEV */
262 if (!PDEVOBJ_bEnablePDEV(ppdev
, pdm
, NULL
))
264 DPRINT1("Failed to enable PDEV!\n");
268 /* Fix up some values */
269 if (ppdev
->gdiinfo
.ulLogPixelsX
== 0)
270 ppdev
->gdiinfo
.ulLogPixelsX
= 96;
272 if (ppdev
->gdiinfo
.ulLogPixelsY
== 0)
273 ppdev
->gdiinfo
.ulLogPixelsY
= 96;
275 /* FIXME: this must be done in a better way */
276 pGraphicsDevice
->StateFlags
|= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
;
278 /* Tell the driver that the PDEV is ready */
279 PDEVOBJ_vCompletePDEV(ppdev
);
281 /* Return the PDEV */
297 /* Exchange driver functions */
298 ppdev
->pfn
= ppdev2
->pfn
;
299 ppdev2
->pfn
= pdevTmp
.pfn
;
302 ppdev
->pldev
= ppdev2
->pldev
;
303 ppdev2
->pldev
= pdevTmp
.pldev
;
305 /* Exchange DHPDEV */
306 ppdev
->dhpdev
= ppdev2
->dhpdev
;
307 ppdev2
->dhpdev
= pdevTmp
.dhpdev
;
309 /* Exchange surface */
310 ppdev
->pSurface
= ppdev2
->pSurface
;
311 ppdev2
->pSurface
= pdevTmp
.pSurface
;
312 hdev
= ppdev
->pSurface
->SurfObj
.hdev
;
313 ppdev
->pSurface
->SurfObj
.hdev
= ppdev2
->pSurface
->SurfObj
.hdev
;
314 ppdev2
->pSurface
->SurfObj
.hdev
= hdev
;
316 /* Exchange devinfo */
317 ppdev
->devinfo
= ppdev2
->devinfo
;
318 ppdev2
->devinfo
= pdevTmp
.devinfo
;
320 /* Exchange gdiinfo */
321 ppdev
->gdiinfo
= ppdev2
->gdiinfo
;
322 ppdev2
->gdiinfo
= pdevTmp
.gdiinfo
;
324 /* Notify each driver instance of its new HDEV association */
325 ppdev
->pfn
.CompletePDEV(ppdev
->dhpdev
, (HDEV
)ppdev
);
326 ppdev2
->pfn
.CompletePDEV(ppdev2
->dhpdev
, (HDEV
)ppdev2
);
336 ppdev
= EngpGetPDEV(0);
338 pdc
= DC_AllocDcWithHandle();
339 DC_vInitDc(pdc
, 0, ppdev
);
342 rclTrg
.left
= rclTrg
.top
= 0;
343 rclTrg
.right
= rclTrg
.bottom
= 400;
345 IntEngBitBltEx(&ppdev
->pSurface
->SurfObj
,
353 &pdc
->eboFill
.BrushObject
,
355 ROP3_TO_ROP4(PATCOPY
),
367 UNICODE_STRING ustrDevice
;
373 EngAcquireSemaphore(ppdev
->hsemDevLock
);
374 /* And everything else */
375 EngAcquireSemaphore(ghsemPDEV
);
377 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev
, ppdev
->pSurface
);
379 // Lookup the GraphicsDevice + select DEVMODE
380 // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
382 /* 1. Temporarily disable the current PDEV */
383 if (!ppdev
->pfn
.AssertMode(ppdev
->dhpdev
, FALSE
))
385 DPRINT1("DrvAssertMode failed\n");
389 /* 2. Create new PDEV */
390 RtlInitUnicodeString(&ustrDevice
, ppdev
->pGraphicsDevice
->szWinDeviceName
);
391 ppdevTmp
= EngpCreatePDEV(&ustrDevice
, pdm
);
394 DPRINT1("Failed to create a new PDEV\n");
398 /* 3. Create a new surface */
399 pSurface
= PDEVOBJ_pSurface(ppdevTmp
);
402 DPRINT1("DrvEnableSurface failed\n");
406 ASSERT(pSurface
->BitsLock
);
408 /* 4. Get DirectDraw information */
409 /* 5. Enable DirectDraw Not traced */
410 /* 6. Copy old PDEV state to new PDEV instance */
412 /* 7. Switch the PDEVs */
413 PDEVOBJ_vSwitchPdev(ppdev
, ppdevTmp
);
414 ASSERT(ppdev
->pSurface
->BitsLock
);
416 /* 8. Disable DirectDraw */
418 PDEVOBJ_vRelease(ppdevTmp
);
424 EngReleaseSemaphore(ppdev
->hsemDevLock
);
425 EngReleaseSemaphore(ghsemPDEV
);
427 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev
, ppdev
->pSurface
);
428 ASSERT(ppdev
->pSurface
->BitsLock
);
439 PUNICODE_STRING pustrDeviceName
)
441 UNICODE_STRING ustrCurrent
;
443 PGRAPHICS_DEVICE pGraphicsDevice
;
445 /* Acquire PDEV lock */
446 EngAcquireSemaphore(ghsemPDEV
);
448 /* If no device name is given, ... */
449 if (!pustrDeviceName
&& gppdevPrimary
)
451 /* ... use the primary PDEV */
452 ppdev
= gppdevPrimary
;
454 /* Reference the pdev */
455 InterlockedIncrement(&ppdev
->cPdevRefs
);
459 /* Loop all present PDEVs */
460 for (ppdev
= gppdevList
; ppdev
; ppdev
= ppdev
->ppdevNext
)
462 /* Get a pointer to the GRAPHICS_DEVICE */
463 pGraphicsDevice
= ppdev
->pGraphicsDevice
;
465 /* Compare the name */
466 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
467 if (RtlEqualUnicodeString(pustrDeviceName
, &ustrCurrent
, FALSE
))
469 /* Found! Reference the PDEV */
470 InterlockedIncrement(&ppdev
->cPdevRefs
);
475 /* Did we find one? */
478 /* No, create a new PDEV */
479 ppdev
= EngpCreatePDEV(pustrDeviceName
, NULL
);
482 /* Insert the PDEV into the list */
483 ppdev
->ppdevNext
= gppdevList
;
486 /* Set as primary PDEV, if we don't have one yet */
489 gppdevPrimary
= ppdev
;
495 /* Release PDEV lock */
496 EngReleaseSemaphore(ghsemPDEV
);
503 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev
)
507 if (ppdev
->flFlags
& PDEV_DISPLAY
)
509 if (ppdev
->devinfo
.iDitherFormat
== BMF_8BPP
||
510 ppdev
->devinfo
.flGraphicsCaps2
& GCAPS2_CHANGEGAMMARAMP
)
514 if (ppdev
->devinfo
.flGraphicsCaps
& GCAPS_CMYKCOLOR
)
515 ret
|= CM_CMYK_COLOR
;
516 if (ppdev
->devinfo
.flGraphicsCaps
& GCAPS_ICM
)
517 ret
|= CM_DEVICE_ICM
;
524 PDEVOBJ_vGetDeviceCaps(
526 OUT PDEVCAPS pDevCaps
)
528 PGDIINFO pGdiInfo
= &ppdev
->gdiinfo
;
530 pDevCaps
->ulVersion
= pGdiInfo
->ulVersion
;
531 pDevCaps
->ulTechnology
= pGdiInfo
->ulTechnology
;
532 pDevCaps
->ulHorzSizeM
= (pGdiInfo
->ulHorzSize
+ 500) / 1000;
533 pDevCaps
->ulVertSizeM
= (pGdiInfo
->ulVertSize
+ 500) / 1000;
534 pDevCaps
->ulHorzSize
= pGdiInfo
->ulHorzSize
;
535 pDevCaps
->ulVertSize
= pGdiInfo
->ulVertSize
;
536 pDevCaps
->ulHorzRes
= pGdiInfo
->ulHorzRes
;
537 pDevCaps
->ulVertRes
= pGdiInfo
->ulVertRes
;
538 pDevCaps
->ulBitsPixel
= pGdiInfo
->cBitsPixel
;
539 if (pDevCaps
->ulBitsPixel
== 15) pDevCaps
->ulBitsPixel
= 16;
540 pDevCaps
->ulPlanes
= pGdiInfo
->cPlanes
;
541 pDevCaps
->ulNumPens
= pGdiInfo
->ulNumColors
;
542 if (pDevCaps
->ulNumPens
!= -1) pDevCaps
->ulNumPens
*= 5;
543 pDevCaps
->ulNumFonts
= 0; // PDEVOBJ_cFonts(ppdev);
544 pDevCaps
->ulNumColors
= pGdiInfo
->ulNumColors
;
545 pDevCaps
->ulRasterCaps
= pGdiInfo
->flRaster
;
546 pDevCaps
->ulAspectX
= pGdiInfo
->ulAspectX
;
547 pDevCaps
->ulAspectY
= pGdiInfo
->ulAspectY
;
548 pDevCaps
->ulAspectXY
= pGdiInfo
->ulAspectXY
;
549 pDevCaps
->ulLogPixelsX
= pGdiInfo
->ulLogPixelsX
;
550 pDevCaps
->ulLogPixelsY
= pGdiInfo
->ulLogPixelsY
;
551 pDevCaps
->ulSizePalette
= pGdiInfo
->ulNumPalReg
;
552 pDevCaps
->ulColorRes
= pGdiInfo
->ulDACRed
+
553 pGdiInfo
->ulDACGreen
+
555 pDevCaps
->ulPhysicalWidth
= pGdiInfo
->szlPhysSize
.cx
;
556 pDevCaps
->ulPhysicalHeight
= pGdiInfo
->szlPhysSize
.cy
;
557 pDevCaps
->ulPhysicalOffsetX
= pGdiInfo
->ptlPhysOffset
.x
;
558 pDevCaps
->ulPhysicalOffsetY
= pGdiInfo
->ptlPhysOffset
.y
;
559 pDevCaps
->ulTextCaps
= pGdiInfo
->flTextCaps
;
560 pDevCaps
->ulTextCaps
|= (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
561 if (pGdiInfo
->ulTechnology
!= DT_PLOTTER
)
562 pDevCaps
->ulTextCaps
|= TC_VA_ABLE
;
563 pDevCaps
->ulVRefresh
= pGdiInfo
->ulVRefresh
;
564 pDevCaps
->ulDesktopHorzRes
= pGdiInfo
->ulHorzRes
;
565 pDevCaps
->ulDesktopVertRes
= pGdiInfo
->ulVertRes
;
566 pDevCaps
->ulBltAlignment
= pGdiInfo
->ulBltAlignment
;
567 pDevCaps
->ulPanningHorzRes
= pGdiInfo
->ulPanningHorzRes
;
568 pDevCaps
->ulPanningVertRes
= pGdiInfo
->ulPanningVertRes
;
569 pDevCaps
->xPanningAlignment
= pGdiInfo
->xPanningAlignment
;
570 pDevCaps
->yPanningAlignment
= pGdiInfo
->yPanningAlignment
;
571 pDevCaps
->ulShadeBlend
= pGdiInfo
->flShadeBlend
;
572 pDevCaps
->ulColorMgmtCaps
= PDEVOBJ_iGetColorManagementCaps(ppdev
);
576 /** Exported functions ********************************************************/
580 EngGetDriverName(IN HDEV hdev
)
582 PPDEVOBJ ppdev
= (PPDEVOBJ
)hdev
;
588 pldev
= ppdev
->pldev
;
591 if (!pldev
->pGdiDriverInfo
)
594 return pldev
->pGdiDriverInfo
->DriverName
.Buffer
;
607 /* Lock the given DC */
608 pdc
= DC_LockDc(hdc
);
611 SetLastWin32Error(ERROR_INVALID_HANDLE
);
616 PDEVOBJ_vGetDeviceCaps(pdc
->ppdev
, &devcaps
);
621 /* Return capability */
625 return devcaps
.ulVersion
;
628 return devcaps
.ulTechnology
;
631 return devcaps
.ulHorzSize
;
634 return devcaps
.ulVertSize
;
637 return devcaps
.ulHorzRes
;
640 return devcaps
.ulVertRes
;
643 return devcaps
.ulLogPixelsX
;
646 return devcaps
.ulLogPixelsY
;
649 return devcaps
.ulBitsPixel
;
652 return devcaps
.ulPlanes
;
658 return devcaps
.ulNumPens
;
661 return devcaps
.ulNumFonts
;
664 return devcaps
.ulNumColors
;
667 return devcaps
.ulAspectX
;
670 return devcaps
.ulAspectY
;
673 return devcaps
.ulAspectXY
;
679 return devcaps
.ulSizePalette
;
685 return devcaps
.ulColorRes
;
688 return devcaps
.ulVertRes
;
691 return devcaps
.ulHorzRes
;
694 return devcaps
.ulBltAlignment
;
697 return devcaps
.ulShadeBlend
;
700 return devcaps
.ulColorMgmtCaps
;
703 return devcaps
.ulPhysicalWidth
;
706 return devcaps
.ulPhysicalHeight
;
708 case PHYSICALOFFSETX
:
709 return devcaps
.ulPhysicalOffsetX
;
711 case PHYSICALOFFSETY
:
712 return devcaps
.ulPhysicalOffsetY
;
715 return devcaps
.ulVRefresh
;
718 return devcaps
.ulRasterCaps
;
721 return (CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
| CC_WIDE
|
722 CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
| CC_ROUNDRECT
);
725 return (LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
726 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
);
729 return (PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
| PC_SCANLINE
|
730 PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
| PC_INTERIORS
);
733 return devcaps
.ulTextCaps
;
749 NtGdiGetDeviceCapsAll(
751 OUT PDEVCAPS pDevCaps
)
757 /* Lock the given DC */
758 pdc
= DC_LockDc(hDC
);
761 SetLastWin32Error(ERROR_INVALID_HANDLE
);
766 PDEVOBJ_vGetDeviceCaps(pdc
->ppdev
, &devcaps
);
771 /* Copy data to caller */
774 ProbeForWrite(pDevCaps
, sizeof(DEVCAPS
), 1);
775 RtlCopyMemory(pDevCaps
, &devcaps
, sizeof(DEVCAPS
));
777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
779 SetLastNtError(_SEH2_GetExceptionCode());
793 DHPDEV dhpdev
= NULL
;
795 /* Check parameter */
796 if (!hdev
|| (PCHAR
)hdev
< (PCHAR
)MmSystemRangeStart
)
800 EngAcquireSemaphore(ghsemPDEV
);
802 /* Walk through the list of PDEVs */
803 for (ppdev
= gppdevList
; ppdev
; ppdev
= ppdev
->ppdevNext
)
805 /* Compare with the given HDEV */
808 /* Found the PDEV! Get it's dhpdev and break */
809 dhpdev
= ppdev
->dhpdev
;
814 /* Unlock PDEV list */
815 EngReleaseSemaphore(ghsemPDEV
);