VirtualBox

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

Last change on this file since 98329 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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