VirtualBox

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

Last change on this file since 71086 was 71086, checked in by vboxsync, 7 years ago

WDDM/VBoxTray: bugref:8444: Fixed compilation error caused by typo

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