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