1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Support for meta devices
5 * FILE: win32ss/gdi/eng/mdevobj.c
6 * PROGRAMER: Hervé Poussineau
7 */
8
9 #include <win32k.h>
10 #define NDEBUG
11 #include <debug.h>
12 DBG_DEFAULT_CHANNEL(EngMDev);
13
14 PMDEVOBJ gpmdev = NULL; /* FIXME: should be stored in gpDispInfo->pmdev */
15
16 VOID
MDEVOBJ_vEnable(_Inout_ PMDEVOBJ pmdev)17 MDEVOBJ_vEnable(
18 _Inout_ PMDEVOBJ pmdev)
19 {
20 ULONG i;
21
22 for (i = 0; i < pmdev->cDev; i++)
23 {
24 PDEVOBJ_vEnableDisplay(pmdev->dev[i].ppdev);
25 }
26 }
27
28 BOOL
MDEVOBJ_bDisable(_Inout_ PMDEVOBJ pmdev)29 MDEVOBJ_bDisable(
30 _Inout_ PMDEVOBJ pmdev)
31 {
32 BOOL bSuccess = TRUE;
33 ULONG i, j;
34
35 for (i = 0; i < pmdev->cDev; i++)
36 {
37 if (!PDEVOBJ_bDisableDisplay(pmdev->dev[i].ppdev))
38 {
39 bSuccess = FALSE;
40 break;
41 }
42 }
43
44 if (!bSuccess)
45 {
46 /* Failed to disable all PDEVs. Reenable those we have disabled */
47 for (j = 0; j < i; j++)
48 {
49 PDEVOBJ_vEnableDisplay(pmdev->dev[i].ppdev);
50 }
51 }
52
53 return bSuccess;
54 }
55
56 PMDEVOBJ
MDEVOBJ_Create(_In_opt_ PUNICODE_STRING pustrDeviceName,_In_opt_ PDEVMODEW pdm)57 MDEVOBJ_Create(
58 _In_opt_ PUNICODE_STRING pustrDeviceName,
59 _In_opt_ PDEVMODEW pdm)
60 {
61 PMDEVOBJ pmdev = NULL;
62 PPDEVOBJ ppdev;
63 PGRAPHICS_DEVICE pGraphicsDevice;
64 DEVMODEW dmDefault;
65 PDEVMODEW localPdm;
66 ULONG iDevNum = 0;
67 ULONG dwAccelerationLevel = 0;
68
69 TRACE("MDEVOBJ_Create('%wZ' '%dx%dx%d (%d Hz)')\n",
70 pustrDeviceName,
71 pdm ? pdm->dmPelsWidth : 0,
72 pdm ? pdm->dmPelsHeight : 0,
73 pdm ? pdm->dmBitsPerPel : 0,
74 pdm ? pdm->dmDisplayFrequency : 0);
75
76 pmdev = ExAllocatePoolZero(PagedPool, sizeof(MDEVOBJ) + sizeof(MDEVDISPLAY), GDITAG_MDEV);
77 if (!pmdev)
78 {
79 ERR("Failed to allocate memory for MDEV\n");
80 return NULL;
81 }
82
83 pmdev->cDev = 0;
84
85 while (TRUE)
86 {
87 /* Get the right graphics devices: either the specified one, or all of them (one after one) */
88 if (pustrDeviceName)
89 pGraphicsDevice = (iDevNum == 0) ? EngpFindGraphicsDevice(pustrDeviceName, 0) : NULL;
90 else
91 pGraphicsDevice = EngpFindGraphicsDevice(NULL, iDevNum);
92 iDevNum++;
93
94 if (!pGraphicsDevice)
95 {
96 TRACE("Done enumeration of graphic devices (DeviceName '%wZ' iDevNum %d)\n", pustrDeviceName, iDevNum);
97 break;
98 }
99
100 if (!pdm)
101 {
102 /* No settings requested. Provide nothing and LDEVOBJ_bProbeAndCaptureDevmode
103 * will read default settings from registry */
104 RtlZeroMemory(&dmDefault, sizeof(dmDefault));
105 dmDefault.dmSize = sizeof(dmDefault);
106 }
107
108 dwAccelerationLevel = EngpGetDisplayDriverAccelerationLevel(pGraphicsDevice);
109
110 /* Get or create a PDEV for these settings */
111 if (LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, pdm ? pdm : &dmDefault, &localPdm, !pdm))
112 {
113 ppdev = PDEVOBJ_Create(pGraphicsDevice, localPdm, dwAccelerationLevel, LDEV_DEVICE_DISPLAY);
114 }
115 else
116 {
117 ppdev = NULL;
118 }
119
120 if (ppdev)
121 {
122 /* Great. We have a found a matching PDEV. Store it in MDEV */
123 if (pmdev->cDev >= 1)
124 {
125 /* We have to reallocate MDEV to add space for the new display */
126 PMDEVOBJ pmdevBigger = ExAllocatePoolZero(PagedPool, sizeof(MDEVOBJ) + (pmdev->cDev + 1) * sizeof(MDEVDISPLAY), GDITAG_MDEV);
127 if (!pmdevBigger)
128 {
129 WARN("Failed to allocate memory for MDEV. Skipping display '%S'\n", pGraphicsDevice->szWinDeviceName);
130 continue;
131 }
132 else
133 {
134 /* Copy existing data */
135 RtlCopyMemory(pmdevBigger, pmdev, sizeof(MDEVOBJ) + pmdev->cDev * sizeof(MDEVDISPLAY));
136 ExFreePoolWithTag(pmdev, GDITAG_MDEV);
137 pmdev = pmdevBigger;
138 }
139 }
140
141 TRACE("Adding '%S' to MDEV %p\n", pGraphicsDevice->szWinDeviceName, pmdev);
142 PDEVOBJ_vReference(ppdev);
143 pmdev->dev[pmdev->cDev].ppdev = ppdev;
144 pmdev->cDev++;
145 }
146 else
147 {
148 WARN("Failed to add '%S' to MDEV %p\n", pGraphicsDevice->szWinDeviceName, pmdev);
149 }
150 }
151
152 if (pmdev->cDev == 0)
153 {
154 TRACE("Failed to add any device to MDEV. Returning NULL\n");
155 MDEVOBJ_vDestroy(pmdev);
156 return NULL;
157 }
158
159 TRACE("Returning new MDEV %p with %d devices\n", pmdev, pmdev->cDev);
160 return pmdev;
161 }
162
163 VOID
MDEVOBJ_vDestroy(_Inout_ PMDEVOBJ pmdev)164 MDEVOBJ_vDestroy(
165 _Inout_ PMDEVOBJ pmdev)
166 {
167 ULONG i;
168
169 for (i = 0; i < pmdev->cDev; i++)
170 {
171 PDEVOBJ_vRelease(pmdev->dev[i].ppdev);
172 }
173
174 if (pmdev->cDev > 1)
175 PDEVOBJ_vRelease(pmdev->ppdevGlobal);
176
177 ExFreePoolWithTag(pmdev, GDITAG_MDEV);
178 }
179