VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp@ 40257

Last change on this file since 40257 was 37630, checked in by vboxsync, 14 years ago

vboxtray/wddm: autoresize fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1/** @file
2 * VBoxTray - Display Settings Interface abstraction for XPDM & WDDM
3 */
4
5/*
6 * Copyright (C) 2006-2010 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxDispIf.h"
18
19#include <iprt/log.h>
20#include <iprt/err.h>
21#include <iprt/assert.h>
22
23#include <malloc.h>
24
25/* display driver interface abstraction for XPDM & WDDM
26 * with WDDM we can not use ExtEscape to communicate with our driver
27 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
28 * that knows nothing about us */
29DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
30{
31 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
32 return NO_ERROR;
33}
34
35DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
36{
37 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
38 return NO_ERROR;
39}
40
41static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
42{
43 HDC hdc = GetDC(HWND_DESKTOP);
44 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
45 int iRet = ExtEscape(hdc, pEscape->escapeCode, cbData, (LPCSTR)pvData, 0, NULL);
46 ReleaseDC(HWND_DESKTOP, hdc);
47 if (iRet > 0)
48 return VINF_SUCCESS;
49 else if (iRet == 0)
50 return ERROR_NOT_SUPPORTED;
51 /* else */
52 return ERROR_GEN_FAILURE;
53}
54
55#ifdef VBOX_WITH_WDDM
56static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
57{
58 DWORD err = NO_ERROR;
59 OSVERSIONINFO OSinfo;
60 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
61 GetVersionEx (&OSinfo);
62 bool bSupported = true;
63
64 if (OSinfo.dwMajorVersion >= 6)
65 {
66 Log((__FUNCTION__": this is vista and up\n"));
67 HMODULE hUser = GetModuleHandle("USER32");
68 if (hUser)
69 {
70 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
71 Log((__FUNCTION__": VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
72 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
73
74 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
75 Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
76 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
77
78 /* this is vista and up */
79 HMODULE hGdi32 = GetModuleHandle("gdi32");
80 if (hGdi32 != NULL)
81 {
82 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
83 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
84 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
85
86 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
87 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
88 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
89
90 pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
91 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
92 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
93
94 pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
95 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
96 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
97
98 pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
99 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
100 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
101
102 if (!bSupported)
103 {
104 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
105 err = ERROR_NOT_SUPPORTED;
106 }
107 }
108 else
109 {
110 Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
111 err = ERROR_NOT_SUPPORTED;
112 }
113
114 }
115 else
116 {
117 Log((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
118 err = ERROR_NOT_SUPPORTED;
119 }
120 }
121 else
122 {
123 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
124 err = ERROR_NOT_SUPPORTED;
125 }
126
127 return err;
128}
129
130static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
131{
132 DWORD winEr = ERROR_INVALID_STATE;
133 memset(pDev, 0, sizeof (*pDev));
134 pDev->cb = sizeof (*pDev);
135
136 for (int i = 0; ; ++i)
137 {
138 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
139 pDev, 0 /* DWORD dwFlags*/))
140 {
141 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
142 {
143 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
144 if (hDc)
145 {
146 *phDc = hDc;
147 return NO_ERROR;
148 }
149 else
150 {
151 winEr = GetLastError();
152 Assert(0);
153 break;
154 }
155 }
156 }
157 else
158 {
159 winEr = GetLastError();
160 Assert(0);
161 break;
162 }
163 }
164
165 return winEr;
166}
167
168
169typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
170typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
171static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
172{
173 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
174 DISPLAY_DEVICE DDev;
175 DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
176 Assert(err == NO_ERROR);
177 if (err == NO_ERROR)
178 {
179 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
180 Assert(!Status);
181 if (!Status)
182 {
183 BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
184
185 if (bCloseAdapter)
186 {
187 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
188 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
189 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
190 if (Status)
191 {
192 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
193 }
194 }
195 }
196 else
197 {
198 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
199 err = ERROR_GEN_FAILURE;
200 }
201
202 DeleteDC(OpenAdapterData.hDc);
203 }
204
205 return err;
206}
207
208typedef struct
209{
210 NTSTATUS Status;
211 PVBOXDISPIFESCAPE pEscape;
212 int cbData;
213} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
214
215DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
216{
217 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
218
219 D3DKMT_ESCAPE EscapeData = {0};
220 EscapeData.hAdapter = hAdapter;
221 //EscapeData.hDevice = NULL;
222 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
223 EscapeData.Flags.HardwareAccess = 1;
224 EscapeData.pPrivateDriverData = pCtx->pEscape;
225 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
226 //EscapeData.hContext = NULL;
227
228 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
229
230 return TRUE;
231}
232
233static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
234{
235 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
236 Ctx.pEscape = pEscape;
237 Ctx.cbData = cbData;
238 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
239 if (err == NO_ERROR)
240 {
241 if (!Ctx.Status)
242 err = NO_ERROR;
243 else
244 {
245 if (Ctx.Status == 0xC00000BBL) /* not supported */
246 err = ERROR_NOT_SUPPORTED;
247 else
248 err = ERROR_GEN_FAILURE;
249 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
250 }
251 }
252 else
253 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
254
255 return err;
256}
257
258typedef struct
259{
260 NTSTATUS Status;
261 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
262} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
263
264DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
265{
266 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
267 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
268 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
269 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
270 if (pData)
271 {
272 memset(pData, 0, cbData);
273 pData->cScreenInfos = 1;
274 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
275
276 IAVidPnData.hAdapter = hAdapter;
277 IAVidPnData.pPrivateDriverData = pData;
278 IAVidPnData.PrivateDriverDataSize = cbData;
279
280 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
281 Assert(!pCtx->Status);
282 if (pCtx->Status)
283 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
284
285 free(pData);
286 }
287 else
288 {
289 Log((__FUNCTION__": malloc failed\n"));
290 pCtx->Status = -1;
291 }
292
293 return TRUE;
294}
295
296static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
297{
298 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
299 Ctx.Info.Id = Id;
300 Ctx.Info.Width = Width;
301 Ctx.Info.Height = Height;
302 Ctx.Info.BitsPerPixel = BitsPerPixel;
303 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
304 vboxDispIfResizeWDDMOp, &Ctx);
305 if (err == NO_ERROR)
306 {
307 if (!Ctx.Status)
308 err = NO_ERROR;
309 else
310 {
311 if (Ctx.Status == 0xC00000BBL) /* not supported */
312 err = ERROR_NOT_SUPPORTED;
313 else
314 err = ERROR_GEN_FAILURE;
315 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
316 }
317 }
318 else
319 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
320
321 return err;
322}
323#endif
324
325DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
326{
327 switch (pIf->enmMode)
328 {
329 case VBOXDISPIF_MODE_XPDM_NT4:
330 case VBOXDISPIF_MODE_XPDM:
331 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData);
332#ifdef VBOX_WITH_WDDM
333 case VBOXDISPIF_MODE_WDDM:
334 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData);
335#endif
336 default:
337 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
338 return ERROR_INVALID_PARAMETER;
339 }
340}
341
342static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
343{
344 return ERROR_NOT_SUPPORTED;
345}
346
347DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
348{
349 switch (pIf->enmMode)
350 {
351 case VBOXDISPIF_MODE_XPDM_NT4:
352 return ERROR_NOT_SUPPORTED;
353 case VBOXDISPIF_MODE_XPDM:
354 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
355#ifdef VBOX_WITH_WDDM
356 case VBOXDISPIF_MODE_WDDM:
357 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
358#endif
359 default:
360 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
361 return ERROR_INVALID_PARAMETER;
362 }
363}
364
365static BOOL vboxDispIfValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
366{
367 DISPLAY_DEVICE DisplayDevice;
368 int i = 0;
369 UINT cMatched = 0;
370 DEVMODE DeviceMode;
371 for (int i = 0; ; ++i)
372 {
373 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
374 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
375
376 if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
377 break;
378
379 Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
380
381 BOOL bFetchDevice = FALSE;
382
383 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
384 {
385 Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
386 bFetchDevice = TRUE;
387 }
388 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
389 {
390
391 Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
392 bFetchDevice = TRUE;
393 }
394
395 if (bFetchDevice)
396 {
397 if (cMatched >= cDevModes)
398 {
399 Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
400 return FALSE;
401 }
402
403 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
404 * A secondary display could be not active at the moment and would not have
405 * a current video mode (ENUM_CURRENT_SETTINGS).
406 */
407 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
408 DeviceMode.dmSize = sizeof(DEVMODE);
409 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
410 ENUM_REGISTRY_SETTINGS, &DeviceMode))
411 {
412 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
413 return FALSE;
414 }
415
416 if ( DeviceMode.dmPelsWidth == 0
417 || DeviceMode.dmPelsHeight == 0)
418 {
419 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
420 * Get the current video mode then.
421 */
422 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
423 DeviceMode.dmSize = sizeof(DeviceMode);
424 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
425 ENUM_CURRENT_SETTINGS, &DeviceMode))
426 {
427 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
428 * for example a disabled secondary display */
429 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
430 return FALSE;
431 }
432 }
433
434 UINT j = 0;
435 for (; j < cDevModes; ++j)
436 {
437 if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(DeviceMode.dmDeviceName)))
438 {
439 if (paDeviceModes[j].dmBitsPerPel != DeviceMode.dmBitsPerPel
440 || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (DeviceMode.dmPelsWidth & 0xfff8)
441 || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (DeviceMode.dmPelsHeight & 0xfff8)
442 || (paDeviceModes[j].dmPosition.x & 0xfff8) != (DeviceMode.dmPosition.x & 0xfff8)
443 || (paDeviceModes[j].dmPosition.y & 0xfff8) != (DeviceMode.dmPosition.y & 0xfff8)
444 || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
445 {
446 return FALSE;
447 }
448 break;
449 }
450 }
451
452 if (j == cDevModes)
453 return FALSE;
454
455 ++cMatched;
456 }
457 }
458
459 return cMatched == cDevModes;
460}
461
462#ifdef VBOX_WITH_WDDM
463DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
464{
465 UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
466 PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
467 pVidPnInfo->cScreenInfos = cDevModes;
468 D3DKMT_HANDLE hAdapter = NULL;
469 NTSTATUS Status;
470 DWORD winEr = NO_ERROR;
471 UINT i = 0;
472
473 for (; i < cDevModes; i++)
474 {
475 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
476 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
477 OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
478 if (!OpenAdapterData.hDc)
479 {
480 winEr = GetLastError();
481 Assert(0);
482 break;
483 }
484
485 Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
486 Assert(!Status);
487 if (Status)
488 {
489 winEr = ERROR_GEN_FAILURE;
490 Assert(0);
491 break;
492 }
493
494 pInfo->Id = OpenAdapterData.VidPnSourceId;
495 pInfo->Width = paDeviceModes[i].dmPelsWidth;
496 pInfo->Height = paDeviceModes[i].dmPelsHeight;
497 pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
498
499 if (!hAdapter)
500 {
501 hAdapter = OpenAdapterData.hAdapter;
502 }
503 else
504 {
505 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
506 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
507 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
508 Assert(!Status);
509 }
510 }
511
512 if (winEr == NO_ERROR)
513 {
514 Assert(hAdapter);
515
516 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
517 IAVidPnData.hAdapter = hAdapter;
518 IAVidPnData.pPrivateDriverData = pVidPnInfo;
519 IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
520
521 DWORD winEr = NO_ERROR;
522 Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
523 Assert(!Status);
524 if (Status)
525 {
526 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
527 winEr = ERROR_GEN_FAILURE;
528 }
529 }
530
531 if (hAdapter)
532 {
533 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
534 ClosaAdapterData.hAdapter = hAdapter;
535 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
536 Assert(!Status);
537 }
538
539 /* ignore any prev errors and just check if resize is OK */
540 if (!vboxDispIfValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
541 {
542 /* now try to resize in a "regular" way */
543 /* Assign the new rectangles to displays. */
544 for (i = 0; i < cDevModes; i++)
545 {
546 /* On Vista one must specify DM_BITSPERPEL.
547 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
548 */
549 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
550
551 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
552 pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
553 paDeviceModes[i].dmPelsWidth,
554 paDeviceModes[i].dmPelsHeight,
555 paDeviceModes[i].dmBitsPerPel,
556 paDeviceModes[i].dmPosition.x,
557 paDeviceModes[i].dmPosition.y));
558
559 LONG status = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
560 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
561 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", status, GetLastError ()));
562 }
563
564 /* A second call to ChangeDisplaySettings updates the monitor. */
565 LONG status = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
566 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
567 if (status == DISP_CHANGE_SUCCESSFUL)
568 {
569 winEr = NO_ERROR;
570 }
571 else if (status == DISP_CHANGE_BADMODE)
572 {
573 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
574 winEr = ERROR_RETRY;
575 }
576 else
577 {
578 winEr = ERROR_GEN_FAILURE;
579 }
580 }
581 else
582 {
583 winEr = NO_ERROR;
584 }
585
586 return winEr;
587}
588#endif /* VBOX_WITH_WDDM */
589
590DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
591{
592 switch (pIf->enmMode)
593 {
594 case VBOXDISPIF_MODE_XPDM_NT4:
595 return ERROR_NOT_SUPPORTED;
596 case VBOXDISPIF_MODE_XPDM:
597 return ERROR_NOT_SUPPORTED;
598#ifdef VBOX_WITH_WDDM
599 case VBOXDISPIF_MODE_WDDM:
600 return vboxDispIfResizeModesWDDM(pIf, paDisplayDevices, paDeviceModes, cDevModes);
601#endif
602 default:
603 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
604 return ERROR_INVALID_PARAMETER;
605 }
606}
607
608static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
609{
610 return NO_ERROR;
611}
612
613static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
614{
615 DWORD err = NO_ERROR;
616 AssertBreakpoint();
617 OSVERSIONINFO OSinfo;
618 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
619 GetVersionEx (&OSinfo);
620 if (OSinfo.dwMajorVersion >= 5)
621 {
622 HMODULE hUser = GetModuleHandle("USER32");
623 if (NULL != hUser)
624 {
625 bool bSupported = true;
626 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
627 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
628 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
629
630 if (!bSupported)
631 {
632 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
633 err = ERROR_NOT_SUPPORTED;
634 }
635 }
636 else
637 {
638 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
639 err = ERROR_NOT_SUPPORTED;
640 }
641 }
642 else
643 {
644 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
645 err = ERROR_NOT_SUPPORTED;
646 }
647
648 return err;
649}
650
651DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
652{
653 /* @todo: may need to addd synchronization in case we want to change modes dynamically
654 * i.e. currently the mode is supposed to be initialized once on service initialization */
655 if (penmOldMode)
656 *penmOldMode = pIf->enmMode;
657
658 if (enmMode == pIf->enmMode)
659 return VINF_ALREADY_INITIALIZED;
660
661 DWORD err = NO_ERROR;
662 switch (enmMode)
663 {
664 case VBOXDISPIF_MODE_XPDM_NT4:
665 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
666 err = vboxDispIfSwitchToXPDM_NT4(pIf);
667 if (err == NO_ERROR)
668 {
669 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
670 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
671 }
672 else
673 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
674 break;
675 case VBOXDISPIF_MODE_XPDM:
676 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
677 err = vboxDispIfSwitchToXPDM(pIf);
678 if (err == NO_ERROR)
679 {
680 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
681 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
682 }
683 else
684 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
685 break;
686#ifdef VBOX_WITH_WDDM
687 case VBOXDISPIF_MODE_WDDM:
688 {
689 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
690 err = vboxDispIfSwitchToWDDM(pIf);
691 if (err == NO_ERROR)
692 {
693 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
694 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
695 }
696 else
697 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
698 break;
699 }
700#endif
701 default:
702 err = ERROR_INVALID_PARAMETER;
703 break;
704 }
705 return err;
706}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette