VirtualBox

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

Last change on this file since 34085 was 33980, checked in by vboxsync, 14 years ago

wddm: vidpn logging + bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 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/* display driver interface abstraction for XPDM & WDDM
24 * with WDDM we can not use ExtEscape to communicate with our driver
25 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
26 * that knows nothing about us */
27DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
28{
29 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
30 return NO_ERROR;
31}
32
33DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
34{
35 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
36 return NO_ERROR;
37}
38
39static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
40{
41 HDC hdc = GetDC(HWND_DESKTOP);
42 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
43 int iRet = ExtEscape(hdc, pEscape->escapeCode, cbData, (LPCSTR)pvData, 0, NULL);
44 ReleaseDC(HWND_DESKTOP, hdc);
45 if (iRet > 0)
46 return VINF_SUCCESS;
47 else if (iRet == 0)
48 return ERROR_NOT_SUPPORTED;
49 /* else */
50 return ERROR_GEN_FAILURE;
51}
52
53#ifdef VBOX_WITH_WDDM
54static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
55{
56 DWORD err = NO_ERROR;
57 OSVERSIONINFO OSinfo;
58 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
59 GetVersionEx (&OSinfo);
60 if (OSinfo.dwMajorVersion >= 6)
61 {
62 /* this is vista and up */
63 Log((__FUNCTION__": this is vista and up\n"));
64 HMODULE hGdi32 = GetModuleHandle("gdi32");
65 if (hGdi32 != NULL)
66 {
67 bool bSupported = true;
68 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
69 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
70 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
71
72 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
73 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
74 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
75
76 pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
77 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
78 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
79
80 pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
81 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
82 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
83
84 pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
85 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
86 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
87
88 if (!bSupported)
89 {
90 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
91 err = ERROR_NOT_SUPPORTED;
92 }
93 }
94 else
95 {
96 Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
97 err = ERROR_NOT_SUPPORTED;
98 }
99 }
100 else
101 {
102 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
103 err = ERROR_NOT_SUPPORTED;
104 }
105
106 return err;
107}
108
109static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
110{
111 DWORD winEr = ERROR_INVALID_STATE;
112 memset(pDev, 0, sizeof (*pDev));
113 pDev->cb = sizeof (*pDev);
114
115 for (int i = 0; ; ++i)
116 {
117 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
118 pDev, 0 /* DWORD dwFlags*/))
119 {
120 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
121 {
122 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
123 if (hDc)
124 {
125 *phDc = hDc;
126 return NO_ERROR;
127 }
128 else
129 {
130 winEr = GetLastError();
131 Assert(0);
132 break;
133 }
134 }
135 }
136 else
137 {
138 winEr = GetLastError();
139 Assert(0);
140 break;
141 }
142 }
143
144 return winEr;
145}
146
147
148typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
149typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
150static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
151{
152 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
153 DISPLAY_DEVICE DDev;
154 DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
155 Assert(err == NO_ERROR);
156 if (err == NO_ERROR)
157 {
158 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
159 Assert(!Status);
160 if (!Status)
161 {
162 BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
163
164 if (bCloseAdapter)
165 {
166 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
167 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
168 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
169 if (Status)
170 {
171 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
172 }
173 }
174 }
175 else
176 {
177 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
178 err = ERROR_GEN_FAILURE;
179 }
180
181 DeleteDC(OpenAdapterData.hDc);
182 }
183
184 return err;
185}
186
187typedef struct
188{
189 NTSTATUS Status;
190 PVBOXDISPIFESCAPE pEscape;
191 int cbData;
192} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
193
194DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
195{
196 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
197
198 D3DKMT_ESCAPE EscapeData = {0};
199 EscapeData.hAdapter = hAdapter;
200 //EscapeData.hDevice = NULL;
201 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
202 EscapeData.Flags.HardwareAccess = 1;
203 EscapeData.pPrivateDriverData = pCtx->pEscape;
204 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
205 //EscapeData.hContext = NULL;
206
207 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
208
209 return TRUE;
210}
211
212static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
213{
214 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
215 Ctx.pEscape = pEscape;
216 Ctx.cbData = cbData;
217 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
218 if (err == NO_ERROR)
219 {
220 if (!Ctx.Status)
221 err = NO_ERROR;
222 else
223 {
224 if (Ctx.Status == 0xC00000BBL) /* not supported */
225 err = ERROR_NOT_SUPPORTED;
226 else
227 err = ERROR_GEN_FAILURE;
228 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
229 }
230 }
231 else
232 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
233
234 return err;
235}
236
237typedef struct
238{
239 NTSTATUS Status;
240 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
241} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
242
243DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
244{
245 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
246
247 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
248 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
249 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
250 if (pData)
251 {
252 memset(pData, 0, cbData);
253 pData->cScreenInfos = 1;
254 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
255
256 IAVidPnData.hAdapter = hAdapter;
257 IAVidPnData.pPrivateDriverData = pData;
258 IAVidPnData.PrivateDriverDataSize = cbData;
259
260 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
261 if (pCtx->Status)
262 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
263
264 free(pData);
265 }
266 else
267 {
268 Log((__FUNCTION__": malloc failed\n"));
269 pCtx->Status = -1;
270 }
271
272 return TRUE;
273}
274
275static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
276{
277 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
278 Ctx.Info.Id = Id;
279 Ctx.Info.Width = Width;
280 Ctx.Info.Height = Height;
281 Ctx.Info.BitsPerPixel = BitsPerPixel;
282 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
283 vboxDispIfResizeWDDMOp, &Ctx);
284 if (err == NO_ERROR)
285 {
286 if (!Ctx.Status)
287 err = NO_ERROR;
288 else
289 {
290 if (Ctx.Status == 0xC00000BBL) /* not supported */
291 err = ERROR_NOT_SUPPORTED;
292 else
293 err = ERROR_GEN_FAILURE;
294 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
295 }
296 }
297 else
298 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
299
300 return err;
301}
302#endif
303
304DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
305{
306 switch (pIf->enmMode)
307 {
308 case VBOXDISPIF_MODE_XPDM_NT4:
309 case VBOXDISPIF_MODE_XPDM:
310 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData);
311#ifdef VBOX_WITH_WDDM
312 case VBOXDISPIF_MODE_WDDM:
313 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData);
314#endif
315 default:
316 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
317 return ERROR_INVALID_PARAMETER;
318 }
319}
320
321static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
322{
323 return ERROR_NOT_SUPPORTED;
324}
325
326DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
327{
328 switch (pIf->enmMode)
329 {
330 case VBOXDISPIF_MODE_XPDM_NT4:
331 return ERROR_NOT_SUPPORTED;
332 case VBOXDISPIF_MODE_XPDM:
333 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
334#ifdef VBOX_WITH_WDDM
335 case VBOXDISPIF_MODE_WDDM:
336 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
337#endif
338 default:
339 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
340 return ERROR_INVALID_PARAMETER;
341 }
342}
343
344static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
345{
346 return NO_ERROR;
347}
348
349static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
350{
351 DWORD err = NO_ERROR;
352 AssertBreakpoint();
353 OSVERSIONINFO OSinfo;
354 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
355 GetVersionEx (&OSinfo);
356 if (OSinfo.dwMajorVersion >= 5)
357 {
358 HMODULE hUser = GetModuleHandle("USER32");
359 if (NULL != hUser)
360 {
361 bool bSupported = true;
362 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
363 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
364 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
365
366 if (!bSupported)
367 {
368 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
369 err = ERROR_NOT_SUPPORTED;
370 }
371 }
372 else
373 {
374 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
375 err = ERROR_NOT_SUPPORTED;
376 }
377 }
378 else
379 {
380 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
381 err = ERROR_NOT_SUPPORTED;
382 }
383
384 return err;
385}
386
387DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
388{
389 /* @todo: may need to addd synchronization in case we want to change modes dynamically
390 * i.e. currently the mode is supposed to be initialized once on service initialization */
391 if (penmOldMode)
392 *penmOldMode = pIf->enmMode;
393
394 if (enmMode == pIf->enmMode)
395 return VINF_ALREADY_INITIALIZED;
396
397 DWORD err = NO_ERROR;
398 switch (enmMode)
399 {
400 case VBOXDISPIF_MODE_XPDM_NT4:
401 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
402 err = vboxDispIfSwitchToXPDM_NT4(pIf);
403 if (err == NO_ERROR)
404 {
405 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
406 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
407 }
408 else
409 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
410 break;
411 case VBOXDISPIF_MODE_XPDM:
412 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
413 err = vboxDispIfSwitchToXPDM(pIf);
414 if (err == NO_ERROR)
415 {
416 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
417 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
418 }
419 else
420 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
421 break;
422#ifdef VBOX_WITH_WDDM
423 case VBOXDISPIF_MODE_WDDM:
424 {
425 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
426 err = vboxDispIfSwitchToWDDM(pIf);
427 if (err == NO_ERROR)
428 {
429 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
430 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
431 }
432 else
433 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
434 break;
435 }
436#endif
437 default:
438 err = ERROR_INVALID_PARAMETER;
439 break;
440 }
441 return err;
442}
Note: See TracBrowser for help on using the repository browser.

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