VirtualBox

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

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

GA/NT/VBoxTray: warnings

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