VirtualBox

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

Last change on this file since 62522 was 62522, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1/* $Id: VBoxMPVModes.cpp 62522 2016-07-22 19:17:25Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2014-2016 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMPWddm.h"
20#include "common/VBoxMPCommon.h"
21
22#include <stdio.h>
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(("too big resolution"));
237 return VERR_INVALID_PARAMETER;
238 }
239 uint32_t cbSurfMem = pResolution->cx * pResolution->cy * 4;
240 if (cbSurfMem > vramSize)
241 return VERR_NOT_SUPPORTED;
242
243 if (!VBoxLikesVideoMode(u32Target, pResolution->cx, pResolution->cy, 32))
244 return VERR_NOT_SUPPORTED;
245
246 if (pModes->aTransientResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
247 {
248 if (!fTransient) /* if the mode is not transient anymore, remove it from transient */
249 pModes->aTransientResolutions[u32Target] = 0;
250 return VINF_ALREADY_INITIALIZED;
251 }
252
253 int rc;
254 bool fTransientIfExists = false;
255 if (pModes->aPendingRemoveCurResolutions[u32Target] == CR_RSIZE2U64(*pResolution))
256 {
257 /* no need to remove it anymore */
258 pModes->aPendingRemoveCurResolutions[u32Target] = 0;
259 rc = VINF_ALREADY_INITIALIZED;
260 fTransientIfExists = true;
261 }
262 else
263 {
264 rc = VBoxVModesAdd(&pModes->Modes, u32Target, CR_RSIZE2U64(*pResolution));
265 if (RT_FAILURE(rc))
266 {
267 WARN(("VBoxVModesAdd failed %d", rc));
268 return rc;
269 }
270 }
271
272 if (rc == VINF_ALREADY_INITIALIZED && !fTransientIfExists)
273 return rc;
274
275 if (fTransient)
276 {
277 if (pModes->aTransientResolutions[u32Target])
278 {
279 /* note that we can not overwrite rc here, because it holds the "existed" status, which we need to return */
280 RTRECTSIZE size = CR_U642RSIZE(pModes->aTransientResolutions[u32Target]);
281 int tmpRc = vboxWddmVModesRemove(pExt, pModes, u32Target, &size);
282 if (RT_FAILURE(tmpRc))
283 {
284 WARN(("vboxWddmVModesRemove failed %d, can never happen", tmpRc));
285 return tmpRc;
286 }
287 }
288 Assert(!pModes->aTransientResolutions[u32Target]);
289
290 pModes->aTransientResolutions[u32Target] = CR_RSIZE2U64(*pResolution);
291 vboxWddmVModesSaveTransient(pExt, u32Target, pResolution);
292 }
293
294 return rc;
295}
296
297int voxWddmVModesInitForTarget(PVBOXMP_DEVEXT pExt, VBOXWDDM_VMODES *pModes, uint32_t u32Target)
298{
299 for (uint32_t i = 0; i < RT_ELEMENTS(g_VBoxBuiltinResolutions); ++i)
300 {
301 vboxWddmVModesAdd(pExt, pModes, u32Target, &g_VBoxBuiltinResolutions[i], FALSE);
302 }
303
304 if (pExt->aTargets[u32Target].Size.cx)
305 {
306 vboxWddmVModesAdd(pExt, pModes, u32Target, &pExt->aTargets[u32Target].Size, TRUE);
307 }
308
309 /* Check registry for manually added modes, up to 128 entries is supported
310 * Give up on the first error encountered.
311 */
312 VBOXMPCMNREGISTRY Registry;
313 int fPrefSet=0;
314 VP_STATUS vpRc;
315
316 vpRc = VBoxMPCmnRegInit(pExt, &Registry);
317 if (vpRc != NO_ERROR)
318 {
319 WARN(("VBoxMPCmnRegInit failed %d, ignore", vpRc));
320 return VINF_SUCCESS;
321 }
322
323 uint32_t CustomXRes = 0, CustomYRes = 0;
324
325 if (u32Target == 0)
326 {
327 /*First name without a suffix*/
328 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes);
329 VBOXMP_WARN_VPS_NOBP(vpRc);
330 vpRc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes);
331 VBOXMP_WARN_VPS_NOBP(vpRc);
332 }
333 else
334 {
335 wchar_t keyname[32];
336 swprintf(keyname, L"CustomXRes%d", u32Target);
337 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
338 VBOXMP_WARN_VPS_NOBP(vpRc);
339 swprintf(keyname, L"CustomYRes%d", u32Target);
340 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
341 VBOXMP_WARN_VPS_NOBP(vpRc);
342 }
343
344 LOG(("got stored custom resolution[%d] %dx%dx", u32Target, CustomXRes, CustomYRes));
345
346 if (CustomXRes || CustomYRes)
347 {
348 if (CustomXRes == 0)
349 CustomXRes = pExt->aTargets[u32Target].Size.cx ? pExt->aTargets[u32Target].Size.cx : 800;
350 if (CustomYRes == 0)
351 CustomYRes = pExt->aTargets[u32Target].Size.cy ? pExt->aTargets[u32Target].Size.cy : 600;
352
353 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
354 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, TRUE);
355 }
356
357
358 for (int curKey=0; curKey<128; curKey++)
359 {
360 wchar_t keyname[24];
361
362 swprintf(keyname, L"CustomMode%dWidth", curKey);
363 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
364 VBOXMP_CHECK_VPS_BREAK(vpRc);
365
366 swprintf(keyname, L"CustomMode%dHeight", curKey);
367 vpRc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
368 VBOXMP_CHECK_VPS_BREAK(vpRc);
369
370 LOG(("got custom mode[%u]=%ux%u", curKey, CustomXRes, CustomYRes));
371
372 /* round down width to be a multiple of 8 if necessary */
373 if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
374 {
375 CustomXRes &= 0xFFF8;
376 }
377
378 LOG(("adding video mode from registry."));
379
380 RTRECTSIZE Resolution = {CustomXRes, CustomYRes};
381
382 vboxWddmVModesAdd(pExt, pModes, u32Target, &Resolution, FALSE);
383 }
384
385 vpRc = VBoxMPCmnRegFini(Registry);
386 VBOXMP_WARN_VPS(vpRc);
387
388 return VINF_SUCCESS;
389}
390
391static VBOXWDDM_VMODES g_VBoxWddmVModes;
392
393void VBoxWddmVModesCleanup()
394{
395 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
396 vboxWddmVModesCleanup(pModes);
397}
398
399int VBoxWddmVModesInit(PVBOXMP_DEVEXT pExt)
400{
401 VBOXWDDM_VMODES *pModes = &g_VBoxWddmVModes;
402
403 vboxWddmVModesInit(pModes, VBoxCommonFromDeviceExt(pExt)->cDisplays);
404
405 int rc;
406
407 for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i)
408 {
409 rc = voxWddmVModesInitForTarget(pExt, pModes, (uint32_t)i);
410 if (RT_FAILURE(rc))
411 {
412 WARN(("voxWddmVModesInitForTarget failed %d", rc));
413 return rc;
414 }
415 }
416
417 return VINF_SUCCESS;
418}
419
420const CR_SORTARRAY* VBoxWddmVModesGet(PVBOXMP_DEVEXT pExt, uint32_t u32Target)
421{
422 if (u32Target >= (uint32_t)VBoxCommonFromDeviceExt(pExt)->cDisplays)
423 {
424 WARN(("invalid target"));
425 return NULL;
426 }
427
428 return &g_VBoxWddmVModes.Modes.aTargets[u32Target];
429}
430
431int VBoxWddmVModesRemove(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution)
432{
433 return vboxWddmVModesRemove(pExt, &g_VBoxWddmVModes, u32Target, pResolution);
434}
435
436int VBoxWddmVModesAdd(PVBOXMP_DEVEXT pExt, uint32_t u32Target, const RTRECTSIZE *pResolution, BOOLEAN fTrancient)
437{
438 return vboxWddmVModesAdd(pExt, &g_VBoxWddmVModes, u32Target, pResolution, fTrancient);
439}
440
441
442static NTSTATUS vboxWddmChildStatusReportPerform(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_CHILD_STATUS pChildStatus, D3DDDI_VIDEO_PRESENT_TARGET_ID iChild)
443{
444 DXGK_CHILD_STATUS DdiChildStatus;
445
446 Assert(iChild < UINT32_MAX/2);
447 Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
448
449 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[iChild];
450
451 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_DISCONNECTED)
452 && pTarget->fConnected)
453 {
454 /* report disconnected */
455 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
456 DdiChildStatus.Type = StatusConnection;
457 DdiChildStatus.ChildUid = iChild;
458 DdiChildStatus.HotPlug.Connected = FALSE;
459
460 LOG(("Reporting DISCONNECT to child %d", DdiChildStatus.ChildUid));
461
462 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
463 if (!NT_SUCCESS(Status))
464 {
465 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
466 return Status;
467 }
468 pTarget->fConnected = FALSE;
469 }
470
471 if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_CONNECTED)
472 && !pTarget->fConnected)
473 {
474 /* report disconnected */
475 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
476 DdiChildStatus.Type = StatusConnection;
477 DdiChildStatus.ChildUid = iChild;
478 DdiChildStatus.HotPlug.Connected = TRUE;
479
480 LOG(("Reporting CONNECT to child %d", DdiChildStatus.ChildUid));
481
482 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
483 if (!NT_SUCCESS(Status))
484 {
485 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
486 return Status;
487 }
488 pTarget->fConnected = TRUE;
489 }
490
491 if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_ROTATED)
492 {
493 /* report disconnected */
494 memset(&DdiChildStatus, 0, sizeof (DdiChildStatus));
495 DdiChildStatus.Type = StatusRotation;
496 DdiChildStatus.ChildUid = iChild;
497 DdiChildStatus.Rotation.Angle = pChildStatus->u8RotationAngle;
498
499 LOG(("Reporting ROTATED to child %d", DdiChildStatus.ChildUid));
500
501 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus);
502 if (!NT_SUCCESS(Status))
503 {
504 WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status));
505 return Status;
506 }
507 }
508
509 return STATUS_SUCCESS;
510}
511
512static NTSTATUS vboxWddmChildStatusHandleRequest(PVBOXMP_DEVEXT pDevExt, VBOXVDMACMD_CHILD_STATUS_IRQ *pBody)
513{
514 NTSTATUS Status = STATUS_SUCCESS;
515
516 for (UINT i = 0; i < pBody->cInfos; ++i)
517 {
518 PVBOXVDMA_CHILD_STATUS pInfo = &pBody->aInfos[i];
519 if (pBody->fFlags & VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL)
520 {
521 for (D3DDDI_VIDEO_PRESENT_TARGET_ID iChild = 0; iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++iChild)
522 {
523 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, iChild);
524 if (!NT_SUCCESS(Status))
525 {
526 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
527 break;
528 }
529 }
530 }
531 else
532 {
533 Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, pInfo->iChild);
534 if (!NT_SUCCESS(Status))
535 {
536 WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status));
537 break;
538 }
539 }
540 }
541
542 return Status;
543}
544
545#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
546typedef struct VBOXWDDMCHILDSTATUSCB
547{
548 PVBOXVDMACBUF_DR pDr;
549 PKEVENT pEvent;
550} VBOXWDDMCHILDSTATUSCB, *PVBOXWDDMCHILDSTATUSCB;
551
552static DECLCALLBACK(VOID) vboxWddmChildStatusReportCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
553{
554 /* we should be called from our DPC routine */
555 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
556
557 PVBOXWDDMCHILDSTATUSCB pCtx = (PVBOXWDDMCHILDSTATUSCB)pvContext;
558 PVBOXVDMACBUF_DR pDr = pCtx->pDr;
559 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
560 VBOXVDMACMD_CHILD_STATUS_IRQ *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ);
561
562 vboxWddmChildStatusHandleRequest(pDevExt, pBody);
563
564 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
565
566 if (pCtx->pEvent)
567 {
568 KeSetEvent(pCtx->pEvent, 0, FALSE);
569 }
570}
571#endif
572
573NTSTATUS VBoxWddmChildStatusReportReconnected(PVBOXMP_DEVEXT pDevExt, uint32_t iChild)
574{
575#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
576 NTSTATUS Status = STATUS_UNSUCCESSFUL;
577 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof (VBOXVDMACMD_CHILD_STATUS_IRQ));
578
579 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd);
580 if (pDr)
581 {
582 // vboxVdmaCBufDrCreate zero initializes the pDr
583 /* the command data follows the descriptor */
584 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
585 pDr->cbBuf = cbCmd;
586 pDr->rc = VERR_NOT_IMPLEMENTED;
587
588 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
589 pHdr->enmType = VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ;
590 pHdr->u32CmdSpecific = 0;
591 PVBOXVDMACMD_CHILD_STATUS_IRQ pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ);
592 pBody->cInfos = 1;
593 if (iChild == D3DDDI_ID_ALL)
594 {
595 pBody->fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL;
596 }
597 pBody->aInfos[0].iChild = iChild;
598 pBody->aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED;
599 /* we're going to KeWaitForSingleObject */
600 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
601
602 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
603 VBOXWDDMCHILDSTATUSCB Ctx;
604 KEVENT Event;
605 KeInitializeEvent(&Event, NotificationEvent, FALSE);
606 Ctx.pDr = pDr;
607 Ctx.pEvent = &Event;
608 vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxWddmChildStatusReportCompletion, &Ctx);
609 /* mark command as submitted & invisible for the dx runtime since dx did not originate it */
610 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
611 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
612 Assert(rc == VINF_SUCCESS);
613 if (RT_SUCCESS(rc))
614 {
615 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
616 Assert(Status == STATUS_SUCCESS);
617 return STATUS_SUCCESS;
618 }
619
620 Status = STATUS_UNSUCCESSFUL;
621
622 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
623 }
624 else
625 {
626 /* @todo: try flushing.. */
627 WARN(("vboxVdmaCBufDrCreate returned NULL"));
628 Status = STATUS_INSUFFICIENT_RESOURCES;
629 }
630
631 return Status;
632#else
633 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
634 Body.cInfos = 1;
635 if (iChild == D3DDDI_ID_ALL)
636 {
637 Body.fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL;
638 }
639 Body.aInfos[0].iChild = iChild;
640 Body.aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED;
641 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
642 return vboxWddmChildStatusHandleRequest(pDevExt, &Body);
643#endif
644}
645
646NTSTATUS VBoxWddmChildStatusConnect(PVBOXMP_DEVEXT pDevExt, uint32_t iChild, BOOLEAN fConnect)
647{
648#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ
649# error "port me!"
650#else
651 Assert(iChild < (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
652 NTSTATUS Status = STATUS_SUCCESS;
653 VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0};
654 Body.cInfos = 1;
655 Body.aInfos[0].iChild = iChild;
656 Body.aInfos[0].fFlags = fConnect ? VBOXVDMA_CHILD_STATUS_F_CONNECTED : VBOXVDMA_CHILD_STATUS_F_DISCONNECTED;
657 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
658 Status = vboxWddmChildStatusHandleRequest(pDevExt, &Body);
659 if (!NT_SUCCESS(Status))
660 WARN(("vboxWddmChildStatusHandleRequest failed Status 0x%x", Status));
661
662 return Status;
663#endif
664}
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