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