VirtualBox

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

Last change on this file since 64878 was 64878, checked in by vboxsync, 8 years ago

WDDM: pass the display enabled flag to the driver to be able to disable powered off screens. Clearly mark some disabled code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.7 KB
Line 
1/* $Id: VBoxDispIf.cpp 64878 2016-12-15 10:51:08Z vboxsync $ */
2/** @file
3 * VBoxTray - Display Settings Interface abstraction for XPDM & WDDM
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxTray.h"
19#define _WIN32_WINNT 0x0601
20#include <iprt/log.h>
21#include <iprt/err.h>
22#include <iprt/assert.h>
23
24#include <malloc.h>
25
26
27/*********************************************************************************************************************************
28* Defined Constants And Macros *
29*********************************************************************************************************************************/
30#ifdef DEBUG_misha
31# define WARN(_m) do { \
32 Assert(0); \
33 Log(_m); \
34 } while (0)
35# define WARN_FUNC(_m) do { \
36 Assert(0); \
37 LogFunc(_m); \
38 } while (0)
39#else
40# define WARN(_m) do { \
41 Log(_m); \
42 } while (0)
43# define WARN_FUNC(_m) do { \
44 LogFunc(_m); \
45 } while (0)
46#endif
47
48#ifdef VBOX_WITH_WDDM
49#include <iprt/asm.h>
50#endif
51
52#include "VBoxDisplay.h"
53
54#ifndef NT_SUCCESS
55# define NT_SUCCESS(_Status) ((_Status) >= 0)
56#endif
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62typedef struct VBOXDISPIF_OP
63{
64 PCVBOXDISPIF pIf;
65 VBOXDISPKMT_ADAPTER Adapter;
66 VBOXDISPKMT_DEVICE Device;
67 VBOXDISPKMT_CONTEXT Context;
68} VBOXDISPIF_OP;
69
70/*
71 * APIs specific to Win7 and above WDDM architecture. Not available for Vista WDDM.
72 * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h.
73 */
74typedef struct _VBOXDISPLAYWDDMAPICONTEXT
75{
76 LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
77 DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
78 LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
79 UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
80 DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
81 LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
82} _VBOXDISPLAYWDDMAPICONTEXT;
83
84static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};
85
86typedef struct VBOXDISPIF_WDDM_DISPCFG
87{
88 UINT32 cPathInfoArray;
89 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
90 UINT32 cModeInfoArray;
91 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
92} VBOXDISPIF_WDDM_DISPCFG;
93
94
95/*********************************************************************************************************************************
96* Internal Functions *
97*********************************************************************************************************************************/
98static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices,
99 DEVMODE *paDeviceModes, UINT devModes);
100static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup,
101 DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
102static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable);
103static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp);
104
105
106static DWORD vboxDispIfWddmDcCreate(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT32 fFlags)
107{
108 UINT32 cPathInfoArray = 0;
109 UINT32 cModeInfoArray = 0;
110 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
111 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
112 DWORD winEr = gCtx.pfnGetDisplayConfigBufferSizes(fFlags, &cPathInfoArray, &cModeInfoArray);
113 if (winEr != ERROR_SUCCESS)
114 {
115 WARN(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes\n"));
116 return winEr;
117 }
118
119 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cPathInfoArray * sizeof(DISPLAYCONFIG_PATH_INFO));
120 if (!pPathInfoArray)
121 {
122 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
123 return ERROR_OUTOFMEMORY;
124 }
125 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
126 if (!pModeInfoArray)
127 {
128 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
129 free(pPathInfoArray);
130 return ERROR_OUTOFMEMORY;
131 }
132
133 winEr = gCtx.pfnQueryDisplayConfig(fFlags, &cPathInfoArray, pPathInfoArray, &cModeInfoArray, pModeInfoArray, NULL);
134 if (winEr != ERROR_SUCCESS)
135 {
136 WARN(("VBoxTray: (WDDM) Failed QueryDisplayConfig\n"));
137 free(pPathInfoArray);
138 free(pModeInfoArray);
139 return winEr;
140 }
141
142 pCfg->cPathInfoArray = cPathInfoArray;
143 pCfg->pPathInfoArray = pPathInfoArray;
144 pCfg->cModeInfoArray = cModeInfoArray;
145 pCfg->pModeInfoArray = pModeInfoArray;
146 return ERROR_SUCCESS;
147}
148
149static DWORD vboxDispIfWddmDcClone(VBOXDISPIF_WDDM_DISPCFG *pCfg, VBOXDISPIF_WDDM_DISPCFG *pCfgDst)
150{
151 memset(pCfgDst, 0, sizeof (*pCfgDst));
152
153 if (pCfg->cPathInfoArray)
154 {
155 pCfgDst->pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
156 if (!pCfgDst->pPathInfoArray)
157 {
158 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
159 return ERROR_OUTOFMEMORY;
160 }
161
162 memcpy(pCfgDst->pPathInfoArray, pCfg->pPathInfoArray, pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
163
164 pCfgDst->cPathInfoArray = pCfg->cPathInfoArray;
165 }
166
167 if (pCfg->cModeInfoArray)
168 {
169 pCfgDst->pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
170 if (!pCfgDst->pModeInfoArray)
171 {
172 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
173 if (pCfgDst->pPathInfoArray)
174 {
175 free(pCfgDst->pPathInfoArray);
176 pCfgDst->pPathInfoArray = NULL;
177 }
178 return ERROR_OUTOFMEMORY;
179 }
180
181 memcpy(pCfgDst->pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
182
183 pCfgDst->cModeInfoArray = pCfg->cModeInfoArray;
184 }
185
186 return ERROR_SUCCESS;
187}
188
189
190static VOID vboxDispIfWddmDcTerm(VBOXDISPIF_WDDM_DISPCFG *pCfg)
191{
192 if (pCfg->pPathInfoArray)
193 free(pCfg->pPathInfoArray);
194 if (pCfg->pModeInfoArray)
195 free(pCfg->pModeInfoArray);
196 /* sanity */
197 memset(pCfg, 0, sizeof (*pCfg));
198}
199
200static UINT32 g_cVBoxDispIfWddmDisplays = 0;
201static DWORD vboxDispIfWddmDcQueryNumDisplays(UINT32 *pcDisplays)
202{
203 if (!g_cVBoxDispIfWddmDisplays)
204 {
205 VBOXDISPIF_WDDM_DISPCFG DispCfg;
206 *pcDisplays = 0;
207 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
208 if (winEr != ERROR_SUCCESS)
209 {
210 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
211 return winEr;
212 }
213
214 int cDisplays = -1;
215
216 for (UINT iter = 0; iter < DispCfg.cPathInfoArray; ++iter)
217 {
218 if (cDisplays < (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id))
219 cDisplays = (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id);
220 }
221
222 cDisplays++;
223
224 g_cVBoxDispIfWddmDisplays = cDisplays;
225 Assert(g_cVBoxDispIfWddmDisplays);
226
227 vboxDispIfWddmDcTerm(&DispCfg);
228 }
229
230 *pcDisplays = g_cVBoxDispIfWddmDisplays;
231 return ERROR_SUCCESS;
232}
233
234#define VBOX_WDDM_DC_SEARCH_PATH_ANY (~(UINT)0)
235static int vboxDispIfWddmDcSearchPath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
236{
237 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
238 {
239 if ( (srcId == VBOX_WDDM_DC_SEARCH_PATH_ANY || pCfg->pPathInfoArray[iter].sourceInfo.id == srcId)
240 && (trgId == VBOX_WDDM_DC_SEARCH_PATH_ANY || pCfg->pPathInfoArray[iter].targetInfo.id == trgId))
241 {
242 return (int)iter;
243 }
244 }
245 return -1;
246}
247
248static int vboxDispIfWddmDcSearchActivePath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
249{
250 int idx = vboxDispIfWddmDcSearchPath(pCfg, srcId, trgId);
251 if (idx < 0)
252 return idx;
253
254 if (!(pCfg->pPathInfoArray[idx].flags & DISPLAYCONFIG_PATH_ACTIVE))
255 return -1;
256
257 return idx;
258}
259
260static VOID vboxDispIfWddmDcSettingsInvalidateModeIndex(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx)
261{
262 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
263 pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
264}
265
266static VOID vboxDispIfWddmDcSettingsInvalidateModeIndeces(VBOXDISPIF_WDDM_DISPCFG *pCfg)
267{
268 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
269 {
270 vboxDispIfWddmDcSettingsInvalidateModeIndex(pCfg, (int)iter);
271 }
272
273 if (pCfg->pModeInfoArray)
274 {
275 free(pCfg->pModeInfoArray);
276 pCfg->pModeInfoArray = NULL;
277 }
278 pCfg->cModeInfoArray = 0;
279}
280
281static DWORD vboxDispIfWddmDcSettingsModeAdd(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT *pIdx)
282{
283 UINT32 cModeInfoArray = pCfg->cModeInfoArray + 1;
284 DISPLAYCONFIG_MODE_INFO *pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
285 if (!pModeInfoArray)
286 {
287 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
288 return ERROR_OUTOFMEMORY;
289 }
290
291 memcpy (pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
292 memset(&pModeInfoArray[cModeInfoArray-1], 0, sizeof (pModeInfoArray[0]));
293 free(pCfg->pModeInfoArray);
294 *pIdx = cModeInfoArray-1;
295 pCfg->pModeInfoArray = pModeInfoArray;
296 pCfg->cModeInfoArray = cModeInfoArray;
297 return ERROR_SUCCESS;
298}
299
300static DWORD vboxDispIfWddmDcSettingsUpdate(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx, DEVMODE *pDeviceMode, BOOL fInvalidateSrcMode, BOOL fEnable)
301{
302 if (fInvalidateSrcMode)
303 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
304 else if (pDeviceMode)
305 {
306 UINT iSrcMode = pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx;
307 if (iSrcMode == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
308 {
309
310 WARN(("VBoxTray: (WDDM) no source mode index specified"));
311 DWORD winEr = vboxDispIfWddmDcSettingsModeAdd(pCfg, &iSrcMode);
312 if (winEr != ERROR_SUCCESS)
313 {
314 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcSettingsModeAdd Failed winEr %d\n", winEr));
315 return winEr;
316 }
317 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = iSrcMode;
318 }
319
320 for (int i = 0; i < (int)pCfg->cPathInfoArray; ++i)
321 {
322 if (i == idx)
323 continue;
324
325 if (pCfg->pPathInfoArray[i].sourceInfo.modeInfoIdx == iSrcMode)
326 {
327 /* this is something we're not expecting/supporting */
328 WARN(("VBoxTray: (WDDM) multiple paths have the same mode index"));
329 return ERROR_NOT_SUPPORTED;
330 }
331 }
332
333 if (pDeviceMode->dmFields & DM_PELSWIDTH)
334 pCfg->pModeInfoArray[iSrcMode].sourceMode.width = pDeviceMode->dmPelsWidth;
335 if (pDeviceMode->dmFields & DM_PELSHEIGHT)
336 pCfg->pModeInfoArray[iSrcMode].sourceMode.height = pDeviceMode->dmPelsHeight;
337 if (pDeviceMode->dmFields & DM_POSITION)
338 {
339 LogFlowFunc(("DM_POSITION %d,%d -> %d,%d\n",
340 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x,
341 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y,
342 pDeviceMode->dmPosition.x, pDeviceMode->dmPosition.y));
343 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x = pDeviceMode->dmPosition.x;
344 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y = pDeviceMode->dmPosition.y;
345 }
346 if (pDeviceMode->dmFields & DM_BITSPERPEL)
347 {
348 switch (pDeviceMode->dmBitsPerPel)
349 {
350 case 32:
351 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
352 break;
353 case 24:
354 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
355 break;
356 case 16:
357 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
358 break;
359 case 8:
360 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
361 break;
362 default:
363 LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32\n", pDeviceMode->dmBitsPerPel));
364 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
365 break;
366 }
367 }
368 }
369
370 pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
371
372 /* "A refresh rate with both the numerator and denominator set to zero indicates that
373 * the caller does not specify a refresh rate and the operating system should use
374 * the most optimal refresh rate available. For this case, in a call to the SetDisplayConfig
375 * function, the caller must set the scanLineOrdering member to the
376 * DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED value; otherwise, SetDisplayConfig fails."
377 *
378 * If a refresh rate is set to a value, then the resize will fail if miniport driver
379 * does not support VSync, i.e. with display-only driver on Win8+ (@bugref{8440}).
380 */
381 pCfg->pPathInfoArray[idx].targetInfo.refreshRate.Numerator = 0;
382 pCfg->pPathInfoArray[idx].targetInfo.refreshRate.Denominator = 0;
383 pCfg->pPathInfoArray[idx].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
384
385 /* Make sure that "The output can be forced on this target even if a monitor is not detected." */
386 pCfg->pPathInfoArray[idx].targetInfo.targetAvailable = TRUE;
387 pCfg->pPathInfoArray[idx].targetInfo.statusFlags |= DISPLAYCONFIG_TARGET_FORCIBLE;
388
389 if (fEnable)
390 pCfg->pPathInfoArray[idx].flags |= DISPLAYCONFIG_PATH_ACTIVE;
391 else
392 pCfg->pPathInfoArray[idx].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
393
394 return ERROR_SUCCESS;
395}
396
397static DWORD vboxDispIfWddmDcSet(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT fFlags)
398{
399 DWORD winEr = gCtx.pfnSetDisplayConfig(pCfg->cPathInfoArray, pCfg->pPathInfoArray, pCfg->cModeInfoArray, pCfg->pModeInfoArray, fFlags);
400 if (winEr != ERROR_SUCCESS)
401 Log(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed for Flags 0x%x\n", fFlags));
402 return winEr;
403}
404
405static BOOL vboxDispIfWddmDcSettingsAdjustSupportedPaths(VBOXDISPIF_WDDM_DISPCFG *pCfg)
406{
407 BOOL fAdjusted = FALSE;
408 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
409 {
410 if (pCfg->pPathInfoArray[iter].sourceInfo.id == pCfg->pPathInfoArray[iter].targetInfo.id)
411 continue;
412
413 if (!(pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
414 continue;
415
416 pCfg->pPathInfoArray[iter].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
417 fAdjusted = TRUE;
418 }
419
420 return fAdjusted;
421}
422
423static void vboxDispIfWddmDcSettingsAttachDisbledToPrimary(VBOXDISPIF_WDDM_DISPCFG *pCfg)
424{
425 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
426 {
427 if ((pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
428 continue;
429
430 pCfg->pPathInfoArray[iter].sourceInfo.id = 0;
431 pCfg->pPathInfoArray[iter].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
432 pCfg->pPathInfoArray[iter].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
433 }
434}
435
436static DWORD vboxDispIfWddmDcSettingsIncludeAllTargets(VBOXDISPIF_WDDM_DISPCFG *pCfg)
437{
438 UINT32 cDisplays = 0;
439 VBOXDISPIF_WDDM_DISPCFG AllCfg;
440 BOOL fAllCfgInited = FALSE;
441
442 DWORD winEr = vboxDispIfWddmDcQueryNumDisplays(&cDisplays);
443 if (winEr != ERROR_SUCCESS)
444 {
445 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcQueryNumDisplays Failed winEr %d\n", winEr));
446 return winEr;
447 }
448
449 DISPLAYCONFIG_PATH_INFO *pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cDisplays * sizeof(DISPLAYCONFIG_PATH_INFO));
450 if (!pPathInfoArray)
451 {
452 WARN(("malloc failed\n"));
453 return ERROR_OUTOFMEMORY;
454 }
455
456 for (UINT i = 0; i < cDisplays; ++i)
457 {
458 int idx = vboxDispIfWddmDcSearchPath(pCfg, i, i);
459 if (idx < 0)
460 {
461 idx = vboxDispIfWddmDcSearchPath(pCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, i);
462 if (idx >= 0)
463 {
464 WARN(("VBoxTray:(WDDM) different source and target paare enabled, this is something we would not expect\n"));
465 }
466 }
467
468 if (idx >= 0)
469 pPathInfoArray[i] = pCfg->pPathInfoArray[idx];
470 else
471 {
472 if (!fAllCfgInited)
473 {
474 winEr = vboxDispIfWddmDcCreate(&AllCfg, QDC_ALL_PATHS);
475 if (winEr != ERROR_SUCCESS)
476 {
477 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
478 free(pPathInfoArray);
479 return winEr;
480 }
481 fAllCfgInited = TRUE;
482 }
483
484 idx = vboxDispIfWddmDcSearchPath(&AllCfg, i, i);
485 if (idx < 0)
486 {
487 WARN(("VBoxTray:(WDDM) %d %d path not supported\n", i, i));
488 idx = vboxDispIfWddmDcSearchPath(pCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, i);
489 if (idx < 0)
490 {
491 WARN(("VBoxTray:(WDDM) %d %d path not supported\n", -1, i));
492 }
493 }
494
495 if (idx >= 0)
496 {
497 pPathInfoArray[i] = AllCfg.pPathInfoArray[idx];
498
499 if (pPathInfoArray[i].flags & DISPLAYCONFIG_PATH_ACTIVE)
500 {
501 WARN(("VBoxTray:(WDDM) disabled path %d %d is marked active\n",
502 pPathInfoArray[i].sourceInfo.id, pPathInfoArray[i].targetInfo.id));
503 pPathInfoArray[i].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
504 }
505
506 Assert(pPathInfoArray[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
507 Assert(pPathInfoArray[i].sourceInfo.statusFlags == 0);
508
509 Assert(pPathInfoArray[i].targetInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
510 Assert(pPathInfoArray[i].targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15);
511 Assert(pPathInfoArray[i].targetInfo.rotation == DISPLAYCONFIG_ROTATION_IDENTITY);
512 Assert(pPathInfoArray[i].targetInfo.scaling == DISPLAYCONFIG_SCALING_PREFERRED);
513 Assert(pPathInfoArray[i].targetInfo.refreshRate.Numerator == 0);
514 Assert(pPathInfoArray[i].targetInfo.refreshRate.Denominator == 0);
515 Assert(pPathInfoArray[i].targetInfo.scanLineOrdering == DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED);
516 Assert(pPathInfoArray[i].targetInfo.targetAvailable == TRUE);
517 Assert(pPathInfoArray[i].targetInfo.statusFlags == DISPLAYCONFIG_TARGET_FORCIBLE);
518
519 Assert(pPathInfoArray[i].flags == 0);
520 }
521 else
522 {
523 pPathInfoArray[i].sourceInfo.adapterId = pCfg->pPathInfoArray[0].sourceInfo.adapterId;
524 pPathInfoArray[i].sourceInfo.id = i;
525 pPathInfoArray[i].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
526 pPathInfoArray[i].sourceInfo.statusFlags = 0;
527
528 pPathInfoArray[i].targetInfo.adapterId = pPathInfoArray[i].sourceInfo.adapterId;
529 pPathInfoArray[i].targetInfo.id = i;
530 pPathInfoArray[i].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
531 pPathInfoArray[i].targetInfo.outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15;
532 pPathInfoArray[i].targetInfo.rotation = DISPLAYCONFIG_ROTATION_IDENTITY;
533 pPathInfoArray[i].targetInfo.scaling = DISPLAYCONFIG_SCALING_PREFERRED;
534 pPathInfoArray[i].targetInfo.refreshRate.Numerator = 0;
535 pPathInfoArray[i].targetInfo.refreshRate.Denominator = 0;
536 pPathInfoArray[i].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
537 pPathInfoArray[i].targetInfo.targetAvailable = TRUE;
538 pPathInfoArray[i].targetInfo.statusFlags = DISPLAYCONFIG_TARGET_FORCIBLE;
539
540 pPathInfoArray[i].flags = 0;
541 }
542 }
543 }
544
545 free(pCfg->pPathInfoArray);
546 pCfg->pPathInfoArray = pPathInfoArray;
547 pCfg->cPathInfoArray = cDisplays;
548 if (fAllCfgInited)
549 vboxDispIfWddmDcTerm(&AllCfg);
550
551 return ERROR_SUCCESS;
552}
553
554static DWORD vboxDispIfOpBegin(PCVBOXDISPIF pIf, VBOXDISPIF_OP *pOp)
555{
556 pOp->pIf = pIf;
557
558 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pOp->Adapter);
559 if (SUCCEEDED(hr))
560 {
561 hr = vboxDispKmtCreateDevice(&pOp->Adapter, &pOp->Device);
562 if (SUCCEEDED(hr))
563 {
564 hr = vboxDispKmtCreateContext(&pOp->Device, &pOp->Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE,
565 0, 0, NULL, 0ULL);
566 if (SUCCEEDED(hr))
567 return ERROR_SUCCESS;
568 else
569 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
570
571 vboxDispKmtDestroyDevice(&pOp->Device);
572 }
573 else
574 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
575
576 vboxDispKmtCloseAdapter(&pOp->Adapter);
577 }
578
579 return hr;
580}
581
582static VOID vboxDispIfOpEnd(VBOXDISPIF_OP *pOp)
583{
584 vboxDispKmtDestroyContext(&pOp->Context);
585 vboxDispKmtDestroyDevice(&pOp->Device);
586 vboxDispKmtCloseAdapter(&pOp->Adapter);
587}
588
589/* display driver interface abstraction for XPDM & WDDM
590 * with WDDM we can not use ExtEscape to communicate with our driver
591 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
592 * that knows nothing about us */
593DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
594{
595 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
596 return NO_ERROR;
597}
598
599#ifdef VBOX_WITH_WDDM
600static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
601static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
602#endif
603
604DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
605{
606#ifdef VBOX_WITH_WDDM
607 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
608 {
609 vboxDispIfWddmTerm(pIf);
610
611 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
612 }
613#endif
614
615 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
616 return NO_ERROR;
617}
618
619static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, int iDirection)
620{
621 RT_NOREF(pIf);
622 HDC hdc = GetDC(HWND_DESKTOP);
623 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
624 int iRet = ExtEscape(hdc, pEscape->escapeCode,
625 iDirection >= 0 ? cbData : 0,
626 iDirection >= 0 ? (LPSTR)pvData : NULL,
627 iDirection <= 0 ? cbData : 0,
628 iDirection <= 0 ? (LPSTR)pvData : NULL);
629 ReleaseDC(HWND_DESKTOP, hdc);
630 if (iRet > 0)
631 return VINF_SUCCESS;
632 if (iRet == 0)
633 return ERROR_NOT_SUPPORTED;
634 /* else */
635 return ERROR_GEN_FAILURE;
636}
637
638#ifdef VBOX_WITH_WDDM
639static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
640{
641 DWORD err = NO_ERROR;
642 OSVERSIONINFO OSinfo;
643 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
644 GetVersionEx (&OSinfo);
645 bool bSupported = true;
646
647 if (OSinfo.dwMajorVersion >= 6)
648 {
649 LogFunc(("this is vista and up\n"));
650 HMODULE hUser = GetModuleHandle("user32.dll");
651 if (hUser)
652 {
653 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
654 LogFunc(("VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
655 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
656
657 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
658 LogFunc(("VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
659 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
660 /* for win 7 and above */
661 if (OSinfo.dwMinorVersion >= 1)
662 {
663 *(uintptr_t *)&gCtx.pfnSetDisplayConfig = (uintptr_t)GetProcAddress(hUser, "SetDisplayConfig");
664 LogFunc(("VBoxDisplayInit: pfnSetDisplayConfig = %p\n", gCtx.pfnSetDisplayConfig));
665 bSupported &= !!(gCtx.pfnSetDisplayConfig);
666
667 *(uintptr_t *)&gCtx.pfnQueryDisplayConfig = (uintptr_t)GetProcAddress(hUser, "QueryDisplayConfig");
668 LogFunc(("VBoxDisplayInit: pfnQueryDisplayConfig = %p\n", gCtx.pfnQueryDisplayConfig));
669 bSupported &= !!(gCtx.pfnQueryDisplayConfig);
670
671 *(uintptr_t *)&gCtx.pfnGetDisplayConfigBufferSizes = (uintptr_t)GetProcAddress(hUser, "GetDisplayConfigBufferSizes");
672 LogFunc(("VBoxDisplayInit: pfnGetDisplayConfigBufferSizes = %p\n", gCtx.pfnGetDisplayConfigBufferSizes));
673 bSupported &= !!(gCtx.pfnGetDisplayConfigBufferSizes);
674 }
675
676 /* this is vista and up */
677 HRESULT hr = vboxDispKmtCallbacksInit(&pIf->modeData.wddm.KmtCallbacks);
678 if (FAILED(hr))
679 {
680 WARN(("VBoxTray: vboxDispKmtCallbacksInit failed hr 0x%x\n", hr));
681 err = hr;
682 }
683 }
684 else
685 {
686 WARN_FUNC(("GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
687 err = ERROR_NOT_SUPPORTED;
688 }
689 }
690 else
691 {
692 WARN_FUNC(("can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
693 err = ERROR_NOT_SUPPORTED;
694 }
695
696 if (err == ERROR_SUCCESS)
697 {
698 err = vboxDispIfWddmInit(pIf);
699 }
700
701 return err;
702}
703
704static DWORD vboxDispIfSwitchToWDDM_W7(PVBOXDISPIF pIf)
705{
706 return vboxDispIfSwitchToWDDM(pIf);
707}
708
709static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
710{
711 DWORD winEr = ERROR_INVALID_STATE;
712 memset(pDev, 0, sizeof (*pDev));
713 pDev->cb = sizeof (*pDev);
714
715 for (int i = 0; ; ++i)
716 {
717 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
718 pDev, 0 /* DWORD dwFlags*/))
719 {
720 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
721 {
722 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
723 if (hDc)
724 {
725 *phDc = hDc;
726 return NO_ERROR;
727 }
728 else
729 {
730 winEr = GetLastError();
731 WARN(("CreateDC failed %d", winEr));
732 break;
733 }
734 }
735 Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
736 }
737 else
738 {
739 winEr = GetLastError();
740 WARN(("EnumDisplayDevices failed %d", winEr));
741 break;
742 }
743 }
744
745 WARN(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
746 return winEr;
747}
748
749static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
750{
751 DWORD winEr = ERROR_SUCCESS;
752 VBOXDISPKMT_ADAPTER Adapter;
753 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &Adapter);
754 if (!SUCCEEDED(hr))
755 {
756 WARN(("VBoxTray: vboxDispKmtOpenAdapter failed hr 0x%x\n", hr));
757 return hr;
758 }
759
760 D3DKMT_ESCAPE EscapeData = {0};
761 EscapeData.hAdapter = Adapter.hAdapter;
762 //EscapeData.hDevice = NULL;
763 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
764 if (fHwAccess)
765 EscapeData.Flags.HardwareAccess = 1;
766 EscapeData.pPrivateDriverData = pEscape;
767 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
768 //EscapeData.hContext = NULL;
769
770 NTSTATUS Status = pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
771 if (NT_SUCCESS(Status))
772 winEr = ERROR_SUCCESS;
773 else
774 {
775 WARN(("VBoxTray: pfnD3DKMTEscape failed Status 0x%x\n", Status));
776 winEr = ERROR_GEN_FAILURE;
777 }
778
779 vboxDispKmtCloseAdapter(&Adapter);
780
781 return winEr;
782}
783#endif
784
785DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
786{
787 switch (pIf->enmMode)
788 {
789 case VBOXDISPIF_MODE_XPDM_NT4:
790 case VBOXDISPIF_MODE_XPDM:
791 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
792#ifdef VBOX_WITH_WDDM
793 case VBOXDISPIF_MODE_WDDM:
794 case VBOXDISPIF_MODE_WDDM_W7:
795 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
796#endif
797 default:
798 LogFunc(("unknown mode (%d)\n", pIf->enmMode));
799 return ERROR_INVALID_PARAMETER;
800 }
801}
802
803DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
804{
805 switch (pIf->enmMode)
806 {
807 case VBOXDISPIF_MODE_XPDM_NT4:
808 case VBOXDISPIF_MODE_XPDM:
809 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
810#ifdef VBOX_WITH_WDDM
811 case VBOXDISPIF_MODE_WDDM:
812 case VBOXDISPIF_MODE_WDDM_W7:
813 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
814#endif
815 default:
816 LogFunc(("unknown mode (%d)\n", pIf->enmMode));
817 return ERROR_INVALID_PARAMETER;
818 }
819}
820
821#ifdef VBOX_WITH_WDDM
822
823#define VBOXRR_TIMER_ID 1234
824
825typedef struct VBOXRR
826{
827 HANDLE hThread;
828 DWORD idThread;
829 HANDLE hEvent;
830 HWND hWnd;
831 CRITICAL_SECTION CritSect;
832 UINT_PTR idTimer;
833 PCVBOXDISPIF pIf;
834 UINT iChangedMode;
835 BOOL fEnable;
836 BOOL fExtDispSup;
837 DISPLAY_DEVICE *paDisplayDevices;
838 DEVMODE *paDeviceModes;
839 UINT cDevModes;
840} VBOXRR, *PVBOXRR;
841
842static VBOXRR g_VBoxRr = {0};
843
844#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
845#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
846
847static void vboxRrRetryStopLocked()
848{
849 PVBOXRR pMon = &g_VBoxRr;
850 if (pMon->pIf)
851 {
852 if (pMon->paDisplayDevices)
853 {
854 free(pMon->paDisplayDevices);
855 pMon->paDisplayDevices = NULL;
856 }
857
858 if (pMon->paDeviceModes)
859 {
860 free(pMon->paDeviceModes);
861 pMon->paDeviceModes = NULL;
862 }
863
864 if (pMon->idTimer)
865 {
866 KillTimer(pMon->hWnd, pMon->idTimer);
867 pMon->idTimer = 0;
868 }
869
870 pMon->cDevModes = 0;
871 pMon->pIf = NULL;
872 }
873}
874
875static void VBoxRrRetryStop()
876{
877 PVBOXRR pMon = &g_VBoxRr;
878 EnterCriticalSection(&pMon->CritSect);
879 vboxRrRetryStopLocked();
880 LeaveCriticalSection(&pMon->CritSect);
881}
882
883//static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
884
885static void vboxRrRetryReschedule()
886{
887}
888
889static void VBoxRrRetrySchedule(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
890{
891 PVBOXRR pMon = &g_VBoxRr;
892 EnterCriticalSection(&pMon->CritSect);
893 vboxRrRetryStopLocked();
894
895 pMon->pIf = pIf;
896 pMon->iChangedMode = iChangedMode;
897 pMon->fEnable = fEnable;
898 pMon->fExtDispSup = fExtDispSup;
899
900 if (cDevModes)
901 {
902 pMon->paDisplayDevices = (DISPLAY_DEVICE*)malloc(sizeof (*paDisplayDevices) * cDevModes);
903 Assert(pMon->paDisplayDevices);
904 if (!pMon->paDisplayDevices)
905 {
906 Log(("malloc failed!"));
907 vboxRrRetryStopLocked();
908 LeaveCriticalSection(&pMon->CritSect);
909 return;
910 }
911 memcpy(pMon->paDisplayDevices, paDisplayDevices, sizeof (*paDisplayDevices) * cDevModes);
912
913 pMon->paDeviceModes = (DEVMODE*)malloc(sizeof (*paDeviceModes) * cDevModes);
914 Assert(pMon->paDeviceModes);
915 if (!pMon->paDeviceModes)
916 {
917 Log(("malloc failed!"));
918 vboxRrRetryStopLocked();
919 LeaveCriticalSection(&pMon->CritSect);
920 return;
921 }
922 memcpy(pMon->paDeviceModes, paDeviceModes, sizeof (*paDeviceModes) * cDevModes);
923 }
924 pMon->cDevModes = cDevModes;
925
926 pMon->idTimer = SetTimer(pMon->hWnd, VBOXRR_TIMER_ID, 1000, (TIMERPROC)NULL);
927 Assert(pMon->idTimer);
928 if (!pMon->idTimer)
929 {
930 WARN(("VBoxTray: SetTimer failed!, err %d\n", GetLastError()));
931 vboxRrRetryStopLocked();
932 }
933
934 LeaveCriticalSection(&pMon->CritSect);
935}
936
937static void vboxRrRetryPerform()
938{
939 PVBOXRR pMon = &g_VBoxRr;
940 EnterCriticalSection(&pMon->CritSect);
941 if (pMon->pIf)
942 {
943 DWORD dwErr = vboxDispIfResizePerform(pMon->pIf, pMon->iChangedMode, pMon->fEnable, pMon->fExtDispSup, pMon->paDisplayDevices, pMon->paDeviceModes, pMon->cDevModes);
944 if (ERROR_RETRY != dwErr)
945 VBoxRrRetryStop();
946 else
947 vboxRrRetryReschedule();
948 }
949 LeaveCriticalSection(&pMon->CritSect);
950}
951
952static LRESULT CALLBACK vboxRrWndProc(HWND hwnd,
953 UINT uMsg,
954 WPARAM wParam,
955 LPARAM lParam
956)
957{
958 switch(uMsg)
959 {
960 case WM_DISPLAYCHANGE:
961 {
962 Log(("VBoxTray: WM_DISPLAYCHANGE\n"));
963 VBoxRrRetryStop();
964 return 0;
965 }
966 case WM_TIMER:
967 {
968 if (wParam == VBOXRR_TIMER_ID)
969 {
970 Log(("VBoxTray: VBOXRR_TIMER_ID\n"));
971 vboxRrRetryPerform();
972 return 0;
973 }
974 break;
975 }
976 case WM_NCHITTEST:
977 LogFunc(("got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
978 return HTNOWHERE;
979 default:
980 break;
981 }
982
983 return DefWindowProc(hwnd, uMsg, wParam, lParam);
984}
985
986#define VBOXRRWND_NAME "VBoxRrWnd"
987
988static HRESULT vboxRrWndCreate(HWND *phWnd)
989{
990 HRESULT hr = S_OK;
991
992 /** @todo r=andy Use VBOXSERVICEENV::hInstance. */
993 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
994
995 /* Register the Window Class. */
996 WNDCLASSEX wc = { 0 };
997 wc.cbSize = sizeof(WNDCLASSEX);
998
999 if (!GetClassInfoEx(hInstance, VBOXRRWND_NAME, &wc))
1000 {
1001 wc.lpfnWndProc = vboxRrWndProc;
1002 wc.hInstance = hInstance;
1003 wc.lpszClassName = VBOXRRWND_NAME;
1004
1005 if (!RegisterClassEx(&wc))
1006 {
1007 WARN_FUNC(("RegisterClass failed, winErr(%d)\n", GetLastError()));
1008 hr = E_FAIL;
1009 }
1010 }
1011
1012 if (hr == S_OK)
1013 {
1014 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
1015 VBOXRRWND_NAME, VBOXRRWND_NAME,
1016 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
1017 -100, -100,
1018 10, 10,
1019 NULL, //GetDesktopWindow() /* hWndParent */,
1020 NULL /* hMenu */,
1021 hInstance,
1022 NULL /* lpParam */);
1023 Assert(hWnd);
1024 if (hWnd)
1025 {
1026 *phWnd = hWnd;
1027 }
1028 else
1029 {
1030 WARN_FUNC(("CreateWindowEx failed, winErr(%d)\n", GetLastError()));
1031 hr = E_FAIL;
1032 }
1033 }
1034
1035 return hr;
1036}
1037
1038static HRESULT vboxRrWndDestroy(HWND hWnd)
1039{
1040 BOOL bResult = DestroyWindow(hWnd);
1041 if (bResult)
1042 return S_OK;
1043
1044 DWORD winErr = GetLastError();
1045 WARN_FUNC(("DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
1046
1047 return HRESULT_FROM_WIN32(winErr);
1048}
1049
1050static HRESULT vboxRrWndInit()
1051{
1052 PVBOXRR pMon = &g_VBoxRr;
1053 return vboxRrWndCreate(&pMon->hWnd);
1054}
1055
1056HRESULT vboxRrWndTerm()
1057{
1058 PVBOXRR pMon = &g_VBoxRr;
1059 HRESULT hrTmp = vboxRrWndDestroy(pMon->hWnd);
1060 Assert(hrTmp == S_OK); NOREF(hrTmp);
1061
1062 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
1063 UnregisterClass(VBOXRRWND_NAME, hInstance);
1064
1065 return S_OK;
1066}
1067
1068#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
1069
1070HRESULT vboxRrRun()
1071{
1072 PVBOXRR pMon = &g_VBoxRr;
1073 MSG Msg;
1074
1075 HRESULT hr = S_FALSE;
1076
1077 /* Create the thread message queue*/
1078 PeekMessage(&Msg,
1079 NULL /* HWND hWnd */,
1080 WM_USER /* UINT wMsgFilterMin */,
1081 WM_USER /* UINT wMsgFilterMax */,
1082 PM_NOREMOVE);
1083
1084 /*
1085 * Send signal that message queue is ready.
1086 * From this moment only the thread is ready to receive messages.
1087 */
1088 BOOL bRc = SetEvent(pMon->hEvent);
1089 if (!bRc)
1090 {
1091 DWORD winErr = GetLastError();
1092 WARN_FUNC(("SetEvent failed, winErr = (%d)", winErr));
1093 HRESULT hrTmp = HRESULT_FROM_WIN32(winErr);
1094 Assert(hrTmp != S_OK); NOREF(hrTmp);
1095 }
1096
1097 do
1098 {
1099 BOOL bResult = GetMessage(&Msg,
1100 0 /*HWND hWnd*/,
1101 0 /*UINT wMsgFilterMin*/,
1102 0 /*UINT wMsgFilterMax*/
1103 );
1104
1105 if (bResult == -1) /* error occurred */
1106 {
1107 DWORD winEr = GetLastError();
1108 hr = HRESULT_FROM_WIN32(winEr);
1109 /* just ensure we never return success in this case */
1110 Assert(hr != S_OK);
1111 Assert(hr != S_FALSE);
1112 if (hr == S_OK || hr == S_FALSE)
1113 hr = E_FAIL;
1114 WARN(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
1115 VBoxRrRetryStop();
1116 break;
1117 }
1118
1119 if(!bResult) /* WM_QUIT was posted */
1120 {
1121 hr = S_FALSE;
1122 Log(("VBoxTray: GetMessage returned FALSE\n"));
1123 VBoxRrRetryStop();
1124 break;
1125 }
1126
1127 switch (Msg.message)
1128 {
1129 case WM_VBOXRR_INIT_QUIT:
1130 case WM_CLOSE:
1131 {
1132 Log(("VBoxTray: closing Rr %d\n", Msg.message));
1133 VBoxRrRetryStop();
1134 PostQuitMessage(0);
1135 break;
1136 }
1137 default:
1138 TranslateMessage(&Msg);
1139 DispatchMessage(&Msg);
1140 break;
1141 }
1142 } while (1);
1143 return 0;
1144}
1145
1146static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
1147{
1148 RT_NOREF(pvUser);
1149 HRESULT hr = vboxRrWndInit();
1150 Assert(hr == S_OK);
1151 if (hr == S_OK)
1152 {
1153 hr = vboxRrRun();
1154 Assert(hr == S_OK);
1155
1156 vboxRrWndTerm();
1157 }
1158
1159 return 0;
1160}
1161
1162HRESULT VBoxRrInit()
1163{
1164 HRESULT hr = E_FAIL;
1165 PVBOXRR pMon = &g_VBoxRr;
1166 memset(pMon, 0, sizeof (*pMon));
1167
1168 InitializeCriticalSection(&pMon->CritSect);
1169
1170 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
1171 TRUE, /* BOOL bManualReset*/
1172 FALSE, /* BOOL bInitialState */
1173 NULL /* LPCTSTR lpName */
1174 );
1175 if (pMon->hEvent)
1176 {
1177 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
1178 0 /* SIZE_T dwStackSize */,
1179 vboxRrRunnerThread,
1180 pMon,
1181 0 /* DWORD dwCreationFlags */,
1182 &pMon->idThread);
1183 if (pMon->hThread)
1184 {
1185 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
1186 if (dwResult == WAIT_OBJECT_0)
1187 return S_OK;
1188 else
1189 {
1190 Log(("WaitForSingleObject failed!"));
1191 hr = E_FAIL;
1192 }
1193 }
1194 else
1195 {
1196 DWORD winErr = GetLastError();
1197 WARN_FUNC(("CreateThread failed, winErr = (%d)", winErr));
1198 hr = HRESULT_FROM_WIN32(winErr);
1199 Assert(hr != S_OK);
1200 }
1201 CloseHandle(pMon->hEvent);
1202 }
1203 else
1204 {
1205 DWORD winErr = GetLastError();
1206 WARN_FUNC(("CreateEvent failed, winErr = (%d)", winErr));
1207 hr = HRESULT_FROM_WIN32(winErr);
1208 Assert(hr != S_OK);
1209 }
1210
1211 DeleteCriticalSection(&pMon->CritSect);
1212
1213 return hr;
1214}
1215
1216VOID VBoxRrTerm()
1217{
1218 HRESULT hr;
1219 PVBOXRR pMon = &g_VBoxRr;
1220 if (!pMon->hThread)
1221 return;
1222
1223 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
1224 DWORD winErr;
1225 if (bResult
1226 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
1227 {
1228 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
1229 if (dwErr == WAIT_OBJECT_0)
1230 {
1231 hr = S_OK;
1232 }
1233 else
1234 {
1235 winErr = GetLastError();
1236 hr = HRESULT_FROM_WIN32(winErr);
1237 }
1238 }
1239 else
1240 {
1241 hr = HRESULT_FROM_WIN32(winErr);
1242 }
1243
1244 DeleteCriticalSection(&pMon->CritSect);
1245
1246 CloseHandle(pMon->hThread);
1247 pMon->hThread = 0;
1248 CloseHandle(pMon->hEvent);
1249 pMon->hThread = 0;
1250}
1251
1252static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
1253{
1254 RT_NOREF(pIf);
1255 HRESULT hr = VBoxRrInit();
1256 if (SUCCEEDED(hr))
1257 return ERROR_SUCCESS;
1258 WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
1259 return hr;
1260}
1261
1262static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
1263{
1264 RT_NOREF(pIf);
1265 VBoxRrTerm();
1266}
1267
1268static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
1269{
1270 if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1271 {
1272 /** @todo do we need ti impl it? */
1273 *pfConnected = TRUE;
1274 return ERROR_SUCCESS;
1275 }
1276
1277 *pfConnected = FALSE;
1278
1279 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1280 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1281 if (winEr != ERROR_SUCCESS)
1282 {
1283 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1284 return winEr;
1285 }
1286
1287 int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
1288 *pfConnected = (idx >= 0);
1289
1290 vboxDispIfWddmDcTerm(&DispCfg);
1291
1292 return ERROR_SUCCESS;
1293}
1294
1295static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp)
1296{
1297 DWORD winEr = ERROR_SUCCESS;
1298 do
1299 {
1300 Sleep(100);
1301
1302 D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
1303 PollData.hAdapter = pOp->Adapter.hAdapter;
1304 PollData.NonDestructiveOnly = 1;
1305 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
1306 if (Status != 0)
1307 {
1308 Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
1309 continue;
1310 }
1311
1312 BOOL fFound = FALSE;
1313#if 0
1314 for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
1315 {
1316 if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
1317 continue;
1318
1319 BOOL fConnected = FALSE;
1320 winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
1321 if (winEr != ERROR_SUCCESS)
1322 {
1323 WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
1324 return winEr;
1325 }
1326
1327 if (!fConnected)
1328 {
1329 WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
1330 fFound = TRUE;
1331 break;
1332 }
1333 }
1334#endif
1335 if (!fFound)
1336 break;
1337 } while (1);
1338
1339 return winEr;
1340}
1341
1342static DWORD vboxDispIfUpdateModesWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, const RTRECTSIZE *pSize)
1343{
1344 DWORD winEr = ERROR_SUCCESS;
1345 VBOXDISPIFESCAPE_UPDATEMODES EscData = {0};
1346 EscData.EscapeHdr.escapeCode = VBOXESC_UPDATEMODES;
1347 EscData.u32TargetId = u32TargetId;
1348 EscData.Size = *pSize;
1349
1350 D3DKMT_ESCAPE EscapeData = {0};
1351 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1352#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1353 /* win8.1 does not allow context-based escapes for display-only mode */
1354 EscapeData.hDevice = pOp->Device.hDevice;
1355 EscapeData.hContext = pOp->Context.hContext;
1356#endif
1357 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1358 EscapeData.Flags.HardwareAccess = 1;
1359 EscapeData.pPrivateDriverData = &EscData;
1360 EscapeData.PrivateDriverDataSize = sizeof (EscData);
1361
1362 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1363 if (NT_SUCCESS(Status))
1364 winEr = ERROR_SUCCESS;
1365 else
1366 {
1367 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_UPDATEMODES failed Status 0x%x\n", Status));
1368 winEr = ERROR_GEN_FAILURE;
1369 }
1370
1371#ifdef VBOX_WDDM_REPLUG_ON_MODE_CHANGE
1372 /* The code was disabled because VBOXESC_UPDATEMODES should not cause (un)plugging virtual displays. */
1373 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1374 if (winEr != NO_ERROR)
1375 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));
1376#endif
1377
1378 return winEr;
1379}
1380
1381static DWORD vboxDispIfTargetConnectivityWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, uint32_t fu32Connect)
1382{
1383 VBOXDISPIFESCAPE_TARGETCONNECTIVITY PrivateData;
1384 RT_ZERO(PrivateData);
1385 PrivateData.EscapeHdr.escapeCode = VBOXESC_TARGET_CONNECTIVITY;
1386 PrivateData.u32TargetId = u32TargetId;
1387 PrivateData.fu32Connect = fu32Connect;
1388
1389 D3DKMT_ESCAPE EscapeData;
1390 RT_ZERO(EscapeData);
1391 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1392 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1393 EscapeData.Flags.HardwareAccess = 1;
1394 EscapeData.pPrivateDriverData = &PrivateData;
1395 EscapeData.PrivateDriverDataSize = sizeof(PrivateData);
1396
1397 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1398 if (NT_SUCCESS(Status))
1399 return ERROR_SUCCESS;
1400
1401 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_TARGETCONNECTIVITY failed Status 0x%x\n", Status));
1402 return ERROR_GEN_FAILURE;
1403}
1404
1405DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
1406{
1407 RT_NOREF(pIf);
1408 Log(("VBoxTray: cancelling pending resize\n"));
1409 VBoxRrRetryStop();
1410 return NO_ERROR;
1411}
1412
1413static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
1414{
1415 /* Without this, Windows will not ask the miniport for its
1416 * mode table but uses an internal cache instead.
1417 */
1418 for (DWORD i = 0; i < cDevModes; i++)
1419 {
1420 DEVMODE tempDevMode;
1421 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
1422 tempDevMode.dmSize = sizeof(DEVMODE);
1423 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
1424 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
1425 }
1426
1427 DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
1428 paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
1429 if (winEr != NO_ERROR)
1430 WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));
1431
1432 return winEr;
1433}
1434
1435static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1436{
1437 LogFunc((" ENTER"));
1438 DWORD winEr;
1439
1440 if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1441 {
1442 winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, fEnable, paDisplayDevices, paDeviceModes, cDevModes);
1443 if (winEr != NO_ERROR)
1444 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
1445 }
1446 else
1447 {
1448 winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
1449 if (winEr != NO_ERROR)
1450 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
1451 }
1452
1453 LogFunc((" LEAVE"));
1454 return winEr;
1455}
1456
1457DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1458{
1459 DWORD winEr = NO_ERROR;
1460
1461 Log(("VBoxTray: vboxDispIfResizeModesWDDM iChanged %d cDevModes %d fEnable %d fExtDispSup %d\n", iChangedMode, cDevModes, fEnable, fExtDispSup));
1462 VBoxRrRetryStop();
1463
1464 VBOXDISPIF_OP Op;
1465
1466 winEr = vboxDispIfOpBegin(pIf, &Op);
1467 if (winEr != NO_ERROR)
1468 {
1469 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
1470 return winEr;
1471 }
1472
1473 VBOXWDDM_RECOMMENDVIDPN VidPnData;
1474
1475 memset(&VidPnData, 0, sizeof (VidPnData));
1476
1477 uint32_t cElements = 0;
1478
1479 for (uint32_t i = 0; i < cDevModes; ++i)
1480 {
1481 if ((i == iChangedMode) ? fEnable : (paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1482 {
1483 VidPnData.aSources[cElements].Size.cx = paDeviceModes[i].dmPelsWidth;
1484 VidPnData.aSources[cElements].Size.cy = paDeviceModes[i].dmPelsHeight;
1485 VidPnData.aTargets[cElements].iSource = cElements;
1486 ++cElements;
1487 }
1488 else
1489 VidPnData.aTargets[cElements].iSource = -1;
1490 }
1491
1492/* The pfnD3DKMTInvalidateActiveVidPn was deprecated since Win7 and causes deadlocks since Win10 TH2.
1493 Instead, the VidPn Manager can replace an old VidPn as soon as SetDisplayConfig or ChangeDisplaySettingsEx will try to set a new display mode.
1494 On Vista D3DKMTInvalidateActiveVidPn is still required. TBD: Get rid of it. */
1495 if (Op.pIf->enmMode < VBOXDISPIF_MODE_WDDM_W7)
1496 {
1497 D3DKMT_INVALIDATEACTIVEVIDPN DdiData = {0};
1498
1499 DdiData.hAdapter = Op.Adapter.hAdapter;
1500 DdiData.pPrivateDriverData = &VidPnData;
1501 DdiData.PrivateDriverDataSize = sizeof (VidPnData);
1502
1503 NTSTATUS Status;
1504 Status = Op.pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTInvalidateActiveVidPn(&DdiData);
1505 LogFunc(("D3DKMTInvalidateActiveVidPn returned %d)\n", Status));
1506 }
1507
1508 vboxDispIfTargetConnectivityWDDM(&Op, iChangedMode, fEnable? 1: 0);
1509
1510 /* Resize displays always to keep the display layout because
1511 * "the D3DKMTInvalidateActiveVidPn function always resets a multimonitor desktop to the default configuration".
1512 */
1513 for (uint32_t i = 0; i < cDevModes; ++i)
1514 {
1515 winEr = NO_ERROR;
1516
1517 /* Whether the current display should be enabled. */
1518 BOOL fCurrentEnable = i == iChangedMode?
1519 fEnable:
1520 RT_BOOL(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE);
1521
1522 if (i == iChangedMode && fCurrentEnable)
1523 {
1524 RTRECTSIZE Size;
1525 Size.cx = paDeviceModes[iChangedMode].dmPelsWidth;
1526 Size.cy = paDeviceModes[iChangedMode].dmPelsHeight;
1527 LogFunc(("Calling vboxDispIfUpdateModesWDDM to change target %d mode to (%d x %d)\n", iChangedMode, Size.cx, Size.cy));
1528 winEr = vboxDispIfUpdateModesWDDM(&Op, iChangedMode, &Size);
1529 LogFunc(("vboxDispIfUpdateModesWDDM returned %d\n", winEr));
1530
1531 if (winEr != NO_ERROR)
1532 WARN(("vboxDispIfUpdateModesWDDM failed %d\n", winEr));
1533 }
1534
1535 if (winEr == NO_ERROR)
1536 {
1537 winEr = vboxDispIfResizePerform(pIf, i, fCurrentEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1538
1539 LogFunc(("vboxDispIfResizePerform returned %d\n", winEr));
1540
1541 if (winEr == ERROR_RETRY)
1542 {
1543 VBoxRrRetrySchedule(pIf, i, fCurrentEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1544
1545 winEr = NO_ERROR;
1546 }
1547 }
1548 }
1549
1550 vboxDispIfOpEnd(&Op);
1551
1552 return winEr;
1553}
1554
1555static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
1556{
1557 RT_NOREF(pIf);
1558 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1559
1560 DWORD winEr;
1561 int iPath;
1562
1563 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1564 if (winEr != ERROR_SUCCESS)
1565 {
1566 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1567 return winEr;
1568 }
1569
1570 UINT cChangeIds = 0;
1571 UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
1572 if (!pChangeIds)
1573 {
1574 WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
1575 winEr = ERROR_OUTOFMEMORY;
1576 goto done;
1577 }
1578
1579 for (UINT i = 0; i < cIds; ++i)
1580 {
1581 UINT Id = pIds[i];
1582 bool fIsDup = false;
1583 for (UINT j = 0; j < cChangeIds; ++j)
1584 {
1585 if (pChangeIds[j] == Id)
1586 {
1587 fIsDup = true;
1588 break;
1589 }
1590 }
1591
1592 if (fIsDup)
1593 continue;
1594
1595 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1596
1597 if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
1598 {
1599 pChangeIds[cChangeIds] = Id;
1600 ++cChangeIds;
1601 }
1602 }
1603
1604 if (cChangeIds == 0)
1605 {
1606 Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
1607 winEr = ERROR_SUCCESS;
1608 goto done;
1609 }
1610
1611 /* we want to set primary for every disabled for non-topoly mode only */
1612 winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
1613 if (winEr != ERROR_SUCCESS)
1614 {
1615 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
1616 return winEr;
1617 }
1618
1619 if (fSetTopology)
1620 vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);
1621
1622 for (UINT i = 0; i < cChangeIds; ++i)
1623 {
1624 UINT Id = pChangeIds[i];
1625 /* re-query paths */
1626 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, Id);
1627 if (iPath < 0)
1628 {
1629 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1630 winEr = ERROR_GEN_FAILURE;
1631 goto done;
1632 }
1633
1634 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
1635 if (winEr != ERROR_SUCCESS)
1636 {
1637 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1638 goto done;
1639 }
1640 }
1641
1642 if (!fSetTopology)
1643 vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);
1644
1645#if 0
1646 /* ensure the zero-index (primary) screen is enabled */
1647 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
1648 if (iPath < 0)
1649 {
1650 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1651 winEr = ERROR_GEN_FAILURE;
1652 goto done;
1653 }
1654
1655 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
1656 if (winEr != ERROR_SUCCESS)
1657 {
1658 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1659 goto done;
1660 }
1661#endif
1662
1663 UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
1664 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1665 if (winEr != ERROR_SUCCESS)
1666 {
1667 if (!fSetTopology)
1668 {
1669 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
1670 fSetFlags |= SDC_ALLOW_CHANGES;
1671 }
1672 else
1673 {
1674 Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
1675 goto done;
1676 }
1677 }
1678
1679 if (!fSetTopology)
1680 fSetFlags |= SDC_SAVE_TO_DATABASE;
1681
1682 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
1683 if (winEr != ERROR_SUCCESS)
1684 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));
1685
1686done:
1687 vboxDispIfWddmDcTerm(&DispCfg);
1688
1689 return winEr;
1690}
1691
1692static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
1693{
1694 DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
1695 if (winEr != ERROR_SUCCESS)
1696 {
1697 if (fEnable)
1698 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1699 else
1700 Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1701 winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
1702 if (winEr != ERROR_SUCCESS)
1703 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1704 }
1705
1706 return winEr;
1707}
1708
1709static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE *paDisplayDevices,
1710 DEVMODE *paDeviceModes, UINT devModes)
1711{
1712 RT_NOREF(paDisplayDevices, devModes);
1713 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1714 DWORD winEr;
1715 int iPath;
1716
1717 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1718 if (winEr != ERROR_SUCCESS)
1719 {
1720 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
1721 return winEr;
1722 }
1723
1724 iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);
1725
1726 if (iPath < 0)
1727 {
1728 vboxDispIfWddmDcTerm(&DispCfg);
1729
1730 if (!fEnable)
1731 {
1732 /* nothing to be done here, just leave */
1733 return ERROR_SUCCESS;
1734 }
1735
1736 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1737 if (winEr != ERROR_SUCCESS)
1738 {
1739 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1740 return winEr;
1741 }
1742
1743 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1744 if (winEr != ERROR_SUCCESS)
1745 {
1746 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1747 return winEr;
1748 }
1749
1750 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1751 if (iPath < 0)
1752 {
1753 WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
1754 vboxDispIfWddmDcTerm(&DispCfg);
1755 return ERROR_RETRY;
1756 }
1757 }
1758
1759 Assert(iPath >= 0);
1760
1761 if (!fEnable)
1762 {
1763 /* need to disable it, and we are done */
1764 vboxDispIfWddmDcTerm(&DispCfg);
1765
1766 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1767 if (winEr != ERROR_SUCCESS)
1768 {
1769 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1770 return winEr;
1771 }
1772
1773 return winEr;
1774 }
1775
1776 Assert(fEnable);
1777
1778 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceModes[Id], FALSE, fEnable);
1779 if (winEr != ERROR_SUCCESS)
1780 {
1781 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
1782 vboxDispIfWddmDcTerm(&DispCfg);
1783 return winEr;
1784 }
1785
1786 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
1787 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1788 if (winEr != ERROR_SUCCESS)
1789 {
1790 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1791 fSetFlags |= SDC_ALLOW_CHANGES;
1792 }
1793
1794 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
1795 if (winEr != ERROR_SUCCESS)
1796 {
1797 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1798 }
1799
1800 vboxDispIfWddmDcTerm(&DispCfg);
1801
1802 return winEr;
1803}
1804
1805#endif /* VBOX_WITH_WDDM */
1806
1807DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1808{
1809 switch (pIf->enmMode)
1810 {
1811 case VBOXDISPIF_MODE_XPDM_NT4:
1812 return ERROR_NOT_SUPPORTED;
1813 case VBOXDISPIF_MODE_XPDM:
1814 return ERROR_NOT_SUPPORTED;
1815#ifdef VBOX_WITH_WDDM
1816 case VBOXDISPIF_MODE_WDDM:
1817 case VBOXDISPIF_MODE_WDDM_W7:
1818 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1819#endif
1820 default:
1821 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
1822 return ERROR_INVALID_PARAMETER;
1823 }
1824}
1825
1826DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
1827{
1828 switch (pIf->enmMode)
1829 {
1830 case VBOXDISPIF_MODE_XPDM_NT4:
1831 return NO_ERROR;
1832 case VBOXDISPIF_MODE_XPDM:
1833 return NO_ERROR;
1834#ifdef VBOX_WITH_WDDM
1835 case VBOXDISPIF_MODE_WDDM:
1836 case VBOXDISPIF_MODE_WDDM_W7:
1837 return vboxDispIfCancelPendingResizeWDDM(pIf);
1838#endif
1839 default:
1840 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
1841 return ERROR_INVALID_PARAMETER;
1842 }
1843}
1844
1845static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
1846{
1847 VBOXDISPIFESCAPE EscapeHdr = {0};
1848 EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
1849 EscapeHdr.u32CmdSpecific = 0;
1850
1851 D3DKMT_ESCAPE EscapeData = {0};
1852 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1853#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1854 /* win8.1 does not allow context-based escapes for display-only mode */
1855 EscapeData.hDevice = pOp->Device.hDevice;
1856 EscapeData.hContext = pOp->Context.hContext;
1857#endif
1858 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1859 EscapeData.Flags.HardwareAccess = 1;
1860 EscapeData.pPrivateDriverData = &EscapeHdr;
1861 EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);
1862
1863 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1864 if (NT_SUCCESS(Status))
1865 {
1866 if (pcConnected)
1867 *pcConnected = EscapeHdr.u32CmdSpecific;
1868 return NO_ERROR;
1869 }
1870 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
1871 return Status;
1872}
1873
1874static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
1875{
1876 DWORD NumDevices = VBoxDisplayGetCount();
1877 if (NumDevices == 0)
1878 {
1879 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1880 return ERROR_GEN_FAILURE;
1881 }
1882
1883 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
1884 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
1885 DWORD DevNum = 0;
1886 DWORD DevPrimaryNum = 0;
1887
1888 DWORD winEr = VBoxDisplayGetConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
1889 if (winEr != NO_ERROR)
1890 {
1891 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
1892 return winEr;
1893 }
1894
1895 if (NumDevices != DevNum)
1896 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
1897
1898
1899 uint32_t cConnected = 0;
1900 winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
1901 if (winEr != NO_ERROR)
1902 {
1903 WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
1904 return winEr;
1905 }
1906
1907 if (!cConnected)
1908 {
1909 Log(("VBoxTray: all targets already connected, nothing to do\n"));
1910 return NO_ERROR;
1911 }
1912
1913 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1914 if (winEr != NO_ERROR)
1915 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));
1916
1917 DWORD NewNumDevices = VBoxDisplayGetCount();
1918 if (NewNumDevices == 0)
1919 {
1920 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1921 return ERROR_GEN_FAILURE;
1922 }
1923
1924 if (NewNumDevices != NumDevices)
1925 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));
1926
1927 DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
1928 DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
1929 DWORD NewDevNum = 0;
1930 DWORD NewDevPrimaryNum = 0;
1931
1932 winEr = VBoxDisplayGetConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
1933 if (winEr != NO_ERROR)
1934 {
1935 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
1936 return winEr;
1937 }
1938
1939 if (NewNumDevices != NewDevNum)
1940 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));
1941
1942 DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
1943 UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
1944 UINT cIds = 0;
1945 for (DWORD i = 0; i < minDevNum; ++i)
1946 {
1947 if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
1948 && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1949 {
1950 pIds[cIds] = i;
1951 ++cIds;
1952 }
1953 }
1954
1955 if (!cIds)
1956 {
1957 /* this is something we would not regularly expect */
1958 WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
1959 return NO_ERROR;
1960 }
1961
1962 if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1963 {
1964 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
1965 if (winEr != NO_ERROR)
1966 WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
1967 }
1968 else
1969 {
1970 for (DWORD i = 0; i < cIds; ++i)
1971 {
1972 winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
1973 if (winEr != NO_ERROR)
1974 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
1975 }
1976 }
1977
1978 return winEr;
1979}
1980
1981
1982static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
1983{
1984 VBOXDISPIF_OP Op;
1985
1986 DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
1987 if (winEr != NO_ERROR)
1988 {
1989 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
1990 return winEr;
1991 }
1992
1993 winEr = vboxDispIfResizeStartedWDDMOp(&Op);
1994 if (winEr != NO_ERROR)
1995 {
1996 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
1997 }
1998
1999 vboxDispIfOpEnd(&Op);
2000
2001 return winEr;
2002}
2003
2004DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
2005{
2006 switch (pIf->enmMode)
2007 {
2008 case VBOXDISPIF_MODE_XPDM_NT4:
2009 return NO_ERROR;
2010 case VBOXDISPIF_MODE_XPDM:
2011 return NO_ERROR;
2012#ifdef VBOX_WITH_WDDM
2013 case VBOXDISPIF_MODE_WDDM:
2014 case VBOXDISPIF_MODE_WDDM_W7:
2015 return vboxDispIfResizeStartedWDDM(pIf);
2016#endif
2017 default:
2018 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
2019 return ERROR_INVALID_PARAMETER;
2020 }
2021}
2022
2023static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
2024{
2025 RT_NOREF(pIf);
2026 return NO_ERROR;
2027}
2028
2029static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
2030{
2031 DWORD err = NO_ERROR;
2032
2033 OSVERSIONINFO OSinfo;
2034 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
2035 GetVersionEx (&OSinfo);
2036 if (OSinfo.dwMajorVersion >= 5)
2037 {
2038 HMODULE hUser = GetModuleHandle("user32.dll");
2039 if (NULL != hUser)
2040 {
2041 bool bSupported = true;
2042 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
2043 LogFunc(("pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
2044 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
2045
2046 if (!bSupported)
2047 {
2048 WARN_FUNC(("pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
2049 err = ERROR_NOT_SUPPORTED;
2050 }
2051 }
2052 else
2053 {
2054 WARN_FUNC(("failed to get USER32 handle, err (%d)\n", GetLastError()));
2055 err = ERROR_NOT_SUPPORTED;
2056 }
2057 }
2058 else
2059 {
2060 WARN_FUNC(("can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
2061 err = ERROR_NOT_SUPPORTED;
2062 }
2063
2064 return err;
2065}
2066
2067DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
2068{
2069 /** @todo may need to addd synchronization in case we want to change modes dynamically
2070 * i.e. currently the mode is supposed to be initialized once on service initialization */
2071 if (penmOldMode)
2072 *penmOldMode = pIf->enmMode;
2073
2074 if (enmMode == pIf->enmMode)
2075 return NO_ERROR;
2076
2077#ifdef VBOX_WITH_WDDM
2078 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
2079 {
2080 vboxDispIfWddmTerm(pIf);
2081
2082 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
2083 }
2084#endif
2085
2086 DWORD err = NO_ERROR;
2087 switch (enmMode)
2088 {
2089 case VBOXDISPIF_MODE_XPDM_NT4:
2090 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
2091 err = vboxDispIfSwitchToXPDM_NT4(pIf);
2092 if (err == NO_ERROR)
2093 {
2094 LogFunc(("successfully switched to XPDM_NT4 mode\n"));
2095 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
2096 }
2097 else
2098 WARN_FUNC(("failed to switch to XPDM_NT4 mode, err (%d)\n", err));
2099 break;
2100 case VBOXDISPIF_MODE_XPDM:
2101 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM\n"));
2102 err = vboxDispIfSwitchToXPDM(pIf);
2103 if (err == NO_ERROR)
2104 {
2105 LogFunc(("successfully switched to XPDM mode\n"));
2106 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
2107 }
2108 else
2109 WARN_FUNC(("failed to switch to XPDM mode, err (%d)\n", err));
2110 break;
2111#ifdef VBOX_WITH_WDDM
2112 case VBOXDISPIF_MODE_WDDM:
2113 {
2114 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM\n"));
2115 err = vboxDispIfSwitchToWDDM(pIf);
2116 if (err == NO_ERROR)
2117 {
2118 LogFunc(("successfully switched to WDDM mode\n"));
2119 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
2120 }
2121 else
2122 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2123 break;
2124 }
2125 case VBOXDISPIF_MODE_WDDM_W7:
2126 {
2127 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
2128 err = vboxDispIfSwitchToWDDM_W7(pIf);
2129 if (err == NO_ERROR)
2130 {
2131 LogFunc(("successfully switched to WDDM mode\n"));
2132 pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
2133 }
2134 else
2135 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2136 break;
2137 }
2138#endif
2139 default:
2140 err = ERROR_INVALID_PARAMETER;
2141 break;
2142 }
2143 return err;
2144}
2145
2146static DWORD vboxDispIfSeamlessCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2147{
2148 RT_NOREF(hEvent);
2149 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
2150 if (SUCCEEDED(hr))
2151 {
2152#ifndef VBOX_DISPIF_WITH_OPCONTEXT
2153 return ERROR_SUCCESS;
2154#else
2155 hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
2156 if (SUCCEEDED(hr))
2157 {
2158 hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
2159 0, 0, hEvent, 0ULL);
2160 if (SUCCEEDED(hr))
2161 return ERROR_SUCCESS;
2162 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
2163
2164 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2165 }
2166 else
2167 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
2168
2169 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2170#endif /* VBOX_DISPIF_WITH_OPCONTEXT */
2171 }
2172
2173 return hr;
2174}
2175
2176static DWORD vboxDispIfSeamlessTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
2177{
2178#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2179 vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
2180 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2181#endif
2182 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2183
2184 return NO_ERROR;
2185}
2186
2187static DWORD vboxDispIfSeamlessSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2188{
2189 D3DKMT_ESCAPE EscapeData = {0};
2190 EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
2191#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2192 EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
2193 EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
2194#endif
2195 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
2196 /*EscapeData.Flags.HardwareAccess = 1;*/
2197 EscapeData.pPrivateDriverData = pData;
2198 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
2199
2200 NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
2201 if (NT_SUCCESS(Status))
2202 return ERROR_SUCCESS;
2203
2204 WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
2205 return Status;
2206}
2207
2208DWORD VBoxDispIfSeamlessCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2209{
2210 memset(pSeamless, 0, sizeof (*pSeamless));
2211 pSeamless->pIf = pIf;
2212
2213 switch (pIf->enmMode)
2214 {
2215 case VBOXDISPIF_MODE_XPDM_NT4:
2216 case VBOXDISPIF_MODE_XPDM:
2217 return NO_ERROR;
2218#ifdef VBOX_WITH_WDDM
2219 case VBOXDISPIF_MODE_WDDM:
2220 case VBOXDISPIF_MODE_WDDM_W7:
2221 return vboxDispIfSeamlessCreateWDDM(pIf, pSeamless, hEvent);
2222#endif
2223 default:
2224 break;
2225 }
2226
2227 WARN(("VBoxTray: VBoxDispIfSeamlessCreate: invalid mode %d\n", pIf->enmMode));
2228 return ERROR_INVALID_PARAMETER;
2229}
2230
2231DWORD VBoxDispIfSeamlessTerm(VBOXDISPIF_SEAMLESS *pSeamless)
2232{
2233 PCVBOXDISPIF const pIf = pSeamless->pIf;
2234 DWORD winEr;
2235 switch (pIf->enmMode)
2236 {
2237 case VBOXDISPIF_MODE_XPDM_NT4:
2238 case VBOXDISPIF_MODE_XPDM:
2239 winEr = NO_ERROR;
2240 break;
2241#ifdef VBOX_WITH_WDDM
2242 case VBOXDISPIF_MODE_WDDM:
2243 case VBOXDISPIF_MODE_WDDM_W7:
2244 winEr = vboxDispIfSeamlessTermWDDM(pSeamless);
2245 break;
2246#endif
2247 default:
2248 WARN(("VBoxTray: VBoxDispIfSeamlessTerm: invalid mode %d\n", pIf->enmMode));
2249 winEr = ERROR_INVALID_PARAMETER;
2250 break;
2251 }
2252
2253 if (winEr == NO_ERROR)
2254 memset(pSeamless, 0, sizeof (*pSeamless));
2255
2256 return winEr;
2257}
2258
2259DWORD VBoxDispIfSeamlessSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2260{
2261 PCVBOXDISPIF const pIf = pSeamless->pIf;
2262
2263 if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
2264 {
2265 WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
2266 return ERROR_INVALID_PARAMETER;
2267 }
2268
2269 switch (pIf->enmMode)
2270 {
2271 case VBOXDISPIF_MODE_XPDM_NT4:
2272 case VBOXDISPIF_MODE_XPDM:
2273 return VBoxDispIfEscape(pIf, pData, cbData);
2274#ifdef VBOX_WITH_WDDM
2275 case VBOXDISPIF_MODE_WDDM:
2276 case VBOXDISPIF_MODE_WDDM_W7:
2277 return vboxDispIfSeamlessSubmitWDDM(pSeamless, pData, cbData);
2278#endif
2279 default:
2280 WARN(("VBoxTray: VBoxDispIfSeamlessSubmit: invalid mode %d\n", pIf->enmMode));
2281 return ERROR_INVALID_PARAMETER;
2282 }
2283}
2284
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