VirtualBox

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

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

added a couple of missing Id headers

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