VirtualBox

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

Last change on this file since 79506 was 78937, checked in by vboxsync, 6 years ago

VBoxTray: Use RTSystemGetNtVersion() rather than GetVersion or GetVersionEx for determining the actual windows version. Some cleanups.

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