VirtualBox

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

Last change on this file since 86815 was 83842, checked in by vboxsync, 5 years ago

Additions/NT/Graphics: Use RTUtf16Printf rather than swprintf (dependency issues). bugref:8489

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 KB
Line 
1/* $Id: VBoxMPVModes.cpp 83842 2020-04-20 09:24:40Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2014-2020 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#include <iprt/utf16.h>
22
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 wszKeyName[32];
192 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomXRes%d", u32Target);
193 rc = VBoxMPCmnRegSetDword(Registry, wszKeyName, pResolution->cx);
194 VBOXMP_WARN_VPS(rc);
195 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomYRes%d", u32Target);
196 rc = VBoxMPCmnRegSetDword(Registry, wszKeyName, pResolution->cy);
197 VBOXMP_WARN_VPS(rc);
198 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomBPP%d", u32Target);
199 rc = VBoxMPCmnRegSetDword(Registry, wszKeyName, 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 if (!g_VBoxDisplayOnly)
224 {
225 /* at least two surfaces will be needed: primary & shadow */
226 vramSize /= 2;
227 }
228 vramSize &= ~PAGE_OFFSET_MASK;
229
230 /* prevent potensial overflow */
231 if ( pResolution->cx > 0x7fff
232 || pResolution->cy > 0x7fff)
233 {
234 WARN(("resolution %dx%d insane", pResolution->cx, pResolution->cy));
235 return VERR_INVALID_PARAMETER;
236 }
237
238 uint32_t cbSurfMem = pResolution->cx * pResolution->cy * 4;
239 if (cbSurfMem > vramSize)
240 {
241 WARN(("resolution %dx%d too big for available VRAM (%d bytes)\n", pResolution->cx, pResolution->cy, vramSize));
242 return VERR_NOT_SUPPORTED;
243 }
244
245 if (!VBoxLikesVideoMode(u32Target, pResolution->cx, pResolution->cy, 32))
246 {
247 WARN(("resolution %dx%d not accepted by the frontend\n", pResolution->cx, pResolution->cy));
248 return VERR_NOT_SUPPORTED;
249 }
250
251 if (pModes->aTransientResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
252 {
253 if (!fTransient) /* if the mode is not transient anymore, remove it from transient */
254 pModes->aTransientResolutions[u32Target] = 0;
255 return VINF_ALREADY_INITIALIZED;
256 }
257
258 int rc;
259 bool fTransientIfExists = false;
260 if (pModes->aPendingRemoveCurResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
261 {
262 /* no need to remove it anymore */
263 pModes->aPendingRemoveCurResolutions[u32Target] = 0;
264 rc = VINF_ALREADY_INITIALIZED;
265 fTransientIfExists = true;
266 }
267 else
268 {
269 rc = VBoxVModesAdd(&pModes->Modes, u32Target, CR_RSIZE2U64(*pResolution));
270 if (RT_FAILURE(rc))
271 {
272 WARN(("VBoxVModesAdd failed %d", rc));
273 return rc;
274 }
275 }
276
277 if (rc == VINF_ALREADY_INITIALIZED && !fTransientIfExists)
278 return rc;
279
280 if (fTransient)
281 {
282 if (pModes->aTransientResolutions[u32Target])
283 {
284 /* note that we can not overwrite rc here, because it holds the "existed" status, which we need to return */
285 RTRECTSIZE size = CR_U642RSIZE(pModes->aTransientResolutions[u32Target]);
286 int tmpRc = vboxWddmVModesRemove(pExt, pModes, u32Target, &size);
287 if (RT_FAILURE(tmpRc))
288 {
289 WARN(("vboxWddmVModesRemove failed %d, can never happen", tmpRc));
290 return tmpRc;
291 }
292 }
293 Assert(!pModes->aTransientResolutions[u32Target]);
294
295 pModes->aTransientResolutions[u32Target] = CR_RSIZE2U64(*pResolution);
296 vboxWddmVModesSaveTransient(pExt, u32Target, pResolution);
297 }
298
299 return rc;
300}
301
302int voxWddmVModesInitForTarget(PVBOXMP_DEVEXT pExt, VBOXWDDM_VMODES *pModes, uint32_t u32Target)
303{
304 for (uint32_t i = 0; i < RT_ELEMENTS(g_VBoxBuiltinResolutions); ++i)
305 {
306 vboxWddmVModesAdd(pExt, pModes, u32Target, &g_VBoxBuiltinResolutions[i], FALSE);
307 }
308
309 if (pExt->aTargets[u32Target].Size.cx)
310 {
311 vboxWddmVModesAdd(pExt, pModes, u32Target, &pExt->aTargets[u32Target].Size, TRUE);
312 }
313
314 /* Check registry for manually added modes, up to 128 entries is supported
315 * Give up on the first error encountered.
316 */
317 VBOXMPCMNREGISTRY Registry;
318 VP_STATUS vpRc;
319
320 vpRc = VBoxMPCmnRegInit(pExt, &Registry);
321 if (vpRc != NO_ERROR)
322 {
323 WARN(("VBoxMPCmnRegInit failed %d, ignore", vpRc));
324 return VINF_SUCCESS;
325 }
326
327 uint32_t CustomXRes = 0, CustomYRes = 0;
328
329 if (u32Target == 0)
330 {
331 /*First name without a suffix*/
332 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes);
333 VBOXMP_WARN_VPS_NOBP(vpRc);
334 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes);
335 VBOXMP_WARN_VPS_NOBP(vpRc);
336 }
337 else
338 {
339 wchar_t wszKeyName[32];
340 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomXRes%d", u32Target);
341 vpRc = VBoxMPCmnRegQueryDword(Registry, wszKeyName, &CustomXRes);
342 VBOXMP_WARN_VPS_NOBP(vpRc);
343 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomYRes%d", u32Target);
344 vpRc = VBoxMPCmnRegQueryDword(Registry, wszKeyName, &CustomYRes);
345 VBOXMP_WARN_VPS_NOBP(vpRc);
346 }
347
348 LOG(("got stored custom resolution[%d] %dx%dx", u32Target, CustomXRes, CustomYRes));
349
350 if (CustomXRes || CustomYRes)
351 {
352 if (CustomXRes == 0)
353 CustomXRes = pExt->aTargets[u32Target].Size.cx ? pExt->aTargets[u32Target].Size.cx : 800;
354 if (CustomYRes == 0)
355 CustomYRes = pExt->aTargets[u32Target].Size.cy ? pExt->aTargets[u32Target].Size.cy : 600;
356
357 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
358 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, TRUE);
359 }
360
361
362 for (int curKey=0; curKey<128; curKey++)
363 {
364 wchar_t wszKeyName[24];
365
366 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomMode%dWidth", curKey);
367 vpRc = VBoxMPCmnRegQueryDword(Registry, wszKeyName, &CustomXRes);
368 VBOXMP_CHECK_VPS_BREAK(vpRc);
369
370 RTUtf16Printf(wszKeyName, RT_ELEMENTS(wszKeyName), "CustomMode%dHeight", curKey);
371 vpRc = VBoxMPCmnRegQueryDword(Registry, wszKeyName, &CustomYRes);
372 VBOXMP_CHECK_VPS_BREAK(vpRc);
373
374 LOG(("got custom mode[%u]=%ux%u", curKey, CustomXRes, CustomYRes));
375
376 /* round down width to be a multiple of 8 if necessary */
377 if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
378 {
379 CustomXRes &= 0xFFF8;
380 }
381
382 LOG(("adding video mode from registry."));
383
384 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
385
386 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, FALSE);
387 }
388
389 vpRc = VBoxMPCmnRegFini(Registry);
390 VBOXMP_WARN_VPS(vpRc);
391
392 return VINF_SUCCESS;
393}
394
395static VBOXWDDM_VMODES g_VBoxWddmVModes;
396
397void VBoxWddmVModesCleanup()
398{
399 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
400 vboxWddmVModesCleanup(pModes);
401}
402
403int VBoxWddmVModesInit(PVBOXMP_DEVEXT pExt)
404{
405 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
406
407 vboxWddmVModesInit(pModes, VBoxCommonFromDeviceExt(pExt)->cDisplays);
408
409 int rc;
410
411 for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i)
412 {
413 rc = voxWddmVModesInitForTarget(pExt, pModes, (uint32_t)i);
414 if (RT_FAILURE(rc))
415 {
416 WARN(("voxWddmVModesInitForTarget failed %d", rc));
417 return rc;
418 }
419 }
420
421 return VINF_SUCCESS;
422}
423
424const CR_SORTARRAY* VBoxWddmVModesGet(PVBOXMP_DEVEXT pExt, uint32_t u32Target)
425{
426 if (u32Target >= (uint32_t)VBoxCommonFromDeviceExt(pExt)->cDisplays)
427 {
428 WARN(("invalid target"));
429 return NULL;
430 }
431
432 return &g_VBoxWddmVModes.Modes.aTargets[u32Target];
433}
434
435int VBoxWddmVModesRemove(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution)
436{
437 return vboxWddmVModesRemove(pExt, &g_VBoxWddmVModes, u32Target, pResolution);
438}
439
440int VBoxWddmVModesAdd(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution, BOOLEAN fTrancient)
441{
442 return vboxWddmVModesAdd(pExt, &g_VBoxWddmVModes, u32Target, pResolution, fTrancient);
443}
444
445
446static NTSTATUS vboxWddmChildStatusReportPerform(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_CHILD_STATUS pChildStatus, D3DDDI_VIDEO_PRESENT_TARGET_ID iChild)
447{
448 DXGK_CHILD_STATUS DdiChildStatus;
449
450 Assert(iChild < UINT32_MAX/2);
451 Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
452
453 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[iChild];
454
455 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_DISCONNECTED)
456 && pTarget->fConnected)
457 {
458 /* report disconnected */
459 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
460 DdiChildStatus.Type = StatusConnection;
461 DdiChildStatus.ChildUid = iChild;
462 DdiChildStatus.HotPlug.Connected = FALSE;
463
464 LOG(("Reporting DISCONNECT to child %d", DdiChildStatus.ChildUid));
465
466 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
467 if (!NT_SUCCESS(Status))
468 {
469 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
470 return Status;
471 }
472 pTarget->fConnected = FALSE;
473 }
474
475 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_CONNECTED)
476 && !pTarget->fConnected)
477 {
478 /* report disconnected */
479 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
480 DdiChildStatus.Type = StatusConnection;
481 DdiChildStatus.ChildUid = iChild;
482 DdiChildStatus.HotPlug.Connected = TRUE;
483
484 LOG(("Reporting CONNECT to child %d", DdiChildStatus.ChildUid));
485
486 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
487 if (!NT_SUCCESS(Status))
488 {
489 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
490 return Status;
491 }
492 pTarget->fConnected = TRUE;
493 }
494
495 if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_ROTATED)
496 {
497 /* report disconnected */
498 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
499 DdiChildStatus.Type = StatusRotation;
500 DdiChildStatus.ChildUid = iChild;
501 DdiChildStatus.Rotation.Angle = pChildStatus->u8RotationAngle;
502
503 LOG(("Reporting ROTATED to child %d", DdiChildStatus.ChildUid));
504
505 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
506 if (!NT_SUCCESS(Status))
507 {
508 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
509 return Status;
510 }
511 }
512
513 return STATUS_SUCCESS;
514}
515
516static NTSTATUS vboxWddmChildStatusHandleRequest(PVBOXMP_DEVEXT pDevExt, VBOXVDMACMD_CHILD_STATUS_IRQ *pBody)
517{
518 NTSTATUS Status = STATUS_SUCCESS;
519
520 for (UINT i = 0; i < pBody->cInfos; ++i)
521 {
522 PVBOXVDMA_CHILD_STATUS pInfo = &pBody->aInfos[i];
523 if (pBody->fFlags & VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL)
524 {
525 for (D3DDDI_VIDEO_PRESENT_TARGET_ID iChild = 0; iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++iChild)
526 {
527 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, iChild);
528 if (!NT_SUCCESS(Status))
529 {
530 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
531 break;
532 }
533 }
534 }
535 else
536 {
537 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, pInfo->iChild);
538 if (!NT_SUCCESS(Status))
539 {
540 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
541 break;
542 }
543 }
544 }
545
546 return Status;
547}
548
549NTSTATUS VBoxWddmChildStatusReportReconnected(PVBOXMP_DEVEXT pDevExt, uint32_t iChild)
550{
551 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
552 Body.cInfos = 1;
553 if (iChild == D3DDDI_ID_ALL)
554 {
555 Body.fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL;
556 }
557 Body.aInfos[0].iChild = iChild;
558 Body.aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED;
559 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
560 return vboxWddmChildStatusHandleRequest(pDevExt, &Body);
561}
562
563NTSTATUS VBoxWddmChildStatusConnect(PVBOXMP_DEVEXT pDevExt, uint32_t iChild, BOOLEAN fConnect)
564{
565 Assert(iChild < (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
566 NTSTATUS Status = STATUS_SUCCESS;
567 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
568 Body.cInfos = 1;
569 Body.aInfos[0].iChild = iChild;
570 Body.aInfos[0].fFlags = fConnect ? VBOXVDMA_CHILD_STATUS_F_CONNECTED : VBOXVDMA_CHILD_STATUS_F_DISCONNECTED;
571 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
572 Status = vboxWddmChildStatusHandleRequest(pDevExt, &Body);
573 if (!NT_SUCCESS(Status))
574 WARN(("vboxWddmChildStatusHandleRequest failed Status 0x%x", Status));
575
576 return Status;
577}
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