VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVModes.cpp@ 69496

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

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: VBoxMPVModes.cpp 69496 2017-10-28 14:55:58Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2014-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPWddm.h"
19#include "common/VBoxMPCommon.h"
20#include <iprt/param.h> /* PAGE_OFFSET_MASK */
21
22#include <stdio.h> /* for swprintf */
23
24
25int VBoxVModesInit(VBOX_VMODES *pModes, uint32_t cTargets)
26{
27 if (cTargets >= VBOX_VIDEO_MAX_SCREENS)
28 {
29 WARN(("invalid target"));
30 return VERR_INVALID_PARAMETER;
31 }
32
33 pModes->cTargets = cTargets;
34 for (uint32_t i = 0; i < cTargets; ++i)
35 {
36 int rc = CrSaInit(&pModes->aTargets[i], 16);
37 if (RT_FAILURE(rc))
38 {
39 WARN(("CrSaInit failed"));
40
41 for (uint32_t j = 0; j < i; ++j)
42 {
43 CrSaCleanup(&pModes->aTargets[j]);
44 }
45 return rc;
46 }
47 }
48
49 return VINF_SUCCESS;
50}
51
52void VBoxVModesCleanup(VBOX_VMODES *pModes)
53{
54 for (uint32_t i = 0; i < pModes->cTargets; ++i)
55 {
56 CrSaCleanup(&pModes->aTargets[i]);
57 }
58}
59
60int VBoxVModesAdd(VBOX_VMODES *pModes, uint32_t u32Target, uint64_t u64)
61{
62 if (u32Target >= pModes->cTargets)
63 {
64 WARN(("invalid target id"));
65 return VERR_INVALID_PARAMETER;
66 }
67
68 return CrSaAdd(&pModes->aTargets[u32Target], u64);
69}
70
71int VBoxVModesRemove(VBOX_VMODES *pModes, uint32_t u32Target, uint64_t u64)
72{
73 if (u32Target >= pModes->cTargets)
74 {
75 WARN(("invalid target id"));
76 return VERR_INVALID_PARAMETER;
77 }
78
79 return CrSaRemove(&pModes->aTargets[u32Target], u64);
80}
81
82static void vboxWddmVModesInit(VBOXWDDM_VMODES *pModes, uint32_t cTargets)
83{
84 VBoxVModesInit(&pModes->Modes, cTargets);
85 memset(pModes->aTransientResolutions, 0, cTargets * sizeof (pModes->aTransientResolutions[0]));
86 memset(pModes->aPendingRemoveCurResolutions, 0, cTargets * sizeof (pModes->aPendingRemoveCurResolutions[0]));
87}
88
89static void vboxWddmVModesCleanup(VBOXWDDM_VMODES *pModes)
90{
91 VBoxVModesCleanup(&pModes->Modes);
92 memset(pModes->aTransientResolutions, 0, sizeof (pModes->aTransientResolutions));
93 memset(pModes->aPendingRemoveCurResolutions, 0, sizeof (pModes->aPendingRemoveCurResolutions));
94}
95
96/*
97static void vboxWddmVModesClone(const VBOXWDDM_VMODES *pModes, VBOXWDDM_VMODES *pDst)
98{
99 VBoxVModesClone(&pModes->Modes, pDst->Modes);
100 memcpy(pDst->aTransientResolutions, pModes->aTransientResolutions, pModes->Modes.cTargets * sizeof (pModes->aTransientResolutions[0]));
101 memcpy(pDst->aPendingRemoveCurResolutions, pModes->aPendingRemoveCurResolutions, pModes->Modes.cTargets * sizeof (pModes->aPendingRemoveCurResolutions[0]));
102}
103*/
104
105static const RTRECTSIZE g_VBoxBuiltinResolutions[] =
106{
107 /* standard modes */
108 { 640, 480 },
109 { 800, 600 },
110 { 1024, 768 },
111 { 1152, 864 },
112 { 1280, 960 },
113 { 1280, 1024 },
114 { 1400, 1050 },
115 { 1600, 1200 },
116 { 1920, 1440 },
117};
118
119DECLINLINE(bool) vboxVModesRMatch(const RTRECTSIZE *pResolution1, const RTRECTSIZE *pResolution2)
120{
121 return !memcmp(pResolution1, pResolution2, sizeof (*pResolution1));
122}
123
124int vboxWddmVModesRemove(PVBOXMP_DEVEXT pExt, VBOXWDDM_VMODES *pModes, uint32_t u32Target, const RTRECTSIZE *pResolution)
125{
126 if (!pResolution->cx || !pResolution->cy)
127 {
128 WARN(("invalid resolution data"));
129 return VERR_INVALID_PARAMETER;
130 }
131
132 if (u32Target >= pModes->Modes.cTargets)
133 {
134 WARN(("invalid target id"));
135 return VERR_INVALID_PARAMETER;
136 }
137
138 if (CR_RSIZE2U64(*pResolution) == pModes->aTransientResolutions[u32Target])
139 pModes->aTransientResolutions[u32Target] = 0;
140
141 if (vboxVModesRMatch(pResolution, &pExt->aTargets[u32Target].Size))
142 {
143 if (CR_RSIZE2U64(*pResolution) == pModes->aPendingRemoveCurResolutions[u32Target])
144 return VINF_ALREADY_INITIALIZED;
145
146 if (pModes->aPendingRemoveCurResolutions[u32Target])
147 {
148 VBoxVModesRemove(&pModes->Modes, u32Target, pModes->aPendingRemoveCurResolutions[u32Target]);
149 pModes->aPendingRemoveCurResolutions[u32Target] = 0;
150 }
151
152 pModes->aPendingRemoveCurResolutions[u32Target] = CR_RSIZE2U64(*pResolution);
153 return VINF_ALREADY_INITIALIZED;
154 }
155 else if (CR_RSIZE2U64(*pResolution) == pModes->aPendingRemoveCurResolutions[u32Target])
156 pModes->aPendingRemoveCurResolutions[u32Target] = 0;
157
158 int rc = VBoxVModesRemove(&pModes->Modes, u32Target, CR_RSIZE2U64(*pResolution));
159 if (RT_FAILURE(rc))
160 {
161 WARN(("VBoxVModesRemove failed %d, can never happen", rc));
162 return rc;
163 }
164
165 if (rc == VINF_ALREADY_INITIALIZED)
166 return rc;
167
168 return VINF_SUCCESS;
169}
170
171static void vboxWddmVModesSaveTransient(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution)
172{
173 VBOXMPCMNREGISTRY Registry;
174 VP_STATUS rc;
175
176 rc = VBoxMPCmnRegInit(pExt, &Registry);
177 VBOXMP_WARN_VPS(rc);
178
179 if (u32Target==0)
180 {
181 /*First name without a suffix*/
182 rc = VBoxMPCmnRegSetDword(Registry, L"CustomXRes", pResolution->cx);
183 VBOXMP_WARN_VPS(rc);
184 rc = VBoxMPCmnRegSetDword(Registry, L"CustomYRes", pResolution->cy);
185 VBOXMP_WARN_VPS(rc);
186 rc = VBoxMPCmnRegSetDword(Registry, L"CustomBPP", 32); /* <- just in case for older driver usage */
187 VBOXMP_WARN_VPS(rc);
188 }
189 else
190 {
191 wchar_t keyname[32];
192 swprintf(keyname, L"CustomXRes%d", u32Target);
193 rc = VBoxMPCmnRegSetDword(Registry, keyname, pResolution->cx);
194 VBOXMP_WARN_VPS(rc);
195 swprintf(keyname, L"CustomYRes%d", u32Target);
196 rc = VBoxMPCmnRegSetDword(Registry, keyname, pResolution->cy);
197 VBOXMP_WARN_VPS(rc);
198 swprintf(keyname, L"CustomBPP%d", u32Target);
199 rc = VBoxMPCmnRegSetDword(Registry, keyname, 32); /* <- just in case for older driver usage */
200 VBOXMP_WARN_VPS(rc);
201 }
202
203 rc = VBoxMPCmnRegFini(Registry);
204 VBOXMP_WARN_VPS(rc);
205}
206
207int vboxWddmVModesAdd(PVBOXMP_DEVEXT pExt, VBOXWDDM_VMODES *pModes, uint32_t u32Target, const RTRECTSIZE *pResolution, BOOLEAN fTransient)
208{
209 if (!pResolution->cx || !pResolution->cy)
210 {
211 WARN(("invalid resolution data"));
212 return VERR_INVALID_PARAMETER;
213 }
214
215 if (u32Target >= pModes->Modes.cTargets)
216 {
217 WARN(("invalid target id"));
218 return VERR_INVALID_PARAMETER;
219 }
220
221 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt);
222 vramSize /= pExt->u.primary.commonInfo.cDisplays;
223# ifdef VBOX_WDDM_WIN8
224 if (!g_VBoxDisplayOnly)
225# endif
226 {
227 /* at least two surfaces will be needed: primary & shadow */
228 vramSize /= 2;
229 }
230 vramSize &= ~PAGE_OFFSET_MASK;
231
232 /* prevent potensial overflow */
233 if ( pResolution->cx > 0x7fff
234 || pResolution->cy > 0x7fff)
235 {
236 WARN(("resolution %dx%d insane", pResolution->cx, pResolution->cy));
237 return VERR_INVALID_PARAMETER;
238 }
239
240 uint32_t cbSurfMem = pResolution->cx * pResolution->cy * 4;
241 if (cbSurfMem > vramSize)
242 {
243 WARN(("resolution %dx%d too big for available VRAM (%d bytes)\n", pResolution->cx, pResolution->cy, vramSize));
244 return VERR_NOT_SUPPORTED;
245 }
246
247 if (!VBoxLikesVideoMode(u32Target, pResolution->cx, pResolution->cy, 32))
248 {
249 WARN(("resolution %dx%d not accepted by the frontend\n", pResolution->cx, pResolution->cy));
250 return VERR_NOT_SUPPORTED;
251 }
252
253 if (pModes->aTransientResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
254 {
255 if (!fTransient) /* if the mode is not transient anymore, remove it from transient */
256 pModes->aTransientResolutions[u32Target] = 0;
257 return VINF_ALREADY_INITIALIZED;
258 }
259
260 int rc;
261 bool fTransientIfExists = false;
262 if (pModes->aPendingRemoveCurResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
263 {
264 /* no need to remove it anymore */
265 pModes->aPendingRemoveCurResolutions[u32Target] = 0;
266 rc = VINF_ALREADY_INITIALIZED;
267 fTransientIfExists = true;
268 }
269 else
270 {
271 rc = VBoxVModesAdd(&pModes->Modes, u32Target, CR_RSIZE2U64(*pResolution));
272 if (RT_FAILURE(rc))
273 {
274 WARN(("VBoxVModesAdd failed %d", rc));
275 return rc;
276 }
277 }
278
279 if (rc == VINF_ALREADY_INITIALIZED && !fTransientIfExists)
280 return rc;
281
282 if (fTransient)
283 {
284 if (pModes->aTransientResolutions[u32Target])
285 {
286 /* note that we can not overwrite rc here, because it holds the "existed" status, which we need to return */
287 RTRECTSIZE size = CR_U642RSIZE(pModes->aTransientResolutions[u32Target]);
288 int tmpRc = vboxWddmVModesRemove(pExt, pModes, u32Target, &size);
289 if (RT_FAILURE(tmpRc))
290 {
291 WARN(("vboxWddmVModesRemove failed %d, can never happen", tmpRc));
292 return tmpRc;
293 }
294 }
295 Assert(!pModes->aTransientResolutions[u32Target]);
296
297 pModes->aTransientResolutions[u32Target] = CR_RSIZE2U64(*pResolution);
298 vboxWddmVModesSaveTransient(pExt, u32Target, pResolution);
299 }
300
301 return rc;
302}
303
304int voxWddmVModesInitForTarget(PVBOXMP_DEVEXT pExt, VBOXWDDM_VMODES *pModes, uint32_t u32Target)
305{
306 for (uint32_t i = 0; i < RT_ELEMENTS(g_VBoxBuiltinResolutions); ++i)
307 {
308 vboxWddmVModesAdd(pExt, pModes, u32Target, &g_VBoxBuiltinResolutions[i], FALSE);
309 }
310
311 if (pExt->aTargets[u32Target].Size.cx)
312 {
313 vboxWddmVModesAdd(pExt, pModes, u32Target, &pExt->aTargets[u32Target].Size, TRUE);
314 }
315
316 /* Check registry for manually added modes, up to 128 entries is supported
317 * Give up on the first error encountered.
318 */
319 VBOXMPCMNREGISTRY Registry;
320 VP_STATUS vpRc;
321
322 vpRc = VBoxMPCmnRegInit(pExt, &Registry);
323 if (vpRc != NO_ERROR)
324 {
325 WARN(("VBoxMPCmnRegInit failed %d, ignore", vpRc));
326 return VINF_SUCCESS;
327 }
328
329 uint32_t CustomXRes = 0, CustomYRes = 0;
330
331 if (u32Target == 0)
332 {
333 /*First name without a suffix*/
334 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes);
335 VBOXMP_WARN_VPS_NOBP(vpRc);
336 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes);
337 VBOXMP_WARN_VPS_NOBP(vpRc);
338 }
339 else
340 {
341 wchar_t keyname[32];
342 swprintf(keyname, L"CustomXRes%d", u32Target);
343 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
344 VBOXMP_WARN_VPS_NOBP(vpRc);
345 swprintf(keyname, L"CustomYRes%d", u32Target);
346 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
347 VBOXMP_WARN_VPS_NOBP(vpRc);
348 }
349
350 LOG(("got stored custom resolution[%d] %dx%dx", u32Target, CustomXRes, CustomYRes));
351
352 if (CustomXRes || CustomYRes)
353 {
354 if (CustomXRes == 0)
355 CustomXRes = pExt->aTargets[u32Target].Size.cx ? pExt->aTargets[u32Target].Size.cx : 800;
356 if (CustomYRes == 0)
357 CustomYRes = pExt->aTargets[u32Target].Size.cy ? pExt->aTargets[u32Target].Size.cy : 600;
358
359 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
360 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, TRUE);
361 }
362
363
364 for (int curKey=0; curKey<128; curKey++)
365 {
366 wchar_t keyname[24];
367
368 swprintf(keyname, L"CustomMode%dWidth", curKey);
369 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
370 VBOXMP_CHECK_VPS_BREAK(vpRc);
371
372 swprintf(keyname, L"CustomMode%dHeight", curKey);
373 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
374 VBOXMP_CHECK_VPS_BREAK(vpRc);
375
376 LOG(("got custom mode[%u]=%ux%u", curKey, CustomXRes, CustomYRes));
377
378 /* round down width to be a multiple of 8 if necessary */
379 if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
380 {
381 CustomXRes &= 0xFFF8;
382 }
383
384 LOG(("adding video mode from registry."));
385
386 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
387
388 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, FALSE);
389 }
390
391 vpRc = VBoxMPCmnRegFini(Registry);
392 VBOXMP_WARN_VPS(vpRc);
393
394 return VINF_SUCCESS;
395}
396
397static VBOXWDDM_VMODES g_VBoxWddmVModes;
398
399void VBoxWddmVModesCleanup()
400{
401 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
402 vboxWddmVModesCleanup(pModes);
403}
404
405int VBoxWddmVModesInit(PVBOXMP_DEVEXT pExt)
406{
407 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
408
409 vboxWddmVModesInit(pModes, VBoxCommonFromDeviceExt(pExt)->cDisplays);
410
411 int rc;
412
413 for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i)
414 {
415 rc = voxWddmVModesInitForTarget(pExt, pModes, (uint32_t)i);
416 if (RT_FAILURE(rc))
417 {
418 WARN(("voxWddmVModesInitForTarget failed %d", rc));
419 return rc;
420 }
421 }
422
423 return VINF_SUCCESS;
424}
425
426const CR_SORTARRAY* VBoxWddmVModesGet(PVBOXMP_DEVEXT pExt, uint32_t u32Target)
427{
428 if (u32Target >= (uint32_t)VBoxCommonFromDeviceExt(pExt)->cDisplays)
429 {
430 WARN(("invalid target"));
431 return NULL;
432 }
433
434 return &g_VBoxWddmVModes.Modes.aTargets[u32Target];
435}
436
437int VBoxWddmVModesRemove(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution)
438{
439 return vboxWddmVModesRemove(pExt, &g_VBoxWddmVModes, u32Target, pResolution);
440}
441
442int VBoxWddmVModesAdd(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution, BOOLEAN fTrancient)
443{
444 return vboxWddmVModesAdd(pExt, &g_VBoxWddmVModes, u32Target, pResolution, fTrancient);
445}
446
447
448static NTSTATUS vboxWddmChildStatusReportPerform(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_CHILD_STATUS pChildStatus, D3DDDI_VIDEO_PRESENT_TARGET_ID iChild)
449{
450 DXGK_CHILD_STATUS DdiChildStatus;
451
452 Assert(iChild < UINT32_MAX/2);
453 Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
454
455 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[iChild];
456
457 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_DISCONNECTED)
458 && pTarget->fConnected)
459 {
460 /* report disconnected */
461 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
462 DdiChildStatus.Type = StatusConnection;
463 DdiChildStatus.ChildUid = iChild;
464 DdiChildStatus.HotPlug.Connected = FALSE;
465
466 LOG(("Reporting DISCONNECT to child %d", DdiChildStatus.ChildUid));
467
468 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
469 if (!NT_SUCCESS(Status))
470 {
471 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
472 return Status;
473 }
474 pTarget->fConnected = FALSE;
475 }
476
477 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_CONNECTED)
478 && !pTarget->fConnected)
479 {
480 /* report disconnected */
481 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
482 DdiChildStatus.Type = StatusConnection;
483 DdiChildStatus.ChildUid = iChild;
484 DdiChildStatus.HotPlug.Connected = TRUE;
485
486 LOG(("Reporting CONNECT to child %d", DdiChildStatus.ChildUid));
487
488 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
489 if (!NT_SUCCESS(Status))
490 {
491 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
492 return Status;
493 }
494 pTarget->fConnected = TRUE;
495 }
496
497 if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_ROTATED)
498 {
499 /* report disconnected */
500 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
501 DdiChildStatus.Type = StatusRotation;
502 DdiChildStatus.ChildUid = iChild;
503 DdiChildStatus.Rotation.Angle = pChildStatus->u8RotationAngle;
504
505 LOG(("Reporting ROTATED to child %d", DdiChildStatus.ChildUid));
506
507 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
508 if (!NT_SUCCESS(Status))
509 {
510 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
511 return Status;
512 }
513 }
514
515 return STATUS_SUCCESS;
516}
517
518static NTSTATUS vboxWddmChildStatusHandleRequest(PVBOXMP_DEVEXT pDevExt, VBOXVDMACMD_CHILD_STATUS_IRQ *pBody)
519{
520 NTSTATUS Status = STATUS_SUCCESS;
521
522 for (UINT i = 0; i < pBody->cInfos; ++i)
523 {
524 PVBOXVDMA_CHILD_STATUS pInfo = &pBody->aInfos[i];
525 if (pBody->fFlags & VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL)
526 {
527 for (D3DDDI_VIDEO_PRESENT_TARGET_ID iChild = 0; iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++iChild)
528 {
529 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, iChild);
530 if (!NT_SUCCESS(Status))
531 {
532 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
533 break;
534 }
535 }
536 }
537 else
538 {
539 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, pInfo->iChild);
540 if (!NT_SUCCESS(Status))
541 {
542 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
543 break;
544 }
545 }
546 }
547
548 return Status;
549}
550
551#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
552typedef struct VBOXWDDMCHILDSTATUSCB
553{
554 PVBOXVDMACBUF_DR pDr;
555 PKEVENT pEvent;
556} VBOXWDDMCHILDSTATUSCB, *PVBOXWDDMCHILDSTATUSCB;
557
558static DECLCALLBACK(VOID) vboxWddmChildStatusReportCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
559{
560 /* we should be called from our DPC routine */
561 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
562
563 PVBOXWDDMCHILDSTATUSCB pCtx = (PVBOXWDDMCHILDSTATUSCB)pvContext;
564 PVBOXVDMACBUF_DR pDr = pCtx->pDr;
565 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
566 VBOXVDMACMD_CHILD_STATUS_IRQ *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ);
567
568 vboxWddmChildStatusHandleRequest(pDevExt, pBody);
569
570 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
571
572 if (pCtx->pEvent)
573 {
574 KeSetEvent(pCtx->pEvent, 0, FALSE);
575 }
576}
577#endif
578
579NTSTATUS VBoxWddmChildStatusReportReconnected(PVBOXMP_DEVEXT pDevExt, uint32_t iChild)
580{
581#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
582 NTSTATUS Status = STATUS_UNSUCCESSFUL;
583 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof (VBOXVDMACMD_CHILD_STATUS_IRQ));
584
585 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd);
586 if (pDr)
587 {
588 // vboxVdmaCBufDrCreate zero initializes the pDr
589 /* the command data follows the descriptor */
590 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
591 pDr->cbBuf = cbCmd;
592 pDr->rc = VERR_NOT_IMPLEMENTED;
593
594 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
595 pHdr->enmType = VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ;
596 pHdr->u32CmdSpecific = 0;
597 PVBOXVDMACMD_CHILD_STATUS_IRQ pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ);
598 pBody->cInfos = 1;
599 if (iChild == D3DDDI_ID_ALL)
600 {
601 pBody->fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL;
602 }
603 pBody->aInfos[0].iChild = iChild;
604 pBody->aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED;
605 /* we're going to KeWaitForSingleObject */
606 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
607
608 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
609 VBOXWDDMCHILDSTATUSCB Ctx;
610 KEVENT Event;
611 KeInitializeEvent(&Event, NotificationEvent, FALSE);
612 Ctx.pDr = pDr;
613 Ctx.pEvent = &Event;
614 vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxWddmChildStatusReportCompletion, &Ctx);
615 /* mark command as submitted & invisible for the dx runtime since dx did not originate it */
616 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
617 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
618 Assert(rc == VINF_SUCCESS);
619 if (RT_SUCCESS(rc))
620 {
621 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
622 AssertNtStatusSuccess(Status);
623 return STATUS_SUCCESS;
624 }
625
626 Status = STATUS_UNSUCCESSFUL;
627
628 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
629 }
630 else
631 {
632 /** @todo try flushing.. */
633 WARN(("vboxVdmaCBufDrCreate returned NULL"));
634 Status = STATUS_INSUFFICIENT_RESOURCES;
635 }
636
637 return Status;
638#else
639 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
640 Body.cInfos = 1;
641 if (iChild == D3DDDI_ID_ALL)
642 {
643 Body.fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL;
644 }
645 Body.aInfos[0].iChild = iChild;
646 Body.aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED;
647 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
648 return vboxWddmChildStatusHandleRequest(pDevExt, &Body);
649#endif
650}
651
652NTSTATUS VBoxWddmChildStatusConnect(PVBOXMP_DEVEXT pDevExt, uint32_t iChild, BOOLEAN fConnect)
653{
654#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
655# error "port me!"
656#else
657 Assert(iChild < (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
658 NTSTATUS Status = STATUS_SUCCESS;
659 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
660 Body.cInfos = 1;
661 Body.aInfos[0].iChild = iChild;
662 Body.aInfos[0].fFlags = fConnect ? VBOXVDMA_CHILD_STATUS_F_CONNECTED : VBOXVDMA_CHILD_STATUS_F_DISCONNECTED;
663 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
664 Status = vboxWddmChildStatusHandleRequest(pDevExt, &Body);
665 if (!NT_SUCCESS(Status))
666 WARN(("vboxWddmChildStatusHandleRequest failed Status 0x%x", Status));
667
668 return Status;
669#endif
670}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette