VirtualBox

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

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

scm: cleaning up todos

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