VirtualBox

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

Last change on this file since 72003 was 72003, checked in by vboxsync, 7 years ago

VBoxDispIf: trailing tab

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