VirtualBox

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

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

bugref:8250: fix

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