VirtualBox

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

Last change on this file since 48789 was 48732, checked in by vboxsync, 11 years ago

fix seamless for wddm display only case

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