VirtualBox

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

Last change on this file since 51556 was 51469, checked in by vboxsync, 11 years ago

VBoxTray: Logging; ripped out all custom logging.

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