VirtualBox

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

Last change on this file since 62556 was 62522, checked in by vboxsync, 8 years ago

(C) 2016

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