VirtualBox

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

Last change on this file since 84382 was 84382, checked in by vboxsync, 5 years ago

VBoxTray: log display config on error.

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

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