VirtualBox

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

Last change on this file since 53315 was 53315, checked in by vboxsync, 10 years ago

VBoxTray: keep monitor layout when resizing with WDDM driver, Windows 7 fix.

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