VirtualBox

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

Last change on this file since 42098 was 42098, checked in by vboxsync, 13 years ago

wddm: new autoresize mechanism basics

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 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 D3DDDI_ESCAPEFLAGS EscapeFlags;
214} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
215
216DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
217{
218 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
219
220 D3DKMT_ESCAPE EscapeData = {0};
221 EscapeData.hAdapter = hAdapter;
222 //EscapeData.hDevice = NULL;
223 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
224 EscapeData.Flags = pCtx->EscapeFlags;
225 EscapeData.pPrivateDriverData = pCtx->pEscape;
226 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
227 //EscapeData.hContext = NULL;
228
229 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
230
231 return TRUE;
232}
233
234static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
235{
236 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
237 Ctx.pEscape = pEscape;
238 Ctx.cbData = cbData;
239 if (fHwAccess)
240 Ctx.EscapeFlags.HardwareAccess = 1;
241 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
242 if (err == NO_ERROR)
243 {
244 if (!Ctx.Status)
245 err = NO_ERROR;
246 else
247 {
248 if (Ctx.Status == 0xC00000BBL) /* not supported */
249 err = ERROR_NOT_SUPPORTED;
250 else
251 err = ERROR_GEN_FAILURE;
252 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
253 }
254 }
255 else
256 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
257
258 return err;
259}
260
261typedef struct
262{
263 NTSTATUS Status;
264 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
265} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
266
267DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
268{
269 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
270 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
271 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
272 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
273 if (pData)
274 {
275 memset(pData, 0, cbData);
276 pData->cScreenInfos = 1;
277 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
278
279 IAVidPnData.hAdapter = hAdapter;
280 IAVidPnData.pPrivateDriverData = pData;
281 IAVidPnData.PrivateDriverDataSize = cbData;
282
283 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
284 Assert(!pCtx->Status);
285 if (pCtx->Status)
286 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
287
288 free(pData);
289 }
290 else
291 {
292 Log((__FUNCTION__": malloc failed\n"));
293 pCtx->Status = -1;
294 }
295
296 return TRUE;
297}
298
299static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
300{
301 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
302 Ctx.Info.Id = Id;
303 Ctx.Info.Width = Width;
304 Ctx.Info.Height = Height;
305 Ctx.Info.BitsPerPixel = BitsPerPixel;
306 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
307 vboxDispIfResizeWDDMOp, &Ctx);
308 if (err == NO_ERROR)
309 {
310 if (!Ctx.Status)
311 err = NO_ERROR;
312 else
313 {
314 if (Ctx.Status == 0xC00000BBL) /* not supported */
315 err = ERROR_NOT_SUPPORTED;
316 else
317 err = ERROR_GEN_FAILURE;
318 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
319 }
320 }
321 else
322 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
323
324 return err;
325}
326#endif
327
328DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
329{
330 switch (pIf->enmMode)
331 {
332 case VBOXDISPIF_MODE_XPDM_NT4:
333 case VBOXDISPIF_MODE_XPDM:
334 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData);
335#ifdef VBOX_WITH_WDDM
336 case VBOXDISPIF_MODE_WDDM:
337 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
338#endif
339 default:
340 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
341 return ERROR_INVALID_PARAMETER;
342 }
343}
344
345static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
346{
347 return ERROR_NOT_SUPPORTED;
348}
349
350DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
351{
352 switch (pIf->enmMode)
353 {
354 case VBOXDISPIF_MODE_XPDM_NT4:
355 return ERROR_NOT_SUPPORTED;
356 case VBOXDISPIF_MODE_XPDM:
357 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
358#ifdef VBOX_WITH_WDDM
359 case VBOXDISPIF_MODE_WDDM:
360 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
361#endif
362 default:
363 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
364 return ERROR_INVALID_PARAMETER;
365 }
366}
367
368static BOOL vboxDispIfValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
369{
370 DISPLAY_DEVICE DisplayDevice;
371 int i = 0;
372 UINT cMatched = 0;
373 DEVMODE DeviceMode;
374 for (int i = 0; ; ++i)
375 {
376 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
377 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
378
379 if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
380 break;
381
382 Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
383
384 BOOL bFetchDevice = FALSE;
385
386 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
387 {
388 Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
389 bFetchDevice = TRUE;
390 }
391 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
392 {
393
394 Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
395 bFetchDevice = TRUE;
396 }
397
398 if (bFetchDevice)
399 {
400 if (cMatched >= cDevModes)
401 {
402 Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
403 return FALSE;
404 }
405
406 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
407 * A secondary display could be not active at the moment and would not have
408 * a current video mode (ENUM_CURRENT_SETTINGS).
409 */
410 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
411 DeviceMode.dmSize = sizeof(DEVMODE);
412 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
413 ENUM_REGISTRY_SETTINGS, &DeviceMode))
414 {
415 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
416 return FALSE;
417 }
418
419 if ( DeviceMode.dmPelsWidth == 0
420 || DeviceMode.dmPelsHeight == 0)
421 {
422 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
423 * Get the current video mode then.
424 */
425 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
426 DeviceMode.dmSize = sizeof(DeviceMode);
427 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
428 ENUM_CURRENT_SETTINGS, &DeviceMode))
429 {
430 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
431 * for example a disabled secondary display */
432 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
433 return FALSE;
434 }
435 }
436
437 UINT j = 0;
438 for (; j < cDevModes; ++j)
439 {
440 if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(DeviceMode.dmDeviceName)))
441 {
442 if (paDeviceModes[j].dmBitsPerPel != DeviceMode.dmBitsPerPel
443 || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (DeviceMode.dmPelsWidth & 0xfff8)
444 || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (DeviceMode.dmPelsHeight & 0xfff8)
445 || (paDeviceModes[j].dmPosition.x & 0xfff8) != (DeviceMode.dmPosition.x & 0xfff8)
446 || (paDeviceModes[j].dmPosition.y & 0xfff8) != (DeviceMode.dmPosition.y & 0xfff8)
447 || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
448 {
449 return FALSE;
450 }
451 break;
452 }
453 }
454
455 if (j == cDevModes)
456 return FALSE;
457
458 ++cMatched;
459 }
460 }
461
462 return cMatched == cDevModes;
463}
464
465#ifdef VBOX_WITH_WDDM
466static DWORD vboxDispIfReinitVideoModes(PCVBOXDISPIF const pIf)
467{
468 VBOXDISPIFESCAPE escape = {0};
469 escape.escapeCode = VBOXESC_REINITVIDEOMODES;
470 DWORD err = vboxDispIfEscapeWDDM(pIf, &escape, 0, FALSE /* hw access must be false here,
471 * otherwise the miniport driver would fail
472 * request to prevent a deadlock */);
473 if (err != NO_ERROR)
474 {
475 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
476 }
477 return err;
478}
479
480DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
481{
482 UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
483 PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
484 pVidPnInfo->cScreenInfos = cDevModes;
485 D3DKMT_HANDLE hAdapter = NULL;
486 NTSTATUS Status;
487 DWORD winEr = NO_ERROR;
488 UINT i = 0;
489
490 for (; i < cDevModes; i++)
491 {
492 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
493 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
494 OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
495 if (!OpenAdapterData.hDc)
496 {
497 winEr = GetLastError();
498 Assert(0);
499 break;
500 }
501
502 Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
503 Assert(!Status);
504 if (Status)
505 {
506 winEr = ERROR_GEN_FAILURE;
507 Assert(0);
508 break;
509 }
510
511 pInfo->Id = OpenAdapterData.VidPnSourceId;
512 pInfo->Width = paDeviceModes[i].dmPelsWidth;
513 pInfo->Height = paDeviceModes[i].dmPelsHeight;
514 pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
515
516 if (!hAdapter)
517 {
518 hAdapter = OpenAdapterData.hAdapter;
519 }
520 else
521 {
522 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
523 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
524 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
525 Assert(!Status);
526 }
527 }
528
529 BOOL fAbleToInvalidateVidPn = FALSE;
530
531 if (winEr == NO_ERROR)
532 {
533 Assert(hAdapter);
534
535 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
536 IAVidPnData.hAdapter = hAdapter;
537 IAVidPnData.pPrivateDriverData = pVidPnInfo;
538 IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
539
540 DWORD winEr = NO_ERROR;
541 Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
542 Assert(!Status);
543 if (Status)
544 {
545 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
546 winEr = ERROR_GEN_FAILURE;
547 }
548 else
549 {
550 fAbleToInvalidateVidPn = TRUE;
551 }
552 }
553
554 if (hAdapter)
555 {
556 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
557 ClosaAdapterData.hAdapter = hAdapter;
558 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
559 Assert(!Status);
560 }
561
562 if (!fAbleToInvalidateVidPn)
563 {
564 /* fallback impl: make the driver invalidate VidPn,
565 * which is done by emulating a monitor re-plug currently */
566 vboxDispIfReinitVideoModes(pIf);
567
568 /* sleep 2 seconds: dirty hack to wait for the new monitor info to be picked up,
569 * @todo: implement it properly by monitoring monitor device arrival/removal */
570 Sleep(2 * 1000);
571 }
572
573 /* ignore any prev errors and just check if resize is OK */
574 if (!vboxDispIfValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
575 {
576 /* now try to resize in a "regular" way */
577 /* Assign the new rectangles to displays. */
578 for (i = 0; i < cDevModes; i++)
579 {
580 /* On Vista one must specify DM_BITSPERPEL.
581 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
582 */
583 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
584
585 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
586 pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
587 paDeviceModes[i].dmPelsWidth,
588 paDeviceModes[i].dmPelsHeight,
589 paDeviceModes[i].dmBitsPerPel,
590 paDeviceModes[i].dmPosition.x,
591 paDeviceModes[i].dmPosition.y));
592
593 if (!fAbleToInvalidateVidPn)
594 {
595 /* @todo: the miniport might have been adjusted the display mode stuff,
596 * adjust the paDeviceModes[i] by picking the closest available one */
597 }
598
599 LONG status = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
600 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
601 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", status, GetLastError ()));
602 }
603
604 /* A second call to ChangeDisplaySettings updates the monitor. */
605 LONG status = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
606 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
607 if (status == DISP_CHANGE_SUCCESSFUL)
608 {
609 winEr = NO_ERROR;
610 }
611 else if (status == DISP_CHANGE_BADMODE)
612 {
613 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
614 winEr = ERROR_RETRY;
615 }
616 else
617 {
618 winEr = ERROR_GEN_FAILURE;
619 }
620 }
621 else
622 {
623 winEr = NO_ERROR;
624 }
625
626 return winEr;
627}
628#endif /* VBOX_WITH_WDDM */
629
630DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
631{
632 switch (pIf->enmMode)
633 {
634 case VBOXDISPIF_MODE_XPDM_NT4:
635 return ERROR_NOT_SUPPORTED;
636 case VBOXDISPIF_MODE_XPDM:
637 return ERROR_NOT_SUPPORTED;
638#ifdef VBOX_WITH_WDDM
639 case VBOXDISPIF_MODE_WDDM:
640 return vboxDispIfResizeModesWDDM(pIf, paDisplayDevices, paDeviceModes, cDevModes);
641#endif
642 default:
643 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
644 return ERROR_INVALID_PARAMETER;
645 }
646}
647
648static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
649{
650 return NO_ERROR;
651}
652
653static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
654{
655 DWORD err = NO_ERROR;
656 AssertBreakpoint();
657 OSVERSIONINFO OSinfo;
658 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
659 GetVersionEx (&OSinfo);
660 if (OSinfo.dwMajorVersion >= 5)
661 {
662 HMODULE hUser = GetModuleHandle("USER32");
663 if (NULL != hUser)
664 {
665 bool bSupported = true;
666 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
667 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
668 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
669
670 if (!bSupported)
671 {
672 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
673 err = ERROR_NOT_SUPPORTED;
674 }
675 }
676 else
677 {
678 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
679 err = ERROR_NOT_SUPPORTED;
680 }
681 }
682 else
683 {
684 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
685 err = ERROR_NOT_SUPPORTED;
686 }
687
688 return err;
689}
690
691DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
692{
693 /* @todo: may need to addd synchronization in case we want to change modes dynamically
694 * i.e. currently the mode is supposed to be initialized once on service initialization */
695 if (penmOldMode)
696 *penmOldMode = pIf->enmMode;
697
698 if (enmMode == pIf->enmMode)
699 return VINF_ALREADY_INITIALIZED;
700
701 DWORD err = NO_ERROR;
702 switch (enmMode)
703 {
704 case VBOXDISPIF_MODE_XPDM_NT4:
705 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
706 err = vboxDispIfSwitchToXPDM_NT4(pIf);
707 if (err == NO_ERROR)
708 {
709 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
710 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
711 }
712 else
713 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
714 break;
715 case VBOXDISPIF_MODE_XPDM:
716 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
717 err = vboxDispIfSwitchToXPDM(pIf);
718 if (err == NO_ERROR)
719 {
720 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
721 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
722 }
723 else
724 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
725 break;
726#ifdef VBOX_WITH_WDDM
727 case VBOXDISPIF_MODE_WDDM:
728 {
729 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
730 err = vboxDispIfSwitchToWDDM(pIf);
731 if (err == NO_ERROR)
732 {
733 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
734 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
735 }
736 else
737 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
738 break;
739 }
740#endif
741 default:
742 err = ERROR_INVALID_PARAMETER;
743 break;
744 }
745 return err;
746}
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