VirtualBox

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

最後變更 在這個檔案從95049是 95049,由 vboxsync 提交於 3 年 前

Additions/VBoxTray: Fixed regression introduced in r117497, which caused a debug assertion + crash on startup on NT4 guests; make sure that we never try to run anything else but VBOXDISPIF_MODE_XPDM_NT4 on NT4 guests. Anything else will get us into serious trouble.

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

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