VirtualBox

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

Last change on this file since 44040 was 44040, checked in by vboxsync, 12 years ago

wddm & vboxtray: better logging for autoresize

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.4 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 "VBoxTray.h"
18
19#include <iprt/log.h>
20#include <iprt/err.h>
21#include <iprt/assert.h>
22
23#include <malloc.h>
24
25#ifdef VBOX_WITH_WDDM
26#include <iprt/asm.h>
27#endif
28
29/* display driver interface abstraction for XPDM & WDDM
30 * with WDDM we can not use ExtEscape to communicate with our driver
31 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
32 * that knows nothing about us */
33DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
34{
35 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
36 return NO_ERROR;
37}
38
39#ifdef VBOX_WITH_WDDM
40static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
41static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
42#endif
43
44DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
45{
46#ifdef VBOX_WITH_WDDM
47 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
48 {
49 vboxDispIfWddmTerm(pIf);
50 }
51#endif
52
53 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
54 return NO_ERROR;
55}
56
57static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, int iDirection)
58{
59 HDC hdc = GetDC(HWND_DESKTOP);
60 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
61 int iRet = ExtEscape(hdc, pEscape->escapeCode,
62 iDirection >= 0 ? cbData : 0,
63 iDirection >= 0 ? (LPSTR)pvData : NULL,
64 iDirection <= 0 ? cbData : 0,
65 iDirection <= 0 ? (LPSTR)pvData : NULL);
66 ReleaseDC(HWND_DESKTOP, hdc);
67 if (iRet > 0)
68 return VINF_SUCCESS;
69 else if (iRet == 0)
70 return ERROR_NOT_SUPPORTED;
71 /* else */
72 return ERROR_GEN_FAILURE;
73}
74
75#ifdef VBOX_WITH_WDDM
76static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
77{
78 DWORD err = NO_ERROR;
79 OSVERSIONINFO OSinfo;
80 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
81 GetVersionEx (&OSinfo);
82 bool bSupported = true;
83
84 if (OSinfo.dwMajorVersion >= 6)
85 {
86 Log((__FUNCTION__": this is vista and up\n"));
87 HMODULE hUser = GetModuleHandle("USER32");
88 if (hUser)
89 {
90 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
91 Log((__FUNCTION__": VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
92 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
93
94 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
95 Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
96 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
97
98 /* this is vista and up */
99 HMODULE hGdi32 = GetModuleHandle("gdi32");
100 if (hGdi32 != NULL)
101 {
102 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
103 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
104 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
105
106 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
107 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
108 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
109
110 pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
111 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
112 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
113
114 pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
115 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
116 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
117
118 pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
119 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
120 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
121
122 if (!bSupported)
123 {
124 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
125 err = ERROR_NOT_SUPPORTED;
126 }
127 }
128 else
129 {
130 Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
131 err = ERROR_NOT_SUPPORTED;
132 }
133
134 }
135 else
136 {
137 Log((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
138 err = ERROR_NOT_SUPPORTED;
139 }
140 }
141 else
142 {
143 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
144 err = ERROR_NOT_SUPPORTED;
145 }
146
147 if (err == ERROR_SUCCESS)
148 {
149 err = vboxDispIfWddmInit(pIf);
150 }
151
152 return err;
153}
154
155static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
156{
157 DWORD winEr = ERROR_INVALID_STATE;
158 memset(pDev, 0, sizeof (*pDev));
159 pDev->cb = sizeof (*pDev);
160
161 for (int i = 0; ; ++i)
162 {
163 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
164 pDev, 0 /* DWORD dwFlags*/))
165 {
166 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
167 {
168 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
169 if (hDc)
170 {
171 *phDc = hDc;
172 return NO_ERROR;
173 }
174 else
175 {
176 winEr = GetLastError();
177 Log(("CreateDC failed %d", winEr));
178 break;
179 }
180 }
181 Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
182 }
183 else
184 {
185 winEr = GetLastError();
186 Log(("EnumDisplayDevices failed %d", winEr));
187 break;
188 }
189 }
190
191 Log(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
192 return winEr;
193}
194
195
196typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
197typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
198static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
199{
200 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
201 DISPLAY_DEVICE DDev;
202 DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
203 Assert(err == NO_ERROR);
204 if (err == NO_ERROR)
205 {
206 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
207 Assert(!Status);
208 if (!Status)
209 {
210 BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
211
212 if (bCloseAdapter)
213 {
214 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
215 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
216 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
217 if (Status)
218 {
219 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
220 }
221 }
222 }
223 else
224 {
225 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
226 err = ERROR_GEN_FAILURE;
227 }
228
229 DeleteDC(OpenAdapterData.hDc);
230 }
231 else
232 Log((__FUNCTION__": vboxDispIfWDDMAdpHdcCreate failed, winEr (%d)\n", err));
233
234 return err;
235}
236
237typedef struct
238{
239 NTSTATUS Status;
240 PVBOXDISPIFESCAPE pEscape;
241 int cbData;
242 D3DDDI_ESCAPEFLAGS EscapeFlags;
243} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
244
245DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
246{
247 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
248
249 D3DKMT_ESCAPE EscapeData = {0};
250 EscapeData.hAdapter = hAdapter;
251 //EscapeData.hDevice = NULL;
252 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
253 EscapeData.Flags = pCtx->EscapeFlags;
254 EscapeData.pPrivateDriverData = pCtx->pEscape;
255 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
256 //EscapeData.hContext = NULL;
257
258 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
259
260 return TRUE;
261}
262
263static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
264{
265 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
266 Ctx.pEscape = pEscape;
267 Ctx.cbData = cbData;
268 if (fHwAccess)
269 Ctx.EscapeFlags.HardwareAccess = 1;
270 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
271 if (err == NO_ERROR)
272 {
273 if (!Ctx.Status)
274 err = NO_ERROR;
275 else
276 {
277 if (Ctx.Status == 0xC00000BBL) /* not supported */
278 err = ERROR_NOT_SUPPORTED;
279 else
280 err = ERROR_GEN_FAILURE;
281 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
282 }
283 }
284 else
285 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
286
287 return err;
288}
289
290typedef struct
291{
292 NTSTATUS Status;
293 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
294} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
295
296DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
297{
298 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
299 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
300 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
301 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
302 if (pData)
303 {
304 memset(pData, 0, cbData);
305 pData->cScreenInfos = 1;
306 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
307
308 IAVidPnData.hAdapter = hAdapter;
309 IAVidPnData.pPrivateDriverData = pData;
310 IAVidPnData.PrivateDriverDataSize = cbData;
311
312 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
313 Assert(!pCtx->Status);
314 if (pCtx->Status)
315 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
316
317 free(pData);
318 }
319 else
320 {
321 Log((__FUNCTION__": malloc failed\n"));
322 pCtx->Status = -1;
323 }
324
325 return TRUE;
326}
327
328static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
329{
330 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
331 Ctx.Info.Id = Id;
332 Ctx.Info.Width = Width;
333 Ctx.Info.Height = Height;
334 Ctx.Info.BitsPerPixel = BitsPerPixel;
335 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
336 vboxDispIfResizeWDDMOp, &Ctx);
337 if (err == NO_ERROR)
338 {
339 if (!Ctx.Status)
340 err = NO_ERROR;
341 else
342 {
343 if (Ctx.Status == 0xC00000BBL) /* not supported */
344 err = ERROR_NOT_SUPPORTED;
345 else
346 err = ERROR_GEN_FAILURE;
347 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
348 }
349 }
350 else
351 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
352
353 return err;
354}
355#endif
356
357DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
358{
359 switch (pIf->enmMode)
360 {
361 case VBOXDISPIF_MODE_XPDM_NT4:
362 case VBOXDISPIF_MODE_XPDM:
363 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
364#ifdef VBOX_WITH_WDDM
365 case VBOXDISPIF_MODE_WDDM:
366 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
367#endif
368 default:
369 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
370 return ERROR_INVALID_PARAMETER;
371 }
372}
373
374DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
375{
376 switch (pIf->enmMode)
377 {
378 case VBOXDISPIF_MODE_XPDM_NT4:
379 case VBOXDISPIF_MODE_XPDM:
380 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
381#ifdef VBOX_WITH_WDDM
382 case VBOXDISPIF_MODE_WDDM:
383 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
384#endif
385 default:
386 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
387 return ERROR_INVALID_PARAMETER;
388 }
389}
390
391static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
392{
393 return ERROR_NOT_SUPPORTED;
394}
395
396DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
397{
398 switch (pIf->enmMode)
399 {
400 case VBOXDISPIF_MODE_XPDM_NT4:
401 return ERROR_NOT_SUPPORTED;
402 case VBOXDISPIF_MODE_XPDM:
403 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
404#ifdef VBOX_WITH_WDDM
405 case VBOXDISPIF_MODE_WDDM:
406 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
407#endif
408 default:
409 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
410 return ERROR_INVALID_PARAMETER;
411 }
412}
413
414
415#ifdef VBOX_WITH_WDDM
416/**/
417typedef DECLCALLBACK(VOID) FNVBOXSCREENMONRUNNER_CB(void *pvCb);
418typedef FNVBOXSCREENMONRUNNER_CB *PFNVBOXSCREENMONRUNNER_CB;
419
420typedef struct VBOXSCREENMON
421{
422 HANDLE hThread;
423 DWORD idThread;
424 HANDLE hEvent;
425 HWND hWnd;
426 PFNVBOXSCREENMONRUNNER_CB pfnCb;
427 void *pvCb;
428} VBOXSCREENMON, *PVBOXSCREENMON;
429
430
431static VBOXSCREENMON g_VBoxScreenMon;
432
433
434#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
435#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
436
437
438static void vboxScreenMonOnChange()
439{
440 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
441 pMon->pfnCb(pMon->pvCb);
442}
443
444static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
445 UINT uMsg,
446 WPARAM wParam,
447 LPARAM lParam
448)
449{
450 switch(uMsg)
451 {
452 case WM_DISPLAYCHANGE:
453 {
454 vboxScreenMonOnChange();
455 }
456 case WM_CLOSE:
457 Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
458 return 0;
459 case WM_DESTROY:
460 Log((__FUNCTION__": got WM_DESTROY for hwnd(0x%x)", hwnd));
461 return 0;
462 case WM_NCHITTEST:
463 Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
464 return HTNOWHERE;
465 }
466
467 return DefWindowProc(hwnd, uMsg, wParam, lParam);
468}
469
470#define VBOXSCREENMONWND_NAME "VboxScreenMonWnd"
471
472static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
473{
474 HRESULT hr = S_OK;
475 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
476 /* Register the Window Class. */
477 WNDCLASS wc;
478 if (!GetClassInfo(hInstance, VBOXSCREENMONWND_NAME, &wc))
479 {
480 wc.style = 0;//CS_OWNDC;
481 wc.lpfnWndProc = vboxScreenMonWndProc;
482 wc.cbClsExtra = 0;
483 wc.cbWndExtra = 0;
484 wc.hInstance = hInstance;
485 wc.hIcon = NULL;
486 wc.hCursor = NULL;
487 wc.hbrBackground = NULL;
488 wc.lpszMenuName = NULL;
489 wc.lpszClassName = VBOXSCREENMONWND_NAME;
490 if (!RegisterClass(&wc))
491 {
492 DWORD winErr = GetLastError();
493 Log((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
494 hr = E_FAIL;
495 }
496 }
497
498 if (hr == S_OK)
499 {
500 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
501 VBOXSCREENMONWND_NAME, VBOXSCREENMONWND_NAME,
502 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
503 -100, -100,
504 10, 10,
505 NULL, //GetDesktopWindow() /* hWndParent */,
506 NULL /* hMenu */,
507 hInstance,
508 NULL /* lpParam */);
509 Assert(hWnd);
510 if (hWnd)
511 {
512 *phWnd = hWnd;
513 }
514 else
515 {
516 DWORD winErr = GetLastError();
517 Log((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
518 hr = E_FAIL;
519 }
520 }
521
522 return hr;
523}
524
525static HRESULT vboxScreenMonWndDestroy(HWND hWnd)
526{
527 BOOL bResult = DestroyWindow(hWnd);
528 if (bResult)
529 return S_OK;
530
531 DWORD winErr = GetLastError();
532 Log((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
533 Assert(0);
534
535 return HRESULT_FROM_WIN32(winErr);
536}
537
538static HRESULT vboxScreenMonWndInit()
539{
540 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
541 return vboxScreenMonWndCreate(&pMon->hWnd);
542}
543
544HRESULT vboxScreenMonWndTerm()
545{
546 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
547 HRESULT tmpHr = vboxScreenMonWndDestroy(pMon->hWnd);
548 Assert(tmpHr == S_OK);
549
550 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
551 UnregisterClass(VBOXSCREENMONWND_NAME, hInstance);
552
553 return S_OK;
554}
555
556#define WM_VBOXSCREENMON_INIT_QUIT (WM_APP+2)
557
558HRESULT vboxScreenMonRun()
559{
560 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
561 MSG Msg;
562
563 HRESULT hr = S_FALSE;
564
565 PeekMessage(&Msg,
566 NULL /* HWND hWnd */,
567 WM_USER /* UINT wMsgFilterMin */,
568 WM_USER /* UINT wMsgFilterMax */,
569 PM_NOREMOVE);
570
571 BOOL bCheck = TRUE;
572
573 do
574 {
575 if (bCheck)
576 {
577 vboxScreenMonOnChange();
578
579 bCheck = FALSE;
580 }
581
582 BOOL bResult = GetMessage(&Msg,
583 0 /*HWND hWnd*/,
584 0 /*UINT wMsgFilterMin*/,
585 0 /*UINT wMsgFilterMax*/
586 );
587
588 if(!bResult) /* WM_QUIT was posted */
589 {
590 hr = S_FALSE;
591 break;
592 }
593
594 if(bResult == -1) /* error occurred */
595 {
596 DWORD winEr = GetLastError();
597 hr = HRESULT_FROM_WIN32(winEr);
598 Assert(0);
599 /* just ensure we never return success in this case */
600 Assert(hr != S_OK);
601 Assert(hr != S_FALSE);
602 if (hr == S_OK || hr == S_FALSE)
603 hr = E_FAIL;
604 break;
605 }
606
607 switch (Msg.message)
608 {
609 case WM_VBOXSCREENMON_INIT_QUIT:
610 case WM_CLOSE:
611 {
612 PostQuitMessage(0);
613 break;
614 }
615 case WM_DISPLAYCHANGE:
616 bCheck = TRUE;
617 default:
618 TranslateMessage(&Msg);
619 DispatchMessage(&Msg);
620 break;
621 }
622 } while (1);
623 return 0;
624}
625
626static DWORD WINAPI vboxScreenMonRunnerThread(void *pvUser)
627{
628 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
629
630 BOOL bRc = SetEvent(pMon->hEvent);
631 if (!bRc)
632 {
633 DWORD winErr = GetLastError();
634 Log((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
635 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
636 Assert(0);
637 Assert(tmpHr != S_OK);
638 }
639
640 HRESULT hr = vboxScreenMonWndInit();
641 Assert(hr == S_OK);
642 if (hr == S_OK)
643 {
644 hr = vboxScreenMonRun();
645 Assert(hr == S_OK);
646
647 vboxScreenMonWndTerm();
648 }
649
650 return 0;
651}
652
653HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
654{
655 HRESULT hr = E_FAIL;
656 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
657 memset(pMon, 0, sizeof (*pMon));
658
659 pMon->pfnCb = pfnCb;
660 pMon->pvCb = pvCb;
661
662 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
663 TRUE, /* BOOL bManualReset*/
664 FALSE, /* BOOL bInitialState */
665 NULL /* LPCTSTR lpName */
666 );
667 if (pMon->hEvent)
668 {
669 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
670 0 /* SIZE_T dwStackSize */,
671 vboxScreenMonRunnerThread,
672 pMon,
673 0 /* DWORD dwCreationFlags */,
674 &pMon->idThread);
675 if (pMon->hThread)
676 {
677 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
678 if (dwResult == WAIT_OBJECT_0)
679 return S_OK;
680 else
681 {
682 Log(("WaitForSingleObject failed!"));
683 hr = E_FAIL;
684 }
685 }
686 else
687 {
688 DWORD winErr = GetLastError();
689 Log((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
690 hr = HRESULT_FROM_WIN32(winErr);
691 Assert(0);
692 Assert(hr != S_OK);
693 }
694 CloseHandle(pMon->hEvent);
695 }
696 else
697 {
698 DWORD winErr = GetLastError();
699 Log((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
700 hr = HRESULT_FROM_WIN32(winErr);
701 Assert(0);
702 Assert(hr != S_OK);
703 }
704
705 return hr;
706}
707
708VOID VBoxScreenMonTerm()
709{
710 HRESULT hr;
711 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
712 if (!pMon->hThread)
713 return;
714
715 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXSCREENMON_INIT_QUIT, 0, 0);
716 DWORD winErr;
717 if (bResult
718 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
719 {
720 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
721 if (dwErr == WAIT_OBJECT_0)
722 {
723 hr = S_OK;
724 }
725 else
726 {
727 winErr = GetLastError();
728 hr = HRESULT_FROM_WIN32(winErr);
729 Assert(0);
730 }
731 }
732 else
733 {
734 hr = HRESULT_FROM_WIN32(winErr);
735 Assert(0);
736 }
737
738 CloseHandle(pMon->hThread);
739 pMon->hThread = 0;
740 CloseHandle(pMon->hEvent);
741 pMon->hThread = 0;
742}
743/**/
744
745typedef struct VBOXDISPIF_WDDM_INTERNAL
746{
747 PCVBOXDISPIF pIf;
748
749 HANDLE hResizeEvent;
750} VBOXDISPIF_WDDM_INTERNAL, *PVBOXDISPIF_WDDM_INTERNAL;
751
752static VBOXDISPIF_WDDM_INTERNAL g_VBoxDispIfWddm;
753
754static BOOL vboxDispIfWddmValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
755{
756 DISPLAY_DEVICE DisplayDevice;
757 int i = 0;
758 UINT cMatched = 0;
759 DEVMODE DeviceMode;
760 for (int i = 0; ; ++i)
761 {
762 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
763 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
764
765 if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
766 break;
767
768 Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
769
770 BOOL bFetchDevice = FALSE;
771
772 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
773 {
774 Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
775 bFetchDevice = TRUE;
776 }
777 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
778 {
779
780 Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
781 bFetchDevice = TRUE;
782 }
783
784 if (bFetchDevice)
785 {
786 if (cMatched >= cDevModes)
787 {
788 Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
789 return FALSE;
790 }
791
792 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
793 * A secondary display could be not active at the moment and would not have
794 * a current video mode (ENUM_CURRENT_SETTINGS).
795 */
796 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
797 DeviceMode.dmSize = sizeof(DEVMODE);
798 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
799 ENUM_REGISTRY_SETTINGS, &DeviceMode))
800 {
801 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
802 return FALSE;
803 }
804
805 if ( DeviceMode.dmPelsWidth == 0
806 || DeviceMode.dmPelsHeight == 0)
807 {
808 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
809 * Get the current video mode then.
810 */
811 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
812 DeviceMode.dmSize = sizeof(DeviceMode);
813 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
814 ENUM_CURRENT_SETTINGS, &DeviceMode))
815 {
816 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
817 * for example a disabled secondary display */
818 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
819 return FALSE;
820 }
821 }
822
823 UINT j = 0;
824 for (; j < cDevModes; ++j)
825 {
826 if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(DeviceMode.dmDeviceName)))
827 {
828 if (paDeviceModes[j].dmBitsPerPel != DeviceMode.dmBitsPerPel
829 || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (DeviceMode.dmPelsWidth & 0xfff8)
830 || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (DeviceMode.dmPelsHeight & 0xfff8)
831 || (paDeviceModes[j].dmPosition.x & 0xfff8) != (DeviceMode.dmPosition.x & 0xfff8)
832 || (paDeviceModes[j].dmPosition.y & 0xfff8) != (DeviceMode.dmPosition.y & 0xfff8)
833 || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
834 {
835 return FALSE;
836 }
837 break;
838 }
839 }
840
841 if (j == cDevModes)
842 return FALSE;
843
844 ++cMatched;
845 }
846 }
847
848 return cMatched == cDevModes;
849}
850
851static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
852{
853 if (vboxDispIfWddmValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
854 return NO_ERROR;
855
856 DWORD winEr;
857 LONG status = DISP_CHANGE_SUCCESSFUL;
858
859 /* now try to resize in a "regular" way */
860 /* Assign the new rectangles to displays. */
861 for (UINT i = 0; i < cDevModes; i++)
862 {
863 /* On Vista one must specify DM_BITSPERPEL.
864 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
865 */
866 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
867
868 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
869 pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
870 paDeviceModes[i].dmPelsWidth,
871 paDeviceModes[i].dmPelsHeight,
872 paDeviceModes[i].dmBitsPerPel,
873 paDeviceModes[i].dmPosition.x,
874 paDeviceModes[i].dmPosition.y));
875
876 /* the miniport might have been adjusted the display mode stuff,
877 * adjust the paDeviceModes[i] by picking the closest available one */
878// DEVMODE AdjustedMode = paDeviceModes[i];
879// vboxDispIfAdjustMode(&paDisplayDevices[i], &AdjustedMode);
880
881 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
882 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
883 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", tmpStatus, GetLastError ()));
884
885 if (tmpStatus != DISP_CHANGE_SUCCESSFUL)
886 {
887 status = tmpStatus;
888 }
889 }
890
891 /* A second call to ChangeDisplaySettings updates the monitor. */
892 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
893 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
894 if (tmpStatus == DISP_CHANGE_SUCCESSFUL)
895 {
896 if (status == DISP_CHANGE_SUCCESSFUL)
897 {
898 return NO_ERROR;
899 }
900 tmpStatus = status;
901 }
902
903 winEr = ERROR_GEN_FAILURE;
904 return winEr;
905}
906
907static DECLCALLBACK(VOID) vboxDispIfWddmScreenMonCb(void *pvCb)
908{
909 PVBOXDISPIF_WDDM_INTERNAL pData = (PVBOXDISPIF_WDDM_INTERNAL)pvCb;
910
911 SetEvent(pData->hResizeEvent);
912}
913
914static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
915{
916 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
917 g_VBoxDispIfWddm.pIf = pIf;
918 g_VBoxDispIfWddm.hResizeEvent = CreateEvent(NULL,
919 FALSE, /* BOOL bManualReset */
920 FALSE, /* BOOL bInitialState */
921 NULL /* LPCTSTR lpName */
922 );
923 if (g_VBoxDispIfWddm.hResizeEvent)
924 {
925 HRESULT hr = VBoxScreenMonInit(vboxDispIfWddmScreenMonCb, &g_VBoxDispIfWddm);
926 if (SUCCEEDED(hr))
927 {
928 /* ensure event is reset */
929 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
930 return ERROR_SUCCESS;
931 }
932 CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
933 }
934 return ERROR_GEN_FAILURE;
935}
936
937static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
938{
939 VBoxScreenMonTerm();
940 CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
941 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
942}
943
944static DWORD vboxDispIfReninitModesWDDM(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
945{
946 VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK Data = {0};
947 Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
948 if (fReconnectDisplaysOnChange)
949 Data.EscapeHdr.u32CmdSpecific = VBOXWDDM_REINITVIDEOMODESBYMASK_F_RECONNECT_DISPLAYS_ON_CHANGE;
950
951 memcpy(Data.ScreenMask, pScreenIdMask, sizeof (Data.ScreenMask));
952
953 DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), fReconnectDisplaysOnChange ? FALSE /* hw access must be false here,
954 * otherwise the miniport driver would fail
955 * request to prevent a deadlock */
956 : TRUE);
957 if (err != NO_ERROR)
958 {
959 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
960 }
961 return err;
962}
963
964static DWORD vboxDispIfAdjustMode(DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
965{
966 DEVMODE CurMode;
967 DEVMODE BestMatchMode;
968 DWORD i = 0;
969 int64_t diffWH = INT64_MAX;
970 int diffBpp = INT32_MAX;
971 for (; ; ++i)
972 {
973 CurMode.dmSize = sizeof (CurMode);
974 CurMode.dmDriverExtra = 0;
975
976 if (!EnumDisplaySettings(pDisplayDevice->DeviceName, i, &CurMode))
977 break;
978
979 if (CurMode.dmPelsWidth == pDeviceMode->dmPelsWidth
980 && CurMode.dmPelsHeight == pDeviceMode->dmPelsHeight
981 && CurMode.dmBitsPerPel == pDeviceMode->dmBitsPerPel)
982 {
983 Log(("Exact match found"));
984 *pDeviceMode = CurMode;
985 return NO_ERROR;
986 }
987
988 int diffCurrW = RT_ABS((int)(CurMode.dmPelsWidth - pDeviceMode->dmPelsWidth));
989 int diffCurrH = RT_ABS((int)(CurMode.dmPelsHeight - pDeviceMode->dmPelsHeight));
990 int diffCurrBpp = RT_ABS((int)(CurMode.dmBitsPerPel - pDeviceMode->dmBitsPerPel)
991 - 1 /* <- to make higher bpp take precedence over lower ones */
992 );
993
994 int64_t diffCurrHW = (int64_t)diffCurrW*diffCurrW + (int64_t)diffCurrH*diffCurrH;
995
996 if (i == 0
997 || diffCurrHW < diffWH
998 || (diffCurrHW == diffWH && diffCurrBpp < diffBpp))
999 {
1000 /* first run */
1001 BestMatchMode = CurMode;
1002 diffWH = diffCurrHW;
1003 diffBpp = diffCurrBpp;
1004 continue;
1005 }
1006 }
1007
1008 if (i == 0)
1009 {
1010 Log(("No modes found!"));
1011 return NO_ERROR;
1012 }
1013
1014 *pDeviceMode = BestMatchMode;
1015 return NO_ERROR;
1016}
1017
1018static DWORD vboxDispIfAdjustModeValues(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
1019{
1020 VBOXDISPIFESCAPE_ADJUSTVIDEOMODES Data = {0};
1021 Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
1022 Data.EscapeHdr.u32CmdSpecific = 1;
1023 Data.aScreenInfos[0].Mode.Id =
1024 Data.aScreenInfos[0].Mode.Width = pDeviceMode->dmPelsWidth;
1025 Data.aScreenInfos[0].Mode.Height = pDeviceMode->dmPelsHeight;
1026 Data.aScreenInfos[0].Mode.BitsPerPixel = pDeviceMode->dmBitsPerPel;
1027 DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), TRUE);
1028 if (err != NO_ERROR)
1029 {
1030 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
1031 }
1032 return err;
1033}
1034
1035DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1036{
1037 UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
1038 PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
1039 pVidPnInfo->cScreenInfos = cDevModes;
1040 D3DKMT_HANDLE hAdapter = NULL;
1041 NTSTATUS Status;
1042 DWORD winEr = NO_ERROR;
1043 UINT i = 0;
1044
1045 for (; i < cDevModes; i++)
1046 {
1047 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
1048 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
1049 OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
1050 if (!OpenAdapterData.hDc)
1051 {
1052 winEr = GetLastError();
1053 Log(("WARNING: Failed to get dc for display device %s, winEr %d\n", paDisplayDevices[i].DeviceName, winEr));
1054 break;
1055 }
1056
1057 Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
1058 Assert(!Status);
1059 if (Status)
1060 {
1061 winEr = ERROR_GEN_FAILURE;
1062 Log(("WARNING: Failed to open adapter from dc, Status 0x%x\n", Status));
1063 break;
1064 }
1065
1066 pInfo->Id = OpenAdapterData.VidPnSourceId;
1067 pInfo->Width = paDeviceModes[i].dmPelsWidth;
1068 pInfo->Height = paDeviceModes[i].dmPelsHeight;
1069 pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
1070
1071 if (!hAdapter)
1072 {
1073 hAdapter = OpenAdapterData.hAdapter;
1074 }
1075 else
1076 {
1077 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1078 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
1079 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1080 if (Status)
1081 Log(("WARNING: Failed to close adapter, Status 0x%x\n", Status));
1082 }
1083 }
1084
1085 BOOL fAbleToInvalidateVidPn = FALSE;
1086
1087 if (winEr == NO_ERROR)
1088 {
1089 Assert(hAdapter);
1090
1091 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
1092 IAVidPnData.hAdapter = hAdapter;
1093 IAVidPnData.pPrivateDriverData = pVidPnInfo;
1094 IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
1095
1096 DWORD winEr = NO_ERROR;
1097 Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
1098 Assert(!Status);
1099 if (Status)
1100 {
1101 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
1102 winEr = ERROR_GEN_FAILURE;
1103 }
1104 else
1105 {
1106 fAbleToInvalidateVidPn = TRUE;
1107 }
1108 }
1109
1110 if (hAdapter)
1111 {
1112 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1113 ClosaAdapterData.hAdapter = hAdapter;
1114 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1115 if (Status)
1116 Log(("WARNING: Failed to close adapter[2], Status 0x%x\n", Status));
1117 }
1118
1119// for (i = 0; i < cDevModes; i++)
1120// {
1121// vboxDispIfAdjustMode(&paDisplayDevices[i], &paDeviceModes[i]);
1122// }
1123
1124 if (fAbleToInvalidateVidPn)
1125 {
1126 Log(("Invalidating VidPn Worked!\n"));
1127 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1128 }
1129 else
1130 {
1131 Log(("Falling back to monitor mode reinit\n"));
1132 /* fallback impl needed for display-only driver
1133 * since D3DKMTInvalidateActiveVidPn is not available for WDDM > 1.0:
1134 * make the driver invalidate VidPn,
1135 * which is done by emulating a monitor re-plug currently */
1136 /* ensure event is reset */
1137 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
1138
1139 uint8_t ScreenMask[VBOXWDDM_SCREENMASK_SIZE] = {0};
1140 ASMBitSet(ScreenMask, iChangedMode);
1141 vboxDispIfReninitModesWDDM(pIf, ScreenMask, TRUE);
1142
1143 for (UINT i = 0; i < 4; ++i)
1144 {
1145 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 500);
1146 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1147 if (winEr == NO_ERROR)
1148 break;
1149 }
1150
1151 Assert(winEr == NO_ERROR);
1152 }
1153
1154 return winEr;
1155}
1156#endif /* VBOX_WITH_WDDM */
1157
1158DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1159{
1160 switch (pIf->enmMode)
1161 {
1162 case VBOXDISPIF_MODE_XPDM_NT4:
1163 return ERROR_NOT_SUPPORTED;
1164 case VBOXDISPIF_MODE_XPDM:
1165 return ERROR_NOT_SUPPORTED;
1166#ifdef VBOX_WITH_WDDM
1167 case VBOXDISPIF_MODE_WDDM:
1168 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
1169#endif
1170 default:
1171 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1172 return ERROR_INVALID_PARAMETER;
1173 }
1174}
1175
1176DWORD VBoxDispIfReninitModes(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
1177{
1178 switch (pIf->enmMode)
1179 {
1180 case VBOXDISPIF_MODE_XPDM_NT4:
1181 return ERROR_NOT_SUPPORTED;
1182 case VBOXDISPIF_MODE_XPDM:
1183 return ERROR_NOT_SUPPORTED;
1184#ifdef VBOX_WITH_WDDM
1185 case VBOXDISPIF_MODE_WDDM:
1186 return vboxDispIfReninitModesWDDM(pIf, pScreenIdMask, fReconnectDisplaysOnChange);
1187#endif
1188 default:
1189 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1190 return ERROR_INVALID_PARAMETER;
1191 }
1192}
1193
1194static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
1195{
1196 return NO_ERROR;
1197}
1198
1199static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
1200{
1201 DWORD err = NO_ERROR;
1202 AssertBreakpoint();
1203 OSVERSIONINFO OSinfo;
1204 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
1205 GetVersionEx (&OSinfo);
1206 if (OSinfo.dwMajorVersion >= 5)
1207 {
1208 HMODULE hUser = GetModuleHandle("USER32");
1209 if (NULL != hUser)
1210 {
1211 bool bSupported = true;
1212 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
1213 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
1214 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
1215
1216 if (!bSupported)
1217 {
1218 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
1219 err = ERROR_NOT_SUPPORTED;
1220 }
1221 }
1222 else
1223 {
1224 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
1225 err = ERROR_NOT_SUPPORTED;
1226 }
1227 }
1228 else
1229 {
1230 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
1231 err = ERROR_NOT_SUPPORTED;
1232 }
1233
1234 return err;
1235}
1236
1237DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
1238{
1239 /* @todo: may need to addd synchronization in case we want to change modes dynamically
1240 * i.e. currently the mode is supposed to be initialized once on service initialization */
1241 if (penmOldMode)
1242 *penmOldMode = pIf->enmMode;
1243
1244 if (enmMode == pIf->enmMode)
1245 return NO_ERROR;
1246
1247#ifdef VBOX_WITH_WDDM
1248 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1249 {
1250 vboxDispIfWddmTerm(pIf);
1251 }
1252#endif
1253
1254 DWORD err = NO_ERROR;
1255 switch (enmMode)
1256 {
1257 case VBOXDISPIF_MODE_XPDM_NT4:
1258 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
1259 err = vboxDispIfSwitchToXPDM_NT4(pIf);
1260 if (err == NO_ERROR)
1261 {
1262 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
1263 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
1264 }
1265 else
1266 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
1267 break;
1268 case VBOXDISPIF_MODE_XPDM:
1269 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
1270 err = vboxDispIfSwitchToXPDM(pIf);
1271 if (err == NO_ERROR)
1272 {
1273 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
1274 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
1275 }
1276 else
1277 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
1278 break;
1279#ifdef VBOX_WITH_WDDM
1280 case VBOXDISPIF_MODE_WDDM:
1281 {
1282 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
1283 err = vboxDispIfSwitchToWDDM(pIf);
1284 if (err == NO_ERROR)
1285 {
1286 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
1287 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
1288 }
1289 else
1290 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
1291 break;
1292 }
1293#endif
1294 default:
1295 err = ERROR_INVALID_PARAMETER;
1296 break;
1297 }
1298 return err;
1299}
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