VirtualBox

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

Last change on this file since 73724 was 73724, checked in by vboxsync, 6 years ago

VMMDev: multimonitor resize for Windows guests, bugref:8444

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

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