VirtualBox

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

Last change on this file since 61603 was 61603, checked in by vboxsync, 9 years ago

VBoxTray: fixed regression from r107867: do not re-enable disabled screens

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.1 KB
Line 
1/* $Id: VBoxDispIf.cpp 61603 2016-06-09 07:48:13Z 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_CLOSE:
945 LogFunc(("got WM_CLOSE for hwnd(0x%x)", hwnd));
946 return 0;
947 case WM_DESTROY:
948 LogFunc(("got WM_DESTROY for hwnd(0x%x)", hwnd));
949 return 0;
950 case WM_NCHITTEST:
951 LogFunc(("got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
952 return HTNOWHERE;
953 default:
954 break;
955 }
956
957 return DefWindowProc(hwnd, uMsg, wParam, lParam);
958}
959
960#define VBOXRRWND_NAME "VBoxRrWnd"
961
962static HRESULT vboxRrWndCreate(HWND *phWnd)
963{
964 HRESULT hr = S_OK;
965
966 /** @todo r=andy Use VBOXSERVICEENV::hInstance. */
967 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
968
969 /* Register the Window Class. */
970 WNDCLASSEX wc = { 0 };
971 wc.cbSize = sizeof(WNDCLASSEX);
972
973 if (!GetClassInfoEx(hInstance, VBOXRRWND_NAME, &wc))
974 {
975 wc.lpfnWndProc = vboxRrWndProc;
976 wc.hInstance = hInstance;
977 wc.lpszClassName = VBOXRRWND_NAME;
978
979 if (!RegisterClassEx(&wc))
980 {
981 DWORD winErr = GetLastError();
982 WARN_FUNC(("RegisterClass failed, winErr(%d)\n", winErr));
983 hr = E_FAIL;
984 }
985 }
986
987 if (hr == S_OK)
988 {
989 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
990 VBOXRRWND_NAME, VBOXRRWND_NAME,
991 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
992 -100, -100,
993 10, 10,
994 NULL, //GetDesktopWindow() /* hWndParent */,
995 NULL /* hMenu */,
996 hInstance,
997 NULL /* lpParam */);
998 Assert(hWnd);
999 if (hWnd)
1000 {
1001 *phWnd = hWnd;
1002 }
1003 else
1004 {
1005 DWORD winErr = GetLastError();
1006 WARN_FUNC(("CreateWindowEx failed, winErr(%d)\n", winErr));
1007 hr = E_FAIL;
1008 }
1009 }
1010
1011 return hr;
1012}
1013
1014static HRESULT vboxRrWndDestroy(HWND hWnd)
1015{
1016 BOOL bResult = DestroyWindow(hWnd);
1017 if (bResult)
1018 return S_OK;
1019
1020 DWORD winErr = GetLastError();
1021 WARN_FUNC(("DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
1022
1023 return HRESULT_FROM_WIN32(winErr);
1024}
1025
1026static HRESULT vboxRrWndInit()
1027{
1028 PVBOXRR pMon = &g_VBoxRr;
1029 return vboxRrWndCreate(&pMon->hWnd);
1030}
1031
1032HRESULT vboxRrWndTerm()
1033{
1034 PVBOXRR pMon = &g_VBoxRr;
1035 HRESULT tmpHr = vboxRrWndDestroy(pMon->hWnd);
1036 Assert(tmpHr == S_OK);
1037
1038 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
1039 UnregisterClass(VBOXRRWND_NAME, hInstance);
1040
1041 return S_OK;
1042}
1043
1044#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
1045
1046HRESULT vboxRrRun()
1047{
1048 PVBOXRR pMon = &g_VBoxRr;
1049 MSG Msg;
1050
1051 HRESULT hr = S_FALSE;
1052
1053 PeekMessage(&Msg,
1054 NULL /* HWND hWnd */,
1055 WM_USER /* UINT wMsgFilterMin */,
1056 WM_USER /* UINT wMsgFilterMax */,
1057 PM_NOREMOVE);
1058
1059 do
1060 {
1061 BOOL bResult = GetMessage(&Msg,
1062 0 /*HWND hWnd*/,
1063 0 /*UINT wMsgFilterMin*/,
1064 0 /*UINT wMsgFilterMax*/
1065 );
1066
1067 if(!bResult) /* WM_QUIT was posted */
1068 {
1069 hr = S_FALSE;
1070 Log(("VBoxTray: GetMessage returned FALSE\n"));
1071 VBoxRrRetryStop();
1072 break;
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 switch (Msg.message)
1090 {
1091 case WM_VBOXRR_INIT_QUIT:
1092 case WM_CLOSE:
1093 {
1094 Log(("VBoxTray: closing Rr %d\n", Msg.message));
1095 VBoxRrRetryStop();
1096 PostQuitMessage(0);
1097 break;
1098 }
1099 default:
1100 TranslateMessage(&Msg);
1101 DispatchMessage(&Msg);
1102 break;
1103 }
1104 } while (1);
1105 return 0;
1106}
1107
1108static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
1109{
1110 PVBOXRR pMon = &g_VBoxRr;
1111
1112 BOOL bRc = SetEvent(pMon->hEvent);
1113 if (!bRc)
1114 {
1115 DWORD winErr = GetLastError();
1116 WARN_FUNC(("SetEvent failed, winErr = (%d)", winErr));
1117 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
1118 Assert(tmpHr != S_OK);
1119 }
1120
1121 HRESULT hr = vboxRrWndInit();
1122 Assert(hr == S_OK);
1123 if (hr == S_OK)
1124 {
1125 hr = vboxRrRun();
1126 Assert(hr == S_OK);
1127
1128 vboxRrWndTerm();
1129 }
1130
1131 return 0;
1132}
1133
1134HRESULT VBoxRrInit()
1135{
1136 HRESULT hr = E_FAIL;
1137 PVBOXRR pMon = &g_VBoxRr;
1138 memset(pMon, 0, sizeof (*pMon));
1139
1140 InitializeCriticalSection(&pMon->CritSect);
1141
1142 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
1143 TRUE, /* BOOL bManualReset*/
1144 FALSE, /* BOOL bInitialState */
1145 NULL /* LPCTSTR lpName */
1146 );
1147 if (pMon->hEvent)
1148 {
1149 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
1150 0 /* SIZE_T dwStackSize */,
1151 vboxRrRunnerThread,
1152 pMon,
1153 0 /* DWORD dwCreationFlags */,
1154 &pMon->idThread);
1155 if (pMon->hThread)
1156 {
1157 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
1158 if (dwResult == WAIT_OBJECT_0)
1159 return S_OK;
1160 else
1161 {
1162 Log(("WaitForSingleObject failed!"));
1163 hr = E_FAIL;
1164 }
1165 }
1166 else
1167 {
1168 DWORD winErr = GetLastError();
1169 WARN_FUNC(("CreateThread failed, winErr = (%d)", winErr));
1170 hr = HRESULT_FROM_WIN32(winErr);
1171 Assert(hr != S_OK);
1172 }
1173 CloseHandle(pMon->hEvent);
1174 }
1175 else
1176 {
1177 DWORD winErr = GetLastError();
1178 WARN_FUNC(("CreateEvent failed, winErr = (%d)", winErr));
1179 hr = HRESULT_FROM_WIN32(winErr);
1180 Assert(hr != S_OK);
1181 }
1182
1183 DeleteCriticalSection(&pMon->CritSect);
1184
1185 return hr;
1186}
1187
1188VOID VBoxRrTerm()
1189{
1190 HRESULT hr;
1191 PVBOXRR pMon = &g_VBoxRr;
1192 if (!pMon->hThread)
1193 return;
1194
1195 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
1196 DWORD winErr;
1197 if (bResult
1198 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
1199 {
1200 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
1201 if (dwErr == WAIT_OBJECT_0)
1202 {
1203 hr = S_OK;
1204 }
1205 else
1206 {
1207 winErr = GetLastError();
1208 hr = HRESULT_FROM_WIN32(winErr);
1209 }
1210 }
1211 else
1212 {
1213 hr = HRESULT_FROM_WIN32(winErr);
1214 }
1215
1216 DeleteCriticalSection(&pMon->CritSect);
1217
1218 CloseHandle(pMon->hThread);
1219 pMon->hThread = 0;
1220 CloseHandle(pMon->hEvent);
1221 pMon->hThread = 0;
1222}
1223
1224static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
1225{
1226 HRESULT hr = VBoxRrInit();
1227 if (SUCCEEDED(hr))
1228 {
1229 return ERROR_SUCCESS;
1230 }
1231 WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
1232 return hr;
1233}
1234
1235static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
1236{
1237 VBoxRrTerm();
1238}
1239
1240static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
1241{
1242 if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1243 {
1244 /* @todo: do we need ti impl it? */
1245 *pfConnected = TRUE;
1246 return ERROR_SUCCESS;
1247 }
1248
1249 *pfConnected = FALSE;
1250
1251 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1252 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1253 if (winEr != ERROR_SUCCESS)
1254 {
1255 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1256 return winEr;
1257 }
1258
1259 int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
1260 *pfConnected = (idx >= 0);
1261
1262 vboxDispIfWddmDcTerm(&DispCfg);
1263
1264 return ERROR_SUCCESS;
1265}
1266
1267static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp)
1268{
1269 DWORD winEr = ERROR_SUCCESS;
1270 do
1271 {
1272 Sleep(100);
1273
1274 D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
1275 PollData.hAdapter = pOp->Adapter.hAdapter;
1276 PollData.NonDestructiveOnly = 1;
1277 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
1278 if (Status != 0)
1279 {
1280 Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
1281 continue;
1282 }
1283
1284 BOOL fFound = FALSE;
1285#if 0
1286 for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
1287 {
1288 if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
1289 continue;
1290
1291 BOOL fConnected = FALSE;
1292 winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
1293 if (winEr != ERROR_SUCCESS)
1294 {
1295 WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
1296 return winEr;
1297 }
1298
1299 if (!fConnected)
1300 {
1301 WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
1302 fFound = TRUE;
1303 break;
1304 }
1305 }
1306#endif
1307 if (!fFound)
1308 break;
1309 } while (1);
1310
1311 return winEr;
1312}
1313
1314static DWORD vboxDispIfUpdateModesWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, const RTRECTSIZE *pSize)
1315{
1316 DWORD winEr = ERROR_SUCCESS;
1317 VBOXDISPIFESCAPE_UPDATEMODES EscData = {0};
1318 EscData.EscapeHdr.escapeCode = VBOXESC_UPDATEMODES;
1319 EscData.u32TargetId = u32TargetId;
1320 EscData.Size = *pSize;
1321
1322 D3DKMT_ESCAPE EscapeData = {0};
1323 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1324#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1325 /* win8.1 does not allow context-based escapes for display-only mode */
1326 EscapeData.hDevice = pOp->Device.hDevice;
1327 EscapeData.hContext = pOp->Context.hContext;
1328#endif
1329 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1330 EscapeData.Flags.HardwareAccess = 1;
1331 EscapeData.pPrivateDriverData = &EscData;
1332 EscapeData.PrivateDriverDataSize = sizeof (EscData);
1333
1334 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1335 if (NT_SUCCESS(Status))
1336 winEr = ERROR_SUCCESS;
1337 else
1338 {
1339 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_UPDATEMODES failed Status 0x%x\n", Status));
1340 winEr = ERROR_GEN_FAILURE;
1341 }
1342
1343/* The code below was commented out because VBOXESC_UPDATEMODES should not cause (un)plugging virtual displays.
1344 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1345 if (winEr != NO_ERROR)
1346 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));
1347*/
1348 return winEr;
1349}
1350
1351DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
1352{
1353 Log(("VBoxTray: cancelling pending resize\n"));
1354 VBoxRrRetryStop();
1355 return NO_ERROR;
1356}
1357
1358static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
1359{
1360 /* Without this, Windows will not ask the miniport for its
1361 * mode table but uses an internal cache instead.
1362 */
1363 for (DWORD i = 0; i < cDevModes; i++)
1364 {
1365 DEVMODE tempDevMode;
1366 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
1367 tempDevMode.dmSize = sizeof(DEVMODE);
1368 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
1369 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
1370 }
1371
1372 DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
1373 paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
1374 if (winEr != NO_ERROR)
1375 WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));
1376
1377 return winEr;
1378}
1379
1380static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1381{
1382 LogFunc((" ENTER"));
1383 DWORD winEr;
1384
1385 if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1386 {
1387 winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, fEnable, paDisplayDevices, paDeviceModes, cDevModes);
1388 if (winEr != NO_ERROR)
1389 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
1390 }
1391 else
1392 {
1393 winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
1394 if (winEr != NO_ERROR)
1395 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
1396 }
1397
1398 LogFunc((" LEAVE"));
1399 return winEr;
1400}
1401
1402DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1403{
1404 DWORD winEr = NO_ERROR;
1405
1406 Log(("VBoxTray: vboxDispIfResizeModesWDDM iChanged %d cDevModes %d fEnable %d fExtDispSup %d\n", iChangedMode, cDevModes, fEnable, fExtDispSup));
1407 VBoxRrRetryStop();
1408
1409 VBOXDISPIF_OP Op;
1410
1411 winEr = vboxDispIfOpBegin(pIf, &Op);
1412 if (winEr != NO_ERROR)
1413 {
1414 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
1415 return winEr;
1416 }
1417
1418 VBOXWDDM_RECOMMENDVIDPN VidPnData;
1419
1420 memset(&VidPnData, 0, sizeof (VidPnData));
1421
1422 uint32_t cElements = 0;
1423
1424 for (uint32_t i = 0; i < cDevModes; ++i)
1425 {
1426 if ((i == iChangedMode) ? fEnable : (paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1427 {
1428 VidPnData.aSources[cElements].Size.cx = paDeviceModes[i].dmPelsWidth;
1429 VidPnData.aSources[cElements].Size.cy = paDeviceModes[i].dmPelsHeight;
1430 VidPnData.aTargets[cElements].iSource = cElements;
1431 ++cElements;
1432 }
1433 else
1434 VidPnData.aTargets[cElements].iSource = -1;
1435 }
1436
1437/* The pfnD3DKMTInvalidateActiveVidPn was deprecated since Win7 and causes deadlocks since Win10 TH2.
1438 Instead, the VidPn Manager can replace an old VidPn as soon as SetDisplayConfig or ChangeDisplaySettingsEx will try to set a new display mode.
1439 On Vista D3DKMTInvalidateActiveVidPn is still required. TBD: Get rid of it. */
1440 if (Op.pIf->enmMode < VBOXDISPIF_MODE_WDDM_W7)
1441 {
1442 D3DKMT_INVALIDATEACTIVEVIDPN DdiData = {0};
1443
1444 DdiData.hAdapter = Op.Adapter.hAdapter;
1445 DdiData.pPrivateDriverData = &VidPnData;
1446 DdiData.PrivateDriverDataSize = sizeof (VidPnData);
1447
1448 NTSTATUS Status;
1449 Status = Op.pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTInvalidateActiveVidPn(&DdiData);
1450 LogFunc(("D3DKMTInvalidateActiveVidPn returned %d)\n", Status));
1451 }
1452
1453 /* Resize displays always to keep the display layout because
1454 * "the D3DKMTInvalidateActiveVidPn function always resets a multimonitor desktop to the default configuration".
1455 */
1456 for (uint32_t i = 0; i < cDevModes; ++i)
1457 {
1458 winEr = NO_ERROR;
1459
1460 /* Whether the current display should be enabled. */
1461 BOOL fCurrentEnable = i == iChangedMode?
1462 fEnable:
1463 RT_BOOL(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE);
1464
1465 if (i == iChangedMode && fCurrentEnable)
1466 {
1467 RTRECTSIZE Size;
1468 Size.cx = paDeviceModes[iChangedMode].dmPelsWidth;
1469 Size.cy = paDeviceModes[iChangedMode].dmPelsHeight;
1470 LogFunc(("Calling vboxDispIfUpdateModesWDDM to change target %d mode to (%d x %d)\n", iChangedMode, Size.cx, Size.cy));
1471 winEr = vboxDispIfUpdateModesWDDM(&Op, iChangedMode, &Size);
1472 LogFunc(("vboxDispIfUpdateModesWDDM returned %d\n", winEr));
1473
1474 if (winEr != NO_ERROR)
1475 WARN(("vboxDispIfUpdateModesWDDM failed %d\n", winEr));
1476 }
1477
1478 if (winEr == NO_ERROR)
1479 {
1480 winEr = vboxDispIfResizePerform(pIf, i, fCurrentEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1481
1482 LogFunc(("vboxDispIfResizePerform returned %d\n", winEr));
1483
1484 if (winEr == ERROR_RETRY)
1485 {
1486 VBoxRrRetrySchedule(pIf, i, fCurrentEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1487
1488 winEr = NO_ERROR;
1489 }
1490 }
1491 }
1492
1493 vboxDispIfOpEnd(&Op);
1494
1495 return winEr;
1496}
1497
1498static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
1499{
1500 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1501
1502 DWORD winEr;
1503 int iPath;
1504
1505 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1506 if (winEr != ERROR_SUCCESS)
1507 {
1508 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1509 return winEr;
1510 }
1511
1512 UINT cChangeIds = 0;
1513 UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
1514 if (!pChangeIds)
1515 {
1516 WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
1517 winEr = ERROR_OUTOFMEMORY;
1518 goto done;
1519 }
1520
1521 for (UINT i = 0; i < cIds; ++i)
1522 {
1523 UINT Id = pIds[i];
1524 bool fIsDup = false;
1525 for (UINT j = 0; j < cChangeIds; ++j)
1526 {
1527 if (pChangeIds[j] == Id)
1528 {
1529 fIsDup = true;
1530 break;
1531 }
1532 }
1533
1534 if (fIsDup)
1535 continue;
1536
1537 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1538
1539 if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
1540 {
1541 pChangeIds[cChangeIds] = Id;
1542 ++cChangeIds;
1543 }
1544 }
1545
1546 if (cChangeIds == 0)
1547 {
1548 Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
1549 winEr = ERROR_SUCCESS;
1550 goto done;
1551 }
1552
1553 /* we want to set primary for every disabled for non-topoly mode only */
1554 winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
1555 if (winEr != ERROR_SUCCESS)
1556 {
1557 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
1558 return winEr;
1559 }
1560
1561 if (fSetTopology)
1562 vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);
1563
1564 for (UINT i = 0; i < cChangeIds; ++i)
1565 {
1566 UINT Id = pChangeIds[i];
1567 /* re-query paths */
1568 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, -1, Id);
1569 if (iPath < 0)
1570 {
1571 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1572 winEr = ERROR_GEN_FAILURE;
1573 goto done;
1574 }
1575
1576 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
1577 if (winEr != ERROR_SUCCESS)
1578 {
1579 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1580 goto done;
1581 }
1582 }
1583
1584 if (!fSetTopology)
1585 vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);
1586
1587#if 0
1588 /* ensure the zero-index (primary) screen is enabled */
1589 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
1590 if (iPath < 0)
1591 {
1592 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1593 winEr = ERROR_GEN_FAILURE;
1594 goto done;
1595 }
1596
1597 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
1598 if (winEr != ERROR_SUCCESS)
1599 {
1600 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1601 goto done;
1602 }
1603#endif
1604
1605 UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
1606 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1607 if (winEr != ERROR_SUCCESS)
1608 {
1609 if (!fSetTopology)
1610 {
1611 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
1612 fSetFlags |= SDC_ALLOW_CHANGES;
1613 }
1614 else
1615 {
1616 Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
1617 goto done;
1618 }
1619 }
1620
1621 if (!fSetTopology)
1622 fSetFlags |= SDC_SAVE_TO_DATABASE;
1623
1624 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
1625 if (winEr != ERROR_SUCCESS)
1626 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));
1627
1628done:
1629 vboxDispIfWddmDcTerm(&DispCfg);
1630
1631 return winEr;
1632}
1633
1634static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
1635{
1636 DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
1637 if (winEr != ERROR_SUCCESS)
1638 {
1639 if (fEnable)
1640 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1641 else
1642 Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1643 winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
1644 if (winEr != ERROR_SUCCESS)
1645 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1646 }
1647
1648 return winEr;
1649}
1650
1651static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes)
1652{
1653 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1654 DWORD winEr;
1655 int iPath;
1656
1657 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1658 if (winEr != ERROR_SUCCESS)
1659 {
1660 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
1661 return winEr;
1662 }
1663
1664 iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);
1665
1666 if (iPath < 0)
1667 {
1668 vboxDispIfWddmDcTerm(&DispCfg);
1669
1670 if (!fEnable)
1671 {
1672 /* nothing to be done here, just leave */
1673 return ERROR_SUCCESS;
1674 }
1675
1676 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1677 if (winEr != ERROR_SUCCESS)
1678 {
1679 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1680 return winEr;
1681 }
1682
1683 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1684 if (winEr != ERROR_SUCCESS)
1685 {
1686 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1687 return winEr;
1688 }
1689
1690 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1691 if (iPath < 0)
1692 {
1693 WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
1694 vboxDispIfWddmDcTerm(&DispCfg);
1695 return ERROR_RETRY;
1696 }
1697 }
1698
1699 Assert(iPath >= 0);
1700
1701 if (!fEnable)
1702 {
1703 /* need to disable it, and we are done */
1704 vboxDispIfWddmDcTerm(&DispCfg);
1705
1706 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1707 if (winEr != ERROR_SUCCESS)
1708 {
1709 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1710 return winEr;
1711 }
1712
1713 return winEr;
1714 }
1715
1716 Assert(fEnable);
1717
1718 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceMode[Id], FALSE, fEnable);
1719 if (winEr != ERROR_SUCCESS)
1720 {
1721 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
1722 vboxDispIfWddmDcTerm(&DispCfg);
1723 return winEr;
1724 }
1725
1726 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
1727 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1728 if (winEr != ERROR_SUCCESS)
1729 {
1730 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1731 fSetFlags |= SDC_ALLOW_CHANGES;
1732 }
1733
1734 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
1735 if (winEr != ERROR_SUCCESS)
1736 {
1737 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1738 }
1739
1740 vboxDispIfWddmDcTerm(&DispCfg);
1741
1742 return winEr;
1743}
1744
1745#endif /* VBOX_WITH_WDDM */
1746
1747DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1748{
1749 switch (pIf->enmMode)
1750 {
1751 case VBOXDISPIF_MODE_XPDM_NT4:
1752 return ERROR_NOT_SUPPORTED;
1753 case VBOXDISPIF_MODE_XPDM:
1754 return ERROR_NOT_SUPPORTED;
1755#ifdef VBOX_WITH_WDDM
1756 case VBOXDISPIF_MODE_WDDM:
1757 case VBOXDISPIF_MODE_WDDM_W7:
1758 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1759#endif
1760 default:
1761 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
1762 return ERROR_INVALID_PARAMETER;
1763 }
1764}
1765
1766DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
1767{
1768 switch (pIf->enmMode)
1769 {
1770 case VBOXDISPIF_MODE_XPDM_NT4:
1771 return NO_ERROR;
1772 case VBOXDISPIF_MODE_XPDM:
1773 return NO_ERROR;
1774#ifdef VBOX_WITH_WDDM
1775 case VBOXDISPIF_MODE_WDDM:
1776 case VBOXDISPIF_MODE_WDDM_W7:
1777 return vboxDispIfCancelPendingResizeWDDM(pIf);
1778#endif
1779 default:
1780 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
1781 return ERROR_INVALID_PARAMETER;
1782 }
1783}
1784
1785static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
1786{
1787 VBOXDISPIFESCAPE EscapeHdr = {0};
1788 EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
1789 EscapeHdr.u32CmdSpecific = 0;
1790
1791 D3DKMT_ESCAPE EscapeData = {0};
1792 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1793#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1794 /* win8.1 does not allow context-based escapes for display-only mode */
1795 EscapeData.hDevice = pOp->Device.hDevice;
1796 EscapeData.hContext = pOp->Context.hContext;
1797#endif
1798 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1799 EscapeData.Flags.HardwareAccess = 1;
1800 EscapeData.pPrivateDriverData = &EscapeHdr;
1801 EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);
1802
1803 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1804 if (NT_SUCCESS(Status))
1805 {
1806 if (pcConnected)
1807 *pcConnected = EscapeHdr.u32CmdSpecific;
1808 return NO_ERROR;
1809 }
1810 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
1811 return Status;
1812}
1813
1814static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
1815{
1816 DWORD NumDevices = VBoxDisplayGetCount();
1817 if (NumDevices == 0)
1818 {
1819 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1820 return ERROR_GEN_FAILURE;
1821 }
1822
1823 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
1824 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
1825 DWORD DevNum = 0;
1826 DWORD DevPrimaryNum = 0;
1827
1828 DWORD winEr = VBoxDisplayGetConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
1829 if (winEr != NO_ERROR)
1830 {
1831 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
1832 return winEr;
1833 }
1834
1835 if (NumDevices != DevNum)
1836 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
1837
1838
1839 uint32_t cConnected = 0;
1840 winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
1841 if (winEr != NO_ERROR)
1842 {
1843 WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
1844 return winEr;
1845 }
1846
1847 if (!cConnected)
1848 {
1849 Log(("VBoxTray: all targets already connected, nothing to do\n"));
1850 return NO_ERROR;
1851 }
1852
1853 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1854 if (winEr != NO_ERROR)
1855 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));
1856
1857 DWORD NewNumDevices = VBoxDisplayGetCount();
1858 if (NewNumDevices == 0)
1859 {
1860 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1861 return ERROR_GEN_FAILURE;
1862 }
1863
1864 if (NewNumDevices != NumDevices)
1865 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));
1866
1867 DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
1868 DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
1869 DWORD NewDevNum = 0;
1870 DWORD NewDevPrimaryNum = 0;
1871
1872 winEr = VBoxDisplayGetConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
1873 if (winEr != NO_ERROR)
1874 {
1875 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
1876 return winEr;
1877 }
1878
1879 if (NewNumDevices != NewDevNum)
1880 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));
1881
1882 DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
1883 UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
1884 UINT cIds = 0;
1885 for (DWORD i = 0; i < minDevNum; ++i)
1886 {
1887 if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
1888 && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1889 {
1890 pIds[cIds] = i;
1891 ++cIds;
1892 }
1893 }
1894
1895 if (!cIds)
1896 {
1897 /* this is something we would not regularly expect */
1898 WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
1899 return NO_ERROR;
1900 }
1901
1902 if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1903 {
1904 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
1905 if (winEr != NO_ERROR)
1906 WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
1907 }
1908 else
1909 {
1910 for (DWORD i = 0; i < cIds; ++i)
1911 {
1912 winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
1913 if (winEr != NO_ERROR)
1914 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
1915 }
1916 }
1917
1918 return winEr;
1919}
1920
1921
1922static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
1923{
1924 VBOXDISPIF_OP Op;
1925
1926 DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
1927 if (winEr != NO_ERROR)
1928 {
1929 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
1930 return winEr;
1931 }
1932
1933 winEr = vboxDispIfResizeStartedWDDMOp(&Op);
1934 if (winEr != NO_ERROR)
1935 {
1936 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
1937 }
1938
1939 vboxDispIfOpEnd(&Op);
1940
1941 return winEr;
1942}
1943
1944DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
1945{
1946 switch (pIf->enmMode)
1947 {
1948 case VBOXDISPIF_MODE_XPDM_NT4:
1949 return NO_ERROR;
1950 case VBOXDISPIF_MODE_XPDM:
1951 return NO_ERROR;
1952#ifdef VBOX_WITH_WDDM
1953 case VBOXDISPIF_MODE_WDDM:
1954 case VBOXDISPIF_MODE_WDDM_W7:
1955 return vboxDispIfResizeStartedWDDM(pIf);
1956#endif
1957 default:
1958 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
1959 return ERROR_INVALID_PARAMETER;
1960 }
1961}
1962
1963static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
1964{
1965 return NO_ERROR;
1966}
1967
1968static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
1969{
1970 DWORD err = NO_ERROR;
1971
1972 OSVERSIONINFO OSinfo;
1973 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
1974 GetVersionEx (&OSinfo);
1975 if (OSinfo.dwMajorVersion >= 5)
1976 {
1977 HMODULE hUser = GetModuleHandle("user32.dll");
1978 if (NULL != hUser)
1979 {
1980 bool bSupported = true;
1981 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
1982 LogFunc(("pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
1983 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
1984
1985 if (!bSupported)
1986 {
1987 WARN_FUNC(("pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
1988 err = ERROR_NOT_SUPPORTED;
1989 }
1990 }
1991 else
1992 {
1993 WARN_FUNC(("failed to get USER32 handle, err (%d)\n", GetLastError()));
1994 err = ERROR_NOT_SUPPORTED;
1995 }
1996 }
1997 else
1998 {
1999 WARN_FUNC(("can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
2000 err = ERROR_NOT_SUPPORTED;
2001 }
2002
2003 return err;
2004}
2005
2006DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
2007{
2008 /* @todo: may need to addd synchronization in case we want to change modes dynamically
2009 * i.e. currently the mode is supposed to be initialized once on service initialization */
2010 if (penmOldMode)
2011 *penmOldMode = pIf->enmMode;
2012
2013 if (enmMode == pIf->enmMode)
2014 return NO_ERROR;
2015
2016#ifdef VBOX_WITH_WDDM
2017 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
2018 {
2019 vboxDispIfWddmTerm(pIf);
2020
2021 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
2022 }
2023#endif
2024
2025 DWORD err = NO_ERROR;
2026 switch (enmMode)
2027 {
2028 case VBOXDISPIF_MODE_XPDM_NT4:
2029 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
2030 err = vboxDispIfSwitchToXPDM_NT4(pIf);
2031 if (err == NO_ERROR)
2032 {
2033 LogFunc(("successfully switched to XPDM_NT4 mode\n"));
2034 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
2035 }
2036 else
2037 WARN_FUNC(("failed to switch to XPDM_NT4 mode, err (%d)\n", err));
2038 break;
2039 case VBOXDISPIF_MODE_XPDM:
2040 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM\n"));
2041 err = vboxDispIfSwitchToXPDM(pIf);
2042 if (err == NO_ERROR)
2043 {
2044 LogFunc(("successfully switched to XPDM mode\n"));
2045 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
2046 }
2047 else
2048 WARN_FUNC(("failed to switch to XPDM mode, err (%d)\n", err));
2049 break;
2050#ifdef VBOX_WITH_WDDM
2051 case VBOXDISPIF_MODE_WDDM:
2052 {
2053 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM\n"));
2054 err = vboxDispIfSwitchToWDDM(pIf);
2055 if (err == NO_ERROR)
2056 {
2057 LogFunc(("successfully switched to WDDM mode\n"));
2058 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
2059 }
2060 else
2061 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2062 break;
2063 }
2064 case VBOXDISPIF_MODE_WDDM_W7:
2065 {
2066 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
2067 err = vboxDispIfSwitchToWDDM_W7(pIf);
2068 if (err == NO_ERROR)
2069 {
2070 LogFunc(("successfully switched to WDDM mode\n"));
2071 pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
2072 }
2073 else
2074 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2075 break;
2076 }
2077#endif
2078 default:
2079 err = ERROR_INVALID_PARAMETER;
2080 break;
2081 }
2082 return err;
2083}
2084
2085static DWORD vboxDispIfSeamlessCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2086{
2087 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
2088 if (SUCCEEDED(hr))
2089 {
2090#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2091 hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
2092 if (SUCCEEDED(hr))
2093 {
2094 hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
2095 0, 0, hEvent, 0ULL);
2096 if (SUCCEEDED(hr))
2097#endif
2098 return ERROR_SUCCESS;
2099#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2100 else
2101 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
2102
2103 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2104 }
2105 else
2106 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
2107
2108 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2109#endif
2110 }
2111
2112 return hr;
2113}
2114
2115static DWORD vboxDispIfSeamlessTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
2116{
2117#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2118 vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
2119 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2120#endif
2121 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2122
2123 return NO_ERROR;
2124}
2125
2126static DWORD vboxDispIfSeamlessSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2127{
2128 D3DKMT_ESCAPE EscapeData = {0};
2129 EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
2130#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2131 EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
2132 EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
2133#endif
2134 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
2135 /*EscapeData.Flags.HardwareAccess = 1;*/
2136 EscapeData.pPrivateDriverData = pData;
2137 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
2138
2139 NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
2140 if (NT_SUCCESS(Status))
2141 return ERROR_SUCCESS;
2142
2143 WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
2144 return Status;
2145}
2146
2147DWORD VBoxDispIfSeamlessCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2148{
2149 memset(pSeamless, 0, sizeof (*pSeamless));
2150 pSeamless->pIf = pIf;
2151
2152 switch (pIf->enmMode)
2153 {
2154 case VBOXDISPIF_MODE_XPDM_NT4:
2155 case VBOXDISPIF_MODE_XPDM:
2156 return NO_ERROR;
2157#ifdef VBOX_WITH_WDDM
2158 case VBOXDISPIF_MODE_WDDM:
2159 case VBOXDISPIF_MODE_WDDM_W7:
2160 return vboxDispIfSeamlessCreateWDDM(pIf, pSeamless, hEvent);
2161#endif
2162 default:
2163 break;
2164 }
2165
2166 WARN(("VBoxTray: VBoxDispIfSeamlessCreate: invalid mode %d\n", pIf->enmMode));
2167 return ERROR_INVALID_PARAMETER;
2168}
2169
2170DWORD VBoxDispIfSeamlessTerm(VBOXDISPIF_SEAMLESS *pSeamless)
2171{
2172 PCVBOXDISPIF const pIf = pSeamless->pIf;
2173 DWORD winEr;
2174 switch (pIf->enmMode)
2175 {
2176 case VBOXDISPIF_MODE_XPDM_NT4:
2177 case VBOXDISPIF_MODE_XPDM:
2178 winEr = NO_ERROR;
2179 break;
2180#ifdef VBOX_WITH_WDDM
2181 case VBOXDISPIF_MODE_WDDM:
2182 case VBOXDISPIF_MODE_WDDM_W7:
2183 winEr = vboxDispIfSeamlessTermWDDM(pSeamless);
2184 break;
2185#endif
2186 default:
2187 WARN(("VBoxTray: VBoxDispIfSeamlessTerm: invalid mode %d\n", pIf->enmMode));
2188 winEr = ERROR_INVALID_PARAMETER;
2189 break;
2190 }
2191
2192 if (winEr == NO_ERROR)
2193 memset(pSeamless, 0, sizeof (*pSeamless));
2194
2195 return winEr;
2196}
2197
2198DWORD VBoxDispIfSeamlessSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2199{
2200 PCVBOXDISPIF const pIf = pSeamless->pIf;
2201
2202 if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
2203 {
2204 WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
2205 return ERROR_INVALID_PARAMETER;
2206 }
2207
2208 switch (pIf->enmMode)
2209 {
2210 case VBOXDISPIF_MODE_XPDM_NT4:
2211 case VBOXDISPIF_MODE_XPDM:
2212 return VBoxDispIfEscape(pIf, pData, cbData);
2213#ifdef VBOX_WITH_WDDM
2214 case VBOXDISPIF_MODE_WDDM:
2215 case VBOXDISPIF_MODE_WDDM_W7:
2216 return vboxDispIfSeamlessSubmitWDDM(pSeamless, pData, cbData);
2217#endif
2218 default:
2219 WARN(("VBoxTray: VBoxDispIfSeamlessSubmit: invalid mode %d\n", pIf->enmMode));
2220 return ERROR_INVALID_PARAMETER;
2221 }
2222}
2223
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