VirtualBox

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

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

fix for ​​​​​​​bugref:8441: removed unneeded comment

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