xref: /reactos/win32ss/gdi/eng/mdevobj.c (revision d82185f1)
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
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
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
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
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