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 PPDEVOBJ gppdevPrimary
= NULL
;
18 static PPDEVOBJ gppdevList
= NULL
;
19 static HSEMAPHORE ghsemPDEV
;
26 ghsemPDEV
= EngCreateSemaphore();
27 if (!ghsemPDEV
) return STATUS_INSUFFICIENT_RESOURCES
;
28 return STATUS_SUCCESS
;
37 ppdev
= ExAllocatePoolWithTag(PagedPool
, sizeof(PDEVOBJ
), GDITAG_PDEV
);
41 RtlZeroMemory(ppdev
, sizeof(PDEVOBJ
));
50 PDEVOBJ_vRelease(PPDEVOBJ ppdev
)
53 EngAcquireSemaphore(ghsemPDEV
);
55 /* Decrease reference count */
58 ASSERT(ppdev
->cPdevRefs
>= 0) ;
60 /* Check if references are left */
61 if (ppdev
->cPdevRefs
== 0)
63 /* Do we have a surface? */
66 /* Release the surface and let the driver free it */
67 SURFACE_ShareUnlockSurface(ppdev
->pSurface
);
68 ppdev
->pfn
.DisableSurface(ppdev
->dhpdev
);
71 /* Do we have a palette? */
74 PALETTE_ShareUnlockPalette(ppdev
->ppalSurf
);
78 ppdev
->pfn
.DisablePDEV(ppdev
->dhpdev
);
80 /* Remove it from list */
81 if( ppdev
== gppdevList
)
82 gppdevList
= ppdev
->ppdevNext
;
85 PPDEVOBJ ppdevCurrent
= gppdevList
;
87 while (!found
&& ppdevCurrent
->ppdevNext
)
89 if (ppdevCurrent
->ppdevNext
== ppdev
)
92 ppdevCurrent
= ppdevCurrent
->ppdevNext
;
95 ppdevCurrent
->ppdevNext
= ppdev
->ppdevNext
;
98 /* Is this the primary one ? */
99 if (ppdev
== gppdevPrimary
)
100 gppdevPrimary
= NULL
;
103 ExFreePoolWithTag(ppdev
, GDITAG_PDEV
);
107 EngReleaseSemaphore(ghsemPDEV
);
116 PWSTR pwszLogAddress
)
118 PFN_DrvEnablePDEV pfnEnablePDEV
;
120 DPRINT1("PDEVOBJ_bEnablePDEV()\n");
122 /* Get the DrvEnablePDEV function */
123 pfnEnablePDEV
= ppdev
->pldev
->pfn
.EnablePDEV
;
125 /* Call the drivers DrvEnablePDEV function */
126 ppdev
->dhpdev
= pfnEnablePDEV(pdevmode
,
135 ppdev
->pGraphicsDevice
->pwszDescription
,
136 ppdev
->pGraphicsDevice
->DeviceObject
);
138 /* Fix up some values */
139 if (ppdev
->gdiinfo
.ulLogPixelsX
== 0)
140 ppdev
->gdiinfo
.ulLogPixelsX
= 96;
142 if (ppdev
->gdiinfo
.ulLogPixelsY
== 0)
143 ppdev
->gdiinfo
.ulLogPixelsY
= 96;
146 GDIOBJ_SetOwnership(ppdev
->devinfo
.hpalDefault
, NULL
);
147 ppdev
->ppalSurf
= PALETTE_ShareLockPalette(ppdev
->devinfo
.hpalDefault
);
149 DPRINT1("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev
->dhpdev
);
156 PDEVOBJ_vCompletePDEV(
159 /* Call the drivers DrvCompletePDEV function */
160 ppdev
->pldev
->pfn
.CompletePDEV(ppdev
->dhpdev
, (HDEV
)ppdev
);
170 /* Check if we already have a surface */
173 /* Increment reference count */
174 GDIOBJ_IncrementShareCount(&ppdev
->pSurface
->BaseObject
);
178 /* Call the drivers DrvEnableSurface */
179 hsurf
= ppdev
->pldev
->pfn
.EnableSurface(ppdev
->dhpdev
);
181 /* Lock the surface */
182 ppdev
->pSurface
= SURFACE_ShareLockSurface(hsurf
);
185 DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev
->pSurface
);
186 return ppdev
->pSurface
;
191 PDEVOBJ_pdmMatchDevMode(
195 PGRAPHICS_DEVICE pGraphicsDevice
;
196 PDEVMODEW pdmCurrent
;
200 pGraphicsDevice
= ppdev
->pGraphicsDevice
;
202 for (i
= 0; i
< pGraphicsDevice
->cDevModes
; i
++)
204 pdmCurrent
= pGraphicsDevice
->pDevModeList
[i
].pdm
;
206 /* Compare asked DEVMODE fields
207 * Only compare those that are valid in both DEVMODE structs */
208 dwFields
= pdmCurrent
->dmFields
& pdm
->dmFields
;
209 /* For now, we only need those */
210 if ((dwFields
& DM_BITSPERPEL
) &&
211 (pdmCurrent
->dmBitsPerPel
!= pdm
->dmBitsPerPel
))
213 if ((dwFields
& DM_PELSWIDTH
) &&
214 (pdmCurrent
->dmPelsWidth
!= pdm
->dmPelsWidth
))
216 if ((dwFields
& DM_PELSHEIGHT
) &&
217 (pdmCurrent
->dmPelsHeight
!= pdm
->dmPelsHeight
))
219 if ((dwFields
& DM_DISPLAYFREQUENCY
) &&
220 (pdmCurrent
->dmDisplayFrequency
!= pdm
->dmDisplayFrequency
))
223 /* Match! Return the DEVMODE */
234 PUNICODE_STRING pustrDeviceName
,
237 PGRAPHICS_DEVICE pGraphicsDevice
;
240 /* Try to find the GRAPHICS_DEVICE */
243 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDeviceName
, 0, 0);
244 if (!pGraphicsDevice
)
246 DPRINT1("No GRAPHICS_DEVICE found for %ls!\n",
247 pustrDeviceName
? pustrDeviceName
->Buffer
: 0);
253 pGraphicsDevice
= gpPrimaryGraphicsDevice
;
256 /* Allocate a new PDEVOBJ */
257 ppdev
= PDEVOBJ_AllocPDEV();
260 DPRINT1("failed to allocate a PDEV\n");
264 /* If no DEVMODEW is given, ... */
267 /* ... use the device's default one */
268 pdm
= pGraphicsDevice
->pDevModeList
[pGraphicsDevice
->iDefaultMode
].pdm
;
269 DPRINT1("Using iDefaultMode = %ld\n", pGraphicsDevice
->iDefaultMode
);
272 /* Try to get a diplay driver */
273 ppdev
->pldev
= EngLoadImageEx(pdm
->dmDeviceName
, LDEV_DEVICE_DISPLAY
);
276 DPRINT1("Could not load display driver '%ls'\n",
277 pGraphicsDevice
->pDiplayDrivers
);
278 ExFreePoolWithTag(ppdev
, GDITAG_PDEV
);
282 /* Copy the function table */
283 ppdev
->pfn
= ppdev
->pldev
->pfn
;
285 /* Set MovePointer function */
286 ppdev
->pfnMovePointer
= ppdev
->pfn
.MovePointer
;
287 if (!ppdev
->pfnMovePointer
)
288 ppdev
->pfnMovePointer
= EngMovePointer
;
290 ppdev
->pGraphicsDevice
= pGraphicsDevice
;
291 ppdev
->hsemDevLock
= EngCreateSemaphore();
292 // Should we change the ative mode of pGraphicsDevice ?
293 ppdev
->pdmwDev
= PDEVOBJ_pdmMatchDevMode(ppdev
, pdm
) ;
296 ppdev
->flFlags
= PDEV_DISPLAY
;
298 /* HACK: Don't use the pointer */
299 ppdev
->Pointer
.Exclude
.right
= -1;
301 /* Call the driver to enable the PDEV */
302 if (!PDEVOBJ_bEnablePDEV(ppdev
, pdm
, NULL
))
304 DPRINT1("Failed to enable PDEV!\n");
308 /* FIXME: this must be done in a better way */
309 pGraphicsDevice
->StateFlags
|= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
;
311 /* Tell the driver that the PDEV is ready */
312 PDEVOBJ_vCompletePDEV(ppdev
);
314 /* Return the PDEV */
330 /* Exchange driver functions */
331 ppdev
->pfn
= ppdev2
->pfn
;
332 ppdev2
->pfn
= pdevTmp
.pfn
;
335 ppdev
->pldev
= ppdev2
->pldev
;
336 ppdev2
->pldev
= pdevTmp
.pldev
;
338 /* Exchange DHPDEV */
339 ppdev
->dhpdev
= ppdev2
->dhpdev
;
340 ppdev2
->dhpdev
= pdevTmp
.dhpdev
;
342 /* Exchange surfaces and associate them with their new PDEV */
343 ppdev
->pSurface
= ppdev2
->pSurface
;
344 ppdev2
->pSurface
= pdevTmp
.pSurface
;
345 ppdev
->pSurface
->SurfObj
.hdev
= (HDEV
)ppdev
;
346 ppdev2
->pSurface
->SurfObj
.hdev
= (HDEV
)ppdev2
;
348 /* Exchange devinfo */
349 ppdev
->devinfo
= ppdev2
->devinfo
;
350 ppdev2
->devinfo
= pdevTmp
.devinfo
;
352 /* Exchange gdiinfo */
353 ppdev
->gdiinfo
= ppdev2
->gdiinfo
;
354 ppdev2
->gdiinfo
= pdevTmp
.gdiinfo
;
356 /* Exchange DEVMODE */
357 ppdev
->pdmwDev
= ppdev2
->pdmwDev
;
358 ppdev2
->pdmwDev
= pdevTmp
.pdmwDev
;
360 /* Exchange state flags */
361 tmpStateFlags
= ppdev
->pGraphicsDevice
->StateFlags
;
362 ppdev
->pGraphicsDevice
->StateFlags
= ppdev2
->pGraphicsDevice
->StateFlags
;
363 ppdev2
->pGraphicsDevice
->StateFlags
= tmpStateFlags
;
365 /* Notify each driver instance of its new HDEV association */
366 ppdev
->pfn
.CompletePDEV(ppdev
->dhpdev
, (HDEV
)ppdev
);
367 ppdev2
->pfn
.CompletePDEV(ppdev2
->dhpdev
, (HDEV
)ppdev2
);
377 UNICODE_STRING ustrDevice
;
383 EngAcquireSemaphore(ppdev
->hsemDevLock
);
384 /* And everything else */
385 EngAcquireSemaphore(ghsemPDEV
);
387 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev
, ppdev
->pSurface
);
389 // Lookup the GraphicsDevice + select DEVMODE
390 // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
392 /* 1. Temporarily disable the current PDEV */
393 if (!ppdev
->pfn
.AssertMode(ppdev
->dhpdev
, FALSE
))
395 DPRINT1("DrvAssertMode failed\n");
399 /* 2. Create new PDEV */
400 RtlInitUnicodeString(&ustrDevice
, ppdev
->pGraphicsDevice
->szWinDeviceName
);
401 ppdevTmp
= EngpCreatePDEV(&ustrDevice
, pdm
);
404 DPRINT1("Failed to create a new PDEV\n");
408 /* 3. Create a new surface */
409 pSurface
= PDEVOBJ_pSurface(ppdevTmp
);
412 DPRINT1("DrvEnableSurface failed\n");
416 /* 4. Get DirectDraw information */
417 /* 5. Enable DirectDraw Not traced */
418 /* 6. Copy old PDEV state to new PDEV instance */
420 /* 7. Switch the PDEVs */
421 PDEVOBJ_vSwitchPdev(ppdev
, ppdevTmp
);
423 /* 8. Disable DirectDraw */
425 PDEVOBJ_vRelease(ppdevTmp
);
427 /* Update primary display capabilities */
428 if(ppdev
== gppdevPrimary
)
430 PDEVOBJ_vGetDeviceCaps(ppdev
, &GdiHandleTable
->DevCaps
);
437 EngReleaseSemaphore(ppdev
->hsemDevLock
);
438 EngReleaseSemaphore(ghsemPDEV
);
440 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev
, ppdev
->pSurface
);
449 PUNICODE_STRING pustrDeviceName
)
451 UNICODE_STRING ustrCurrent
;
453 PGRAPHICS_DEVICE pGraphicsDevice
;
455 /* Acquire PDEV lock */
456 EngAcquireSemaphore(ghsemPDEV
);
458 /* If no device name is given, ... */
459 if (!pustrDeviceName
&& gppdevPrimary
)
461 /* ... use the primary PDEV */
462 ppdev
= gppdevPrimary
;
464 /* Reference the pdev */
465 InterlockedIncrement(&ppdev
->cPdevRefs
);
469 /* Loop all present PDEVs */
470 for (ppdev
= gppdevList
; ppdev
; ppdev
= ppdev
->ppdevNext
)
472 /* Get a pointer to the GRAPHICS_DEVICE */
473 pGraphicsDevice
= ppdev
->pGraphicsDevice
;
475 /* Compare the name */
476 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
477 if (RtlEqualUnicodeString(pustrDeviceName
, &ustrCurrent
, FALSE
))
479 /* Found! Reference the PDEV */
480 InterlockedIncrement(&ppdev
->cPdevRefs
);
485 /* Did we find one? */
488 /* No, create a new PDEV */
489 ppdev
= EngpCreatePDEV(pustrDeviceName
, NULL
);
492 /* Insert the PDEV into the list */
493 ppdev
->ppdevNext
= gppdevList
;
496 /* Set as primary PDEV, if we don't have one yet */
499 gppdevPrimary
= ppdev
;
500 ppdev
->pGraphicsDevice
->StateFlags
|= DISPLAY_DEVICE_PRIMARY_DEVICE
;
506 /* Release PDEV lock */
507 EngReleaseSemaphore(ghsemPDEV
);
514 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev
)
518 if (ppdev
->flFlags
& PDEV_DISPLAY
)
520 if (ppdev
->devinfo
.iDitherFormat
== BMF_8BPP
||
521 ppdev
->devinfo
.flGraphicsCaps2
& GCAPS2_CHANGEGAMMARAMP
)
525 if (ppdev
->devinfo
.flGraphicsCaps
& GCAPS_CMYKCOLOR
)
526 ret
|= CM_CMYK_COLOR
;
527 if (ppdev
->devinfo
.flGraphicsCaps
& GCAPS_ICM
)
528 ret
|= CM_DEVICE_ICM
;
535 PDEVOBJ_vGetDeviceCaps(
537 OUT PDEVCAPS pDevCaps
)
539 PGDIINFO pGdiInfo
= &ppdev
->gdiinfo
;
541 pDevCaps
->ulVersion
= pGdiInfo
->ulVersion
;
542 pDevCaps
->ulTechnology
= pGdiInfo
->ulTechnology
;
543 pDevCaps
->ulHorzSizeM
= (pGdiInfo
->ulHorzSize
+ 500) / 1000;
544 pDevCaps
->ulVertSizeM
= (pGdiInfo
->ulVertSize
+ 500) / 1000;
545 pDevCaps
->ulHorzSize
= pGdiInfo
->ulHorzSize
;
546 pDevCaps
->ulVertSize
= pGdiInfo
->ulVertSize
;
547 pDevCaps
->ulHorzRes
= pGdiInfo
->ulHorzRes
;
548 pDevCaps
->ulVertRes
= pGdiInfo
->ulVertRes
;
549 pDevCaps
->ulBitsPixel
= pGdiInfo
->cBitsPixel
;
550 if (pDevCaps
->ulBitsPixel
== 15) pDevCaps
->ulBitsPixel
= 16;
551 pDevCaps
->ulPlanes
= pGdiInfo
->cPlanes
;
552 pDevCaps
->ulNumPens
= pGdiInfo
->ulNumColors
;
553 if (pDevCaps
->ulNumPens
!= -1) pDevCaps
->ulNumPens
*= 5;
554 pDevCaps
->ulNumFonts
= 0; // PDEVOBJ_cFonts(ppdev);
555 pDevCaps
->ulNumColors
= pGdiInfo
->ulNumColors
;
556 pDevCaps
->ulRasterCaps
= pGdiInfo
->flRaster
;
557 pDevCaps
->ulAspectX
= pGdiInfo
->ulAspectX
;
558 pDevCaps
->ulAspectY
= pGdiInfo
->ulAspectY
;
559 pDevCaps
->ulAspectXY
= pGdiInfo
->ulAspectXY
;
560 pDevCaps
->ulLogPixelsX
= pGdiInfo
->ulLogPixelsX
;
561 pDevCaps
->ulLogPixelsY
= pGdiInfo
->ulLogPixelsY
;
562 pDevCaps
->ulSizePalette
= pGdiInfo
->ulNumPalReg
;
563 pDevCaps
->ulColorRes
= pGdiInfo
->ulDACRed
+
564 pGdiInfo
->ulDACGreen
+
566 pDevCaps
->ulPhysicalWidth
= pGdiInfo
->szlPhysSize
.cx
;
567 pDevCaps
->ulPhysicalHeight
= pGdiInfo
->szlPhysSize
.cy
;
568 pDevCaps
->ulPhysicalOffsetX
= pGdiInfo
->ptlPhysOffset
.x
;
569 pDevCaps
->ulPhysicalOffsetY
= pGdiInfo
->ptlPhysOffset
.y
;
570 pDevCaps
->ulTextCaps
= pGdiInfo
->flTextCaps
;
571 pDevCaps
->ulTextCaps
|= (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
572 if (pGdiInfo
->ulTechnology
!= DT_PLOTTER
)
573 pDevCaps
->ulTextCaps
|= TC_VA_ABLE
;
574 pDevCaps
->ulVRefresh
= pGdiInfo
->ulVRefresh
;
575 pDevCaps
->ulDesktopHorzRes
= pGdiInfo
->ulHorzRes
;
576 pDevCaps
->ulDesktopVertRes
= pGdiInfo
->ulVertRes
;
577 pDevCaps
->ulBltAlignment
= pGdiInfo
->ulBltAlignment
;
578 pDevCaps
->ulPanningHorzRes
= pGdiInfo
->ulPanningHorzRes
;
579 pDevCaps
->ulPanningVertRes
= pGdiInfo
->ulPanningVertRes
;
580 pDevCaps
->xPanningAlignment
= pGdiInfo
->xPanningAlignment
;
581 pDevCaps
->yPanningAlignment
= pGdiInfo
->yPanningAlignment
;
582 pDevCaps
->ulShadeBlend
= pGdiInfo
->flShadeBlend
;
583 pDevCaps
->ulColorMgmtCaps
= PDEVOBJ_iGetColorManagementCaps(ppdev
);
587 /** Exported functions ********************************************************/
591 EngGetDriverName(IN HDEV hdev
)
593 PPDEVOBJ ppdev
= (PPDEVOBJ
)hdev
;
599 pldev
= ppdev
->pldev
;
602 if (!pldev
->pGdiDriverInfo
)
605 return pldev
->pGdiDriverInfo
->DriverName
.Buffer
;
618 /* Lock the given DC */
619 pdc
= DC_LockDc(hdc
);
622 SetLastWin32Error(ERROR_INVALID_HANDLE
);
627 PDEVOBJ_vGetDeviceCaps(pdc
->ppdev
, &devcaps
);
632 /* Return capability */
636 return devcaps
.ulVersion
;
639 return devcaps
.ulTechnology
;
642 return devcaps
.ulHorzSize
;
645 return devcaps
.ulVertSize
;
648 return devcaps
.ulHorzRes
;
651 return devcaps
.ulVertRes
;
654 return devcaps
.ulLogPixelsX
;
657 return devcaps
.ulLogPixelsY
;
660 return devcaps
.ulBitsPixel
;
663 return devcaps
.ulPlanes
;
669 return devcaps
.ulNumPens
;
672 return devcaps
.ulNumFonts
;
675 return devcaps
.ulNumColors
;
678 return devcaps
.ulAspectX
;
681 return devcaps
.ulAspectY
;
684 return devcaps
.ulAspectXY
;
690 return devcaps
.ulSizePalette
;
696 return devcaps
.ulColorRes
;
699 return devcaps
.ulVertRes
;
702 return devcaps
.ulHorzRes
;
705 return devcaps
.ulBltAlignment
;
708 return devcaps
.ulShadeBlend
;
711 return devcaps
.ulColorMgmtCaps
;
714 return devcaps
.ulPhysicalWidth
;
717 return devcaps
.ulPhysicalHeight
;
719 case PHYSICALOFFSETX
:
720 return devcaps
.ulPhysicalOffsetX
;
722 case PHYSICALOFFSETY
:
723 return devcaps
.ulPhysicalOffsetY
;
726 return devcaps
.ulVRefresh
;
729 return devcaps
.ulRasterCaps
;
732 return (CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
| CC_WIDE
|
733 CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
| CC_ROUNDRECT
);
736 return (LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
737 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
);
740 return (PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
| PC_SCANLINE
|
741 PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
| PC_INTERIORS
);
744 return devcaps
.ulTextCaps
;
760 NtGdiGetDeviceCapsAll(
762 OUT PDEVCAPS pDevCaps
)
768 /* Lock the given DC */
769 pdc
= DC_LockDc(hDC
);
772 SetLastWin32Error(ERROR_INVALID_HANDLE
);
777 PDEVOBJ_vGetDeviceCaps(pdc
->ppdev
, &devcaps
);
782 /* Copy data to caller */
785 ProbeForWrite(pDevCaps
, sizeof(DEVCAPS
), 1);
786 RtlCopyMemory(pDevCaps
, &devcaps
, sizeof(DEVCAPS
));
788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
790 SetLastNtError(_SEH2_GetExceptionCode());
804 DHPDEV dhpdev
= NULL
;
806 /* Check parameter */
807 if (!hdev
|| (PCHAR
)hdev
< (PCHAR
)MmSystemRangeStart
)
811 EngAcquireSemaphore(ghsemPDEV
);
813 /* Walk through the list of PDEVs */
814 for (ppdev
= gppdevList
; ppdev
; ppdev
= ppdev
->ppdevNext
)
816 /* Compare with the given HDEV */
819 /* Found the PDEV! Get it's dhpdev and break */
820 dhpdev
= ppdev
->dhpdev
;
825 /* Unlock PDEV list */
826 EngReleaseSemaphore(ghsemPDEV
);
833 PDEVOBJ_sizl(PPDEVOBJ ppdev
, PSIZEL psizl
)
835 if (ppdev
->flFlags
& PDEV_META_DEVICE
)
837 psizl
->cx
= ppdev
->ulHorzRes
;
838 psizl
->cy
= ppdev
->ulVertRes
;
842 psizl
->cx
= ppdev
->gdiinfo
.ulHorzRes
;
843 psizl
->cy
= ppdev
->gdiinfo
.ulVertRes
;