VirtualBox

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

Last change on this file since 41233 was 41233, checked in by vboxsync, 13 years ago

wddm: visible rects fix for disabled Aero

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.3 KB
Line 
1/* $Id: VBoxMPVdma.cpp 41233 2012-05-10 12:16:22Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011 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#include "VBoxMPVdma.h"
22#include "VBoxMPVhwa.h"
23#include <iprt/asm.h>
24
25NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe)
26{
27 KeInitializeSpinLock(&pPipe->SinchLock);
28 KeInitializeEvent(&pPipe->Event, SynchronizationEvent, FALSE);
29 InitializeListHead(&pPipe->CmdListHead);
30 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
31 pPipe->bNeedNotify = true;
32 return STATUS_SUCCESS;
33}
34
35NTSTATUS vboxVdmaPipeSvrOpen(PVBOXVDMAPIPE pPipe)
36{
37 NTSTATUS Status = STATUS_SUCCESS;
38 KIRQL OldIrql;
39 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
40 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
41 switch (pPipe->enmState)
42 {
43 case VBOXVDMAPIPE_STATE_CREATED:
44 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
45 pPipe->bNeedNotify = false;
46 break;
47 case VBOXVDMAPIPE_STATE_OPENNED:
48 pPipe->bNeedNotify = false;
49 break;
50 default:
51 AssertBreakpoint();
52 Status = STATUS_INVALID_PIPE_STATE;
53 break;
54 }
55
56 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
57 return Status;
58}
59
60NTSTATUS vboxVdmaPipeSvrClose(PVBOXVDMAPIPE pPipe)
61{
62 NTSTATUS Status = STATUS_SUCCESS;
63 KIRQL OldIrql;
64 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
65 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
66 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
67 switch (pPipe->enmState)
68 {
69 case VBOXVDMAPIPE_STATE_CLOSING:
70 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
71 break;
72 case VBOXVDMAPIPE_STATE_CLOSED:
73 break;
74 default:
75 AssertBreakpoint();
76 Status = STATUS_INVALID_PIPE_STATE;
77 break;
78 }
79
80 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
81 return Status;
82}
83
84NTSTATUS vboxVdmaPipeCltClose(PVBOXVDMAPIPE pPipe)
85{
86 NTSTATUS Status = STATUS_SUCCESS;
87 KIRQL OldIrql;
88 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
89 bool bNeedNotify = false;
90 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
91 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
92 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
93 switch (pPipe->enmState)
94 {
95 case VBOXVDMAPIPE_STATE_OPENNED:
96 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
97 bNeedNotify = pPipe->bNeedNotify;
98 pPipe->bNeedNotify = false;
99 break;
100 case VBOXVDMAPIPE_STATE_CREATED:
101 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
102 pPipe->bNeedNotify = false;
103 break;
104 case VBOXVDMAPIPE_STATE_CLOSED:
105 break;
106 default:
107 AssertBreakpoint();
108 Status = STATUS_INVALID_PIPE_STATE;
109 break;
110 }
111
112 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
113
114 if (bNeedNotify)
115 {
116 KeSetEvent(&pPipe->Event, 0, FALSE);
117 }
118 return Status;
119}
120
121NTSTATUS vboxVdmaPipeDestruct(PVBOXVDMAPIPE pPipe)
122{
123 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
124 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
125 /* ensure the pipe is closed */
126 NTSTATUS Status = vboxVdmaPipeCltClose(pPipe);
127 Assert(Status == STATUS_SUCCESS);
128
129 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
130
131 return Status;
132}
133
134NTSTATUS vboxVdmaPipeSvrCmdGetList(PVBOXVDMAPIPE pPipe, PLIST_ENTRY pDetachHead)
135{
136 PLIST_ENTRY pEntry = NULL;
137 KIRQL OldIrql;
138 NTSTATUS Status = STATUS_SUCCESS;
139 VBOXVDMAPIPE_STATE enmState = VBOXVDMAPIPE_STATE_CLOSED;
140 do
141 {
142 bool bListEmpty = true;
143 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
144 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
145 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
146 Assert(pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED);
147 enmState = pPipe->enmState;
148 if (enmState >= VBOXVDMAPIPE_STATE_OPENNED)
149 {
150 vboxVideoLeDetach(&pPipe->CmdListHead, pDetachHead);
151 bListEmpty = !!(IsListEmpty(pDetachHead));
152 pPipe->bNeedNotify = bListEmpty;
153 }
154 else
155 {
156 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
157 Status = STATUS_INVALID_PIPE_STATE;
158 break;
159 }
160
161 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
162
163 if (!bListEmpty)
164 {
165 Assert(Status == STATUS_SUCCESS);
166 break;
167 }
168
169 if (enmState == VBOXVDMAPIPE_STATE_OPENNED)
170 {
171 Status = KeWaitForSingleObject(&pPipe->Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
172 Assert(Status == STATUS_SUCCESS);
173 if (Status != STATUS_SUCCESS)
174 break;
175 }
176 else
177 {
178 Assert(enmState == VBOXVDMAPIPE_STATE_CLOSING);
179 Status = STATUS_PIPE_CLOSING;
180 break;
181 }
182 } while (1);
183
184 return Status;
185}
186
187NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd)
188{
189 NTSTATUS Status = STATUS_SUCCESS;
190 KIRQL OldIrql;
191 bool bNeedNotify = false;
192
193 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
194
195 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
196 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
197 {
198 bNeedNotify = pPipe->bNeedNotify;
199 InsertHeadList(&pPipe->CmdListHead, &pCmd->ListEntry);
200 pPipe->bNeedNotify = false;
201 }
202 else
203 Status = STATUS_INVALID_PIPE_STATE;
204
205 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
206
207 if (bNeedNotify)
208 {
209 KeSetEvent(&pPipe->Event, 0, FALSE);
210 }
211
212 return Status;
213}
214
215PVBOXVDMAPIPE_CMD_DR vboxVdmaGgCmdCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_TYPE enmType, uint32_t cbCmd)
216{
217 PVBOXVDMAPIPE_CMD_DR pHdr;
218#ifdef VBOX_WDDM_IRQ_COMPLETION
219 if (enmType == VBOXVDMAPIPE_CMD_TYPE_DMACMD)
220 {
221 UINT cbAlloc = VBOXVDMACMD_SIZE_FROMBODYSIZE(cbCmd);
222 VBOXVDMACBUF_DR* pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbAlloc);
223 if (!pDr)
224 {
225 WARN(("dr allocation failed"));
226 return NULL;
227 }
228 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
229 pDr->cbBuf = VBOXVDMACMD_HEADER_SIZE();
230 pDr->rc = VINF_SUCCESS;
231
232
233 PVBOXVDMACMD pDmaHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
234 pDmaHdr->enmType = VBOXVDMACMD_TYPE_DMA_NOP;
235 pDmaHdr->u32CmdSpecific = 0;
236
237 pHdr = VBOXVDMACMD_BODY(pDmaHdr, VBOXVDMAPIPE_CMD_DR);
238 }
239 else
240#endif
241 {
242 pHdr = (PVBOXVDMAPIPE_CMD_DR)vboxWddmMemAllocZero(cbCmd);
243 if (!pHdr)
244 {
245 WARN(("cmd allocation failed"));
246 return NULL;
247 }
248 }
249 pHdr->enmType = enmType;
250 pHdr->cRefs = 1;
251 return pHdr;
252}
253
254#ifdef VBOX_WDDM_IRQ_COMPLETION
255DECLINLINE(VBOXVDMACBUF_DR*) vboxVdmaGgCmdDmaGetDr(PVBOXVDMAPIPE_CMD_DMACMD pDr)
256{
257 VBOXVDMACMD* pDmaCmd = VBOXVDMACMD_FROM_BODY(pDr);
258 VBOXVDMACBUF_DR* pDmaDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaCmd);
259 return pDmaDr;
260}
261
262DECLINLINE(PVBOXVDMADDI_CMD) vboxVdmaGgCmdDmaGetDdiCmd(PVBOXVDMAPIPE_CMD_DMACMD pDr)
263{
264 VBOXVDMACBUF_DR* pDmaDr = vboxVdmaGgCmdDmaGetDr(pDr);
265 return VBOXVDMADDI_CMD_FROM_BUF_DR(pDmaDr);
266}
267
268#endif
269
270void vboxVdmaGgCmdDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pDr)
271{
272#ifdef VBOX_WDDM_IRQ_COMPLETION
273 if (pDr->enmType == VBOXVDMAPIPE_CMD_TYPE_DMACMD)
274 {
275 VBOXVDMACBUF_DR* pDmaDr = vboxVdmaGgCmdDmaGetDr((PVBOXVDMAPIPE_CMD_DMACMD)pDr);
276 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDmaDr);
277 return;
278 }
279#endif
280 vboxWddmMemFree(pDr);
281}
282
283DECLCALLBACK(VOID) vboxVdmaGgDdiCmdRelease(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
284{
285 vboxVdmaGgCmdRelease(pDevExt, (PVBOXVDMAPIPE_CMD_DR)pvContext);
286}
287
288/**
289 * helper function used for system thread creation
290 */
291static NTSTATUS vboxVdmaGgThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
292{
293 NTSTATUS fStatus;
294 HANDLE hThread;
295 OBJECT_ATTRIBUTES fObjectAttributes;
296
297 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
298
299 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
300 NULL, NULL);
301
302 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
303 &fObjectAttributes, NULL, NULL,
304 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
305 if (!NT_SUCCESS(fStatus))
306 return fStatus;
307
308 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
309 KernelMode, (PVOID*) ppThread, NULL);
310 ZwClose(hThread);
311 return STATUS_SUCCESS;
312}
313
314DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const PVBOXWDDM_RECTS_INFO pRects, PVBOXWDDM_RECTS_INFO pResult)
315{
316 uint32_t cRects = 0;
317 for (uint32_t i = 0; i < pRects->cRects; ++i)
318 {
319 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[cRects]))
320 {
321 ++cRects;
322 }
323 }
324
325 pResult->cRects = cRects;
326}
327
328DECLINLINE(bool) vboxVdmaDirtyRectsHasIntersections(const RECT *paRects1, uint32_t cRects1, const RECT *paRects2, uint32_t cRects2)
329{
330 RECT tmpRect;
331 for (uint32_t i = 0; i < cRects1; ++i)
332 {
333 const RECT * pRect1 = &paRects1[i];
334 for (uint32_t j = 0; j < cRects2; ++j)
335 {
336 const RECT * pRect2 = &paRects2[j];
337 if (vboxWddmRectIntersection(pRect1, pRect2, &tmpRect))
338 return true;
339 }
340 }
341 return false;
342}
343
344DECLINLINE(bool) vboxVdmaDirtyRectsIsCover(const RECT *paRects, uint32_t cRects, const RECT *paRectsCovered, uint32_t cRectsCovered)
345{
346 for (uint32_t i = 0; i < cRectsCovered; ++i)
347 {
348 const RECT * pRectCovered = &paRectsCovered[i];
349 uint32_t j = 0;
350 for (; j < cRects; ++j)
351 {
352 const RECT * pRect = &paRects[j];
353 if (vboxWddmRectIsCoveres(pRect, pRectCovered))
354 break;
355 }
356 if (j == cRects)
357 return false;
358 }
359 return true;
360}
361
362NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain)
363{
364 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
365 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(0);
366 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal =
367 (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pSwapchain->pContext->CmContext, cbCmdInternal);
368 Assert(pCmdInternal);
369 if (pCmdInternal)
370 {
371 pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
372 pCmdInternal->Cmd.fFlags.Value = 0;
373 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
374 pCmdInternal->Cmd.fFlags.bHide = 1;
375 pCmdInternal->Cmd.RectsInfo.cRects = 0;
376 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
377 return STATUS_SUCCESS;
378 }
379 return STATUS_NO_MEMORY;
380}
381
382/**
383 * @param pDevExt
384 */
385static NTSTATUS vboxVdmaGgDirtyRectsProcess(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain, RECT *pSrcRect, VBOXVDMAPIPE_RECTS *pContextRects)
386{
387 PVBOXWDDM_RECTS_INFO pRects = &pContextRects->UpdateRects;
388 NTSTATUS Status = STATUS_SUCCESS;
389 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = NULL;
390 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects);
391 BOOLEAN fCurChanged = FALSE, fCurRectChanged = FALSE;
392 POINT CurPos;
393 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
394
395 ExAcquireFastMutex(&pDevExt->ContextMutex);
396
397 if (pSwapchain)
398 {
399 CurPos.x = pContextRects->ContextRect.left - pSrcRect->left;
400 CurPos.y = pContextRects->ContextRect.top - pSrcRect->top;
401
402 if (CurPos.x != pSwapchain->Pos.x || CurPos.y != pSwapchain->Pos.y)
403 {
404#if 0
405 if (pSwapchain->Pos.x != VBOXWDDM_INVALID_COORD)
406 VBoxWddmVrListTranslate(&pSwapchain->VisibleRegions, pSwapchain->Pos.x - CurPos.x, pSwapchain->Pos.y - CurPos.y);
407 else
408#endif
409 VBoxWddmVrListClear(&pSwapchain->VisibleRegions);
410 fCurRectChanged = TRUE;
411 pSwapchain->Pos = CurPos;
412 }
413
414 Status = VBoxWddmVrListRectsAdd(&pSwapchain->VisibleRegions, pRects->cRects, pRects->aRects, &fCurChanged);
415 if (!NT_SUCCESS(Status))
416 {
417 WARN(("VBoxWddmVrListRectsAdd failed!"));
418 goto done;
419 }
420
421
422 /* visible rects of different windows do not intersect,
423 * so if the given window visible rects did not increase, others have not changed either */
424 if (!fCurChanged && !fCurRectChanged)
425 goto done;
426 }
427
428 /* before posting the add visible rects diff, we need to first hide rects for other windows */
429
430 for (PLIST_ENTRY pCur = pDevExt->SwapchainList3D.Flink; pCur != &pDevExt->SwapchainList3D; pCur = pCur->Flink)
431 {
432 if (pCur != &pSwapchain->DevExtListEntry)
433 {
434 PVBOXWDDM_SWAPCHAIN pCurSwapchain = VBOXWDDMENTRY_2_SWAPCHAIN(pCur);
435 BOOLEAN fChanged = FALSE;
436
437 Status = VBoxWddmVrListRectsSubst(&pCurSwapchain->VisibleRegions, pRects->cRects, pRects->aRects, &fChanged);
438 if (!NT_SUCCESS(Status))
439 {
440 WARN(("vboxWddmVrListRectsAdd failed!"));
441 goto done;
442 }
443
444 if (!fChanged)
445 continue;
446
447 if (!pCmdInternal)
448 {
449 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pCurSwapchain->pContext->CmContext, cbCmdInternal);
450 if (!pCmdInternal)
451 {
452 WARN(("vboxVideoCmCmdCreate failed!"));
453 Status = STATUS_NO_MEMORY;
454 goto done;
455 }
456 }
457 else
458 {
459 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pCurSwapchain->pContext->CmContext);
460 }
461
462 pCmdInternal->Cmd.fFlags.Value = 0;
463 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
464 memcpy(&pCmdInternal->Cmd.RectsInfo, pRects, RT_OFFSETOF(VBOXWDDM_RECTS_INFO, aRects[pRects->cRects]));
465
466 pCmdInternal->hSwapchainUm = pCurSwapchain->hSwapchainUm;
467
468 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects));
469 pCmdInternal = NULL;
470 }
471 }
472
473 if (!pSwapchain)
474 goto done;
475
476 RECT *pVisRects;
477
478 if (fCurRectChanged && fCurChanged)
479 {
480 cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects + 1);
481 if (pCmdInternal)
482 vboxVideoCmCmdRelease(pCmdInternal);
483 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal);
484 pCmdInternal->Cmd.fFlags.Value = 0;
485 pCmdInternal->Cmd.fFlags.bSetViewRect = 1;
486 pCmdInternal->Cmd.fFlags.bAddVisibleRects = 1;
487 pCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects + 1;
488 pCmdInternal->Cmd.RectsInfo.aRects[0].left = CurPos.x;
489 pCmdInternal->Cmd.RectsInfo.aRects[0].top = CurPos.y;
490 pCmdInternal->Cmd.RectsInfo.aRects[0].right = CurPos.x + pSwapchain->width;
491 pCmdInternal->Cmd.RectsInfo.aRects[0].bottom = CurPos.y + pSwapchain->height;
492 pVisRects = &pCmdInternal->Cmd.RectsInfo.aRects[1];
493 }
494 else
495 {
496 if (!pCmdInternal)
497 {
498 Assert(pContext == pSwapchain->pContext);
499 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal);
500 if (!pCmdInternal)
501 {
502 WARN(("vboxVideoCmCmdCreate failed!"));
503 Status = STATUS_NO_MEMORY;
504 goto done;
505 }
506 }
507 else
508 {
509 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pContext->CmContext);
510 }
511
512 pCmdInternal->Cmd.fFlags.Value = 0;
513 pCmdInternal->Cmd.fFlags.bAddVisibleRects = 1;
514 pCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects;
515 pVisRects = &pCmdInternal->Cmd.RectsInfo.aRects[0];
516 }
517
518 pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
519
520 if (pRects->cRects)
521 memcpy(pVisRects, pRects->aRects, sizeof (RECT) * pRects->cRects);
522
523 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects));
524 pCmdInternal = NULL;
525
526done:
527 ExReleaseFastMutex(&pDevExt->ContextMutex);
528
529 if (pCmdInternal)
530 vboxVideoCmCmdRelease(pCmdInternal);
531
532 return Status;
533}
534
535static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF)
536{
537 NTSTATUS Status = STATUS_UNSUCCESSFUL;
538 Assert (pDevExt->pvVisibleVram);
539 if (pDevExt->pvVisibleVram)
540 {
541 PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
542 Assert(pAlloc->offVram != VBOXVIDEOOFFSET_VOID);
543 if (pAlloc->offVram != VBOXVIDEOOFFSET_VOID)
544 {
545 RECT UnionRect = {0};
546 uint8_t *pvMem = pDevExt->pvVisibleVram + pAlloc->offVram;
547 UINT bpp = pAlloc->SurfDesc.bpp;
548 Assert(bpp);
549 Assert(((bpp * pAlloc->SurfDesc.width) >> 3) == pAlloc->SurfDesc.pitch);
550 switch (bpp)
551 {
552 case 32:
553 {
554 uint8_t bytestPP = bpp >> 3;
555 for (UINT i = 0; i < pCF->ClrFill.Rects.cRects; ++i)
556 {
557 RECT *pRect = &pCF->ClrFill.Rects.aRects[i];
558 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
559 {
560 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->SurfDesc.pitch) + (pRect->left * bytestPP));
561 uint32_t cRaw = pRect->right - pRect->left;
562 Assert(pRect->left >= 0);
563 Assert(pRect->right <= (LONG)pAlloc->SurfDesc.width);
564 Assert(pRect->top >= 0);
565 Assert(pRect->bottom <= (LONG)pAlloc->SurfDesc.height);
566 for (UINT j = 0; j < cRaw; ++j)
567 {
568 *pvU32Mem = pCF->ClrFill.Color;
569 ++pvU32Mem;
570 }
571 }
572 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
573 }
574 Status = STATUS_SUCCESS;
575 break;
576 }
577 case 16:
578 case 8:
579 default:
580 AssertBreakpoint();
581 break;
582 }
583
584 if (Status == STATUS_SUCCESS)
585 {
586 if (pAlloc->SurfDesc.VidPnSourceId != D3DDDI_ID_UNINITIALIZED
587 && pAlloc->bAssigned
588#if 0//def VBOXWDDM_RENDER_FROM_SHADOW
589 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
590#else
591 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE
592#endif
593 )
594 {
595 if (!vboxWddmRectIsEmpty(&UnionRect))
596 {
597 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->ClrFill.Alloc.pAlloc->SurfDesc.VidPnSourceId];
598 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
599 if (!cUnlockedVBVADisabled)
600 {
601 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &UnionRect);
602 }
603 else
604 {
605 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UnionRect);
606 }
607 }
608 }
609 else
610 {
611 AssertBreakpoint();
612 }
613 }
614 }
615 }
616
617 return Status;
618}
619
620NTSTATUS vboxVdmaGgDmaBltPerform(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSrcAlloc, RECT* pSrcRect,
621 PVBOXWDDM_ALLOCATION pDstAlloc, RECT* pDstRect)
622{
623 uint8_t* pvVramBase = pDevExt->pvVisibleVram;
624 /* we do not support stretching */
625 uint32_t srcWidth = pSrcRect->right - pSrcRect->left;
626 uint32_t srcHeight = pSrcRect->bottom - pSrcRect->top;
627 uint32_t dstWidth = pDstRect->right - pDstRect->left;
628 uint32_t dstHeight = pDstRect->bottom - pDstRect->top;
629 Assert(srcHeight == dstHeight);
630 Assert(dstWidth == srcWidth);
631 Assert(pDstAlloc->offVram != VBOXVIDEOOFFSET_VOID);
632 Assert(pSrcAlloc->offVram != VBOXVIDEOOFFSET_VOID);
633 D3DDDIFORMAT enmSrcFormat, enmDstFormat;
634
635 enmSrcFormat = pSrcAlloc->SurfDesc.format;
636 enmDstFormat = pDstAlloc->SurfDesc.format;
637
638 if (enmSrcFormat != enmDstFormat)
639 {
640 /* just ignore the alpha component
641 * this is ok since our software-based stuff can not handle alpha channel in any way */
642 enmSrcFormat = vboxWddmFmtNoAlphaFormat(enmSrcFormat);
643 enmDstFormat = vboxWddmFmtNoAlphaFormat(enmDstFormat);
644 if (enmSrcFormat != enmDstFormat)
645 {
646 WARN(("color conversion src(%d), dst(%d) not supported!", pSrcAlloc->SurfDesc.format, pDstAlloc->SurfDesc.format));
647 return STATUS_INVALID_PARAMETER;
648 }
649 }
650 if (srcHeight != dstHeight)
651 return STATUS_INVALID_PARAMETER;
652 if (srcWidth != dstWidth)
653 return STATUS_INVALID_PARAMETER;
654 if (pDstAlloc->offVram == VBOXVIDEOOFFSET_VOID)
655 return STATUS_INVALID_PARAMETER;
656 if (pSrcAlloc->offVram == VBOXVIDEOOFFSET_VOID)
657 return STATUS_INVALID_PARAMETER;
658
659 uint8_t *pvDstSurf = pvVramBase + pDstAlloc->offVram;
660 uint8_t *pvSrcSurf = pvVramBase + pSrcAlloc->offVram;
661
662 if (pDstAlloc->SurfDesc.width == dstWidth
663 && pSrcAlloc->SurfDesc.width == srcWidth
664 && pSrcAlloc->SurfDesc.width == pDstAlloc->SurfDesc.width)
665 {
666 Assert(!pDstRect->left);
667 Assert(!pSrcRect->left);
668 uint32_t cbDstOff = vboxWddmCalcOffXYrd(0 /* x */, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
669 uint32_t cbSrcOff = vboxWddmCalcOffXYrd(0 /* x */, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
670 uint32_t cbSize = vboxWddmCalcSize(pDstAlloc->SurfDesc.pitch, dstHeight, pDstAlloc->SurfDesc.format);
671 memcpy(pvDstSurf + cbDstOff, pvSrcSurf + cbSrcOff, cbSize);
672 }
673 else
674 {
675 uint32_t cbDstLine = vboxWddmCalcRowSize(pDstRect->left, pDstRect->right, pDstAlloc->SurfDesc.format);
676 uint32_t offDstStart = vboxWddmCalcOffXYrd(pDstRect->left, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
677 Assert(cbDstLine <= pDstAlloc->SurfDesc.pitch);
678 uint32_t cbDstSkip = pDstAlloc->SurfDesc.pitch;
679 uint8_t * pvDstStart = pvDstSurf + offDstStart;
680
681 uint32_t cbSrcLine = vboxWddmCalcRowSize(pSrcRect->left, pSrcRect->right, pSrcAlloc->SurfDesc.format);
682 uint32_t offSrcStart = vboxWddmCalcOffXYrd(pSrcRect->left, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
683 Assert(cbSrcLine <= pSrcAlloc->SurfDesc.pitch);
684 uint32_t cbSrcSkip = pSrcAlloc->SurfDesc.pitch;
685 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
686
687 uint32_t cRows = vboxWddmCalcNumRows(pDstRect->top, pDstRect->bottom, pDstAlloc->SurfDesc.format);
688
689 Assert(cbDstLine == cbSrcLine);
690
691 for (uint32_t i = 0; i < cRows; ++i)
692 {
693 memcpy(pvDstStart, pvSrcStart, cbDstLine);
694 pvDstStart += cbDstSkip;
695 pvSrcStart += cbSrcSkip;
696 }
697 }
698 return STATUS_SUCCESS;
699}
700
701/*
702 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
703 */
704static NTSTATUS vboxVdmaGgDmaBlt(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_BLT pBlt)
705{
706 /* we do not support stretching for now */
707 Assert(pBlt->SrcRect.right - pBlt->SrcRect.left == pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left);
708 Assert(pBlt->SrcRect.bottom - pBlt->SrcRect.top == pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top);
709 if (pBlt->SrcRect.right - pBlt->SrcRect.left != pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left)
710 return STATUS_INVALID_PARAMETER;
711 if (pBlt->SrcRect.bottom - pBlt->SrcRect.top != pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top)
712 return STATUS_INVALID_PARAMETER;
713 Assert(pBlt->DstRects.UpdateRects.cRects);
714
715 NTSTATUS Status = STATUS_SUCCESS;
716
717 if (pBlt->DstRects.UpdateRects.cRects)
718 {
719 for (uint32_t i = 0; i < pBlt->DstRects.UpdateRects.cRects; ++i)
720 {
721 RECT SrcRect;
722 vboxWddmRectTranslated(&SrcRect, &pBlt->DstRects.UpdateRects.aRects[i], -pBlt->DstRects.ContextRect.left, -pBlt->DstRects.ContextRect.top);
723
724 Status = vboxVdmaGgDmaBltPerform(pDevExt, pBlt->SrcAlloc.pAlloc, &SrcRect,
725 pBlt->DstAlloc.pAlloc, &pBlt->DstRects.UpdateRects.aRects[i]);
726 Assert(Status == STATUS_SUCCESS);
727 if (Status != STATUS_SUCCESS)
728 return Status;
729 }
730 }
731 else
732 {
733 Status = vboxVdmaGgDmaBltPerform(pDevExt, pBlt->SrcAlloc.pAlloc, &pBlt->SrcRect,
734 pBlt->DstAlloc.pAlloc, &pBlt->DstRects.ContextRect);
735 Assert(Status == STATUS_SUCCESS);
736 if (Status != STATUS_SUCCESS)
737 return Status;
738 }
739
740 return Status;
741}
742
743static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y)
744{
745 vboxWddmRectTranslate(&pRects->ContextRect, x, y);
746
747 for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i)
748 {
749 vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y);
750 }
751}
752
753static NTSTATUS vboxVdmaGgDmaCmdProcessFast(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd)
754{
755 NTSTATUS Status = STATUS_SUCCESS;
756 PVBOXWDDM_CONTEXT pContext = pDmaCmd->pContext;
757 DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
758 switch (pDmaCmd->enmCmd)
759 {
760 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
761 {
762 PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd;
763 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
764 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
765
766 if (pBlt->Hdr.fFlags.fRealOp)
767 {
768 vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt);
769
770 if ((pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE
771 || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
772 && pDstAlloc->bAssigned)
773 {
774 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->SurfDesc.VidPnSourceId];
775 Assert(pDstAlloc->SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
776 Assert(pSource->pPrimaryAllocation == pDstAlloc);
777
778 RECT UpdateRect;
779 UpdateRect = pBlt->Blt.DstRects.UpdateRects.aRects[0];
780 for (UINT i = 1; i < pBlt->Blt.DstRects.UpdateRects.cRects; ++i)
781 {
782 vboxWddmRectUnite(&UpdateRect, &pBlt->Blt.DstRects.UpdateRects.aRects[i]);
783 }
784
785 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
786 if (!cUnlockedVBVADisabled)
787 {
788 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
789 }
790 else
791 {
792 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
793 }
794 }
795 }
796
797 if (pBlt->Hdr.fFlags.fVisibleRegions)
798 {
799 Status = STATUS_MORE_PROCESSING_REQUIRED;
800 vboxWddmAllocationRetain(pDstAlloc);
801 vboxWddmAllocationRetain(pSrcAlloc);
802 }
803 break;
804 }
805
806 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
807 {
808 PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd;
809 Assert(pFlip->Hdr.fFlags.fVisibleRegions);
810 Assert(!pFlip->Hdr.fFlags.fRealOp);
811 if (pFlip->Hdr.fFlags.fVisibleRegions)
812 {
813 Status = STATUS_MORE_PROCESSING_REQUIRED;
814 vboxWddmAllocationRetain(pFlip->Flip.Alloc.pAlloc);
815 }
816
817 break;
818 }
819 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
820 {
821 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDmaCmd;
822 Assert(pCF->Hdr.fFlags.fRealOp);
823 Assert(!pCF->Hdr.fFlags.fVisibleRegions);
824 Status = vboxVdmaGgDmaColorFill(pDevExt, pCF);
825 Assert(Status == STATUS_SUCCESS);
826 break;
827 }
828
829 default:
830 Assert(0);
831 break;
832 }
833
834 /* Corresponding Release is done by dma command completion handler */
835 vboxVdmaGgCmdAddRef(&pDmaCmd->Hdr);
836
837 NTSTATUS tmpStatus = vboxVdmaGgCmdDmaNotifyCompleted(pDevExt, pDmaCmd, enmComplType);
838 if (!NT_SUCCESS(tmpStatus))
839 {
840 WARN(("vboxVdmaGgCmdDmaNotifyCompleted failed, Status 0x%x", tmpStatus));
841 /* the command was NOT submitted, and thus will not be released, release it here */
842 vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr);
843 Status = tmpStatus;
844 }
845
846 return Status;
847}
848
849static NTSTATUS vboxVdmaGgDmaCmdProcessSlow(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd)
850{
851 NTSTATUS Status = STATUS_SUCCESS;
852 PVBOXWDDM_CONTEXT pContext = pDmaCmd->pContext;
853 DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
854
855 Assert(pDmaCmd->fFlags.Value);
856 Assert(!pDmaCmd->fFlags.fRealOp);
857
858 switch (pDmaCmd->enmCmd)
859 {
860 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
861 {
862 PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd;
863 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
864 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
865 BOOLEAN bComplete = TRUE;
866 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->SurfDesc.VidPnSourceId];
867 Assert(pDstAlloc->SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
868
869 if (pBlt->Hdr.fFlags.fVisibleRegions)
870 {
871 PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc);
872 POINT pos = pSource->VScreenPos;
873 if (pos.x || pos.y)
874 {
875 /* note: do NOT translate the src rect since it is used for screen pos calculation */
876 vboxWddmBltPipeRectsTranslate(&pBlt->Blt.DstRects, pos.x, pos.y);
877 }
878
879 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects);
880 Assert(Status == STATUS_SUCCESS);
881
882 if (pSwapchain)
883 vboxWddmSwapchainRelease(pSwapchain);
884 }
885 else
886 {
887 WARN(("not expected!"));
888 }
889
890 vboxWddmAllocationRelease(pDstAlloc);
891 vboxWddmAllocationRelease(pSrcAlloc);
892
893 break;
894 }
895
896 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
897 {
898 PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd;
899 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
900 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->SurfDesc.VidPnSourceId];
901 if (pFlip->Hdr.fFlags.fVisibleRegions)
902 {
903 PVBOXWDDM_SWAPCHAIN pSwapchain;
904 pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pAlloc);
905 if (pSwapchain)
906 {
907 POINT pos = pSource->VScreenPos;
908 RECT SrcRect;
909 VBOXVDMAPIPE_RECTS Rects;
910 SrcRect.left = 0;
911 SrcRect.top = 0;
912 SrcRect.right = pAlloc->SurfDesc.width;
913 SrcRect.bottom = pAlloc->SurfDesc.height;
914 Rects.ContextRect.left = pos.x;
915 Rects.ContextRect.top = pos.y;
916 Rects.ContextRect.right = pAlloc->SurfDesc.width + pos.x;
917 Rects.ContextRect.bottom = pAlloc->SurfDesc.height + pos.y;
918 Rects.UpdateRects.cRects = 1;
919 Rects.UpdateRects.aRects[0] = Rects.ContextRect;
920 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &SrcRect, &Rects);
921 Assert(Status == STATUS_SUCCESS);
922 vboxWddmSwapchainRelease(pSwapchain);
923 }
924 }
925 else
926 {
927 WARN(("not expected!"));
928 }
929
930 vboxWddmAllocationRelease(pAlloc);
931
932 break;
933 }
934
935 default:
936 {
937 WARN(("not expected!"));
938 break;
939 }
940 }
941
942 vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr);
943
944 return Status;
945}
946
947static DECLCALLBACK(UINT) vboxVdmaGgCmdCancelVisitor(PVBOXVIDEOCM_CTX pContext, PVOID pvCmd, uint32_t cbCmd, PVOID pvVisitor)
948{
949 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)pvVisitor;
950 if (!pSwapchain)
951 return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD;
952 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)pvCmd;
953 if (pCmdInternal->hSwapchainUm == pSwapchain->hSwapchainUm)
954 return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD;
955 return 0;
956}
957
958static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
959{
960 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvUser;
961 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
962
963 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
964 Assert(Status == STATUS_SUCCESS);
965 if (Status == STATUS_SUCCESS)
966 {
967 do
968 {
969 LIST_ENTRY CmdList;
970 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
971 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
972 if (Status == STATUS_SUCCESS)
973 {
974 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList;)
975 {
976 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
977 RemoveEntryList(pCur);
978 pCur = CmdList.Blink;
979 switch (pDr->enmType)
980 {
981 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
982 {
983 PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pDr;
984 Status = vboxVdmaGgDmaCmdProcessSlow(pDevExt, pDmaCmd);
985 Assert(Status == STATUS_SUCCESS);
986 } break;
987#if 0
988 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
989 {
990 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
991 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pRects->pContext, pRects->pSwapchain, &pRects->ContextsRects);
992 Assert(Status == STATUS_SUCCESS);
993 vboxVdmaGgCmdRelease(pDevExt, pDr);
994 break;
995 }
996#endif
997 case VBOXVDMAPIPE_CMD_TYPE_FINISH:
998 {
999 PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)pDr;
1000 PVBOXWDDM_CONTEXT pContext = pCmd->pContext;
1001 Assert(pCmd->pEvent);
1002 Status = vboxVideoCmCmdSubmitCompleteEvent(&pContext->CmContext, pCmd->pEvent);
1003 if (Status != STATUS_SUCCESS)
1004 {
1005 WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status));
1006 }
1007 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1008 break;
1009 }
1010 case VBOXVDMAPIPE_CMD_TYPE_CANCEL:
1011 {
1012 PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)pDr;
1013 PVBOXWDDM_CONTEXT pContext = pCmd->pContext;
1014 Status = vboxVideoCmCmdVisit(&pContext->CmContext, FALSE, vboxVdmaGgCmdCancelVisitor, pCmd->pSwapchain);
1015 if (Status != STATUS_SUCCESS)
1016 {
1017 WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status));
1018 }
1019 Assert(pCmd->pEvent);
1020 KeSetEvent(pCmd->pEvent, 0, FALSE);
1021 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1022 break;
1023 }
1024 default:
1025 AssertBreakpoint();
1026 }
1027 }
1028 }
1029 else
1030 break;
1031 } while (1);
1032 }
1033
1034 /* always try to close the pipe to make sure the client side is notified */
1035 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
1036 Assert(Status == STATUS_SUCCESS);
1037}
1038
1039NTSTATUS vboxVdmaGgConstruct(PVBOXMP_DEVEXT pDevExt)
1040{
1041 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
1042 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
1043 Assert(Status == STATUS_SUCCESS);
1044 if (Status == STATUS_SUCCESS)
1045 {
1046 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pDevExt);
1047 Assert(Status == STATUS_SUCCESS);
1048 if (Status == STATUS_SUCCESS)
1049 return STATUS_SUCCESS;
1050
1051 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
1052 Assert(tmpStatus == STATUS_SUCCESS);
1053 }
1054
1055 /* we're here ONLY in case of an error */
1056 Assert(Status != STATUS_SUCCESS);
1057 return Status;
1058}
1059
1060NTSTATUS vboxVdmaGgDestruct(PVBOXMP_DEVEXT pDevExt)
1061{
1062 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
1063 /* this informs the server thread that it should complete all current commands and exit */
1064 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
1065 Assert(Status == STATUS_SUCCESS);
1066 if (Status == STATUS_SUCCESS)
1067 {
1068 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
1069 Assert(Status == STATUS_SUCCESS);
1070 if (Status == STATUS_SUCCESS)
1071 {
1072 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
1073 Assert(Status == STATUS_SUCCESS);
1074 }
1075 }
1076
1077 return Status;
1078}
1079
1080NTSTATUS vboxVdmaGgCmdSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pCmd)
1081{
1082 switch (pCmd->enmType)
1083 {
1084 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
1085 {
1086 PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pCmd;
1087 NTSTATUS Status = vboxVdmaGgDmaCmdProcessFast(pDevExt, pDmaCmd);
1088 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
1089 break;
1090 return Status;
1091 }
1092 default:
1093 break;
1094 }
1095 /* correspondinf Release is done by the pipe command handler */
1096 vboxVdmaGgCmdAddRef(pCmd);
1097 return vboxVdmaPipeCltCmdPut(&pDevExt->u.primary.Vdma.DmaGg.CmdPipe, &pCmd->PipeHdr);
1098}
1099
1100NTSTATUS vboxVdmaGgCmdDmaNotifySubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd)
1101{
1102 PVBOXVDMADDI_CMD pDdiCmd;
1103#ifdef VBOX_WDDM_IRQ_COMPLETION
1104 pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd);
1105#else
1106 pDdiCmd = &pCmd->DdiCmd;
1107#endif
1108 NTSTATUS Status = vboxVdmaDdiCmdSubmitted(pDevExt, pDdiCmd);
1109 Assert(Status == STATUS_SUCCESS);
1110 return Status;
1111}
1112
1113NTSTATUS vboxVdmaGgCmdDmaNotifyCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1114{
1115#ifdef VBOX_WDDM_IRQ_COMPLETION
1116 VBOXVDMACBUF_DR* pDr = vboxVdmaGgCmdDmaGetDr(pCmd);
1117 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1118 Assert(rc == VINF_SUCCESS);
1119 if (RT_SUCCESS(rc))
1120 {
1121 return STATUS_SUCCESS;
1122 }
1123 return STATUS_UNSUCCESSFUL;
1124#else
1125 return vboxVdmaDdiCmdCompleted(pDevExt, &pCmd->DdiCmd, enmComplType);
1126#endif
1127}
1128
1129VOID vboxVdmaGgCmdDmaNotifyInit(PVBOXVDMAPIPE_CMD_DMACMD pCmd,
1130 uint32_t u32NodeOrdinal, uint32_t u32FenceId,
1131 PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete, PVOID pvComplete)
1132{
1133 PVBOXVDMADDI_CMD pDdiCmd;
1134#ifdef VBOX_WDDM_IRQ_COMPLETION
1135 pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd);
1136#else
1137 pDdiCmd = &pCmd->DdiCmd;
1138#endif
1139 vboxVdmaDdiCmdInit(pDdiCmd, u32NodeOrdinal, u32FenceId, pfnComplete, pvComplete);
1140}
1141
1142NTSTATUS vboxVdmaGgCmdFinish(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PKEVENT pEvent)
1143{
1144 NTSTATUS Status = STATUS_SUCCESS;
1145
1146 PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_FINISH, sizeof (*pCmd));
1147 if (pCmd)
1148 {
1149 pCmd->pContext = pContext;
1150 pCmd->pEvent = pEvent;
1151 Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr);
1152 if (!NT_SUCCESS(Status))
1153 {
1154 WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status));
1155 }
1156 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1157 }
1158 else
1159 {
1160 WARN(("vboxVdmaGgCmdCreate failed"));
1161 Status = STATUS_NO_MEMORY;
1162 }
1163 return Status;
1164}
1165
1166NTSTATUS vboxVdmaGgCmdCancel(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
1167{
1168 NTSTATUS Status = STATUS_SUCCESS;
1169
1170 PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_CANCEL, sizeof (*pCmd));
1171 if (pCmd)
1172 {
1173 KEVENT Event;
1174 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1175 pCmd->pContext = pContext;
1176 pCmd->pSwapchain = pSwapchain;
1177 pCmd->pEvent = &Event;
1178 Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr);
1179 if (NT_SUCCESS(Status))
1180 {
1181 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1182 Assert(Status == STATUS_SUCCESS);
1183 }
1184 else
1185 {
1186 WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status));
1187 }
1188 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1189 }
1190 else
1191 {
1192 WARN(("vboxVdmaGgCmdCreate failed"));
1193 Status = STATUS_NO_MEMORY;
1194 }
1195 return Status;
1196}
1197
1198/* end */
1199
1200#ifdef VBOX_WITH_VDMA
1201/*
1202 * This is currently used by VDMA. It is invisible for Vdma API clients since
1203 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1204 * transport for DMA commands submission
1205 */
1206
1207#ifdef VBOXVDMA_WITH_VBVA
1208static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1209{
1210 int rc;
1211 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1212 {
1213 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1214 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1215 }
1216 else
1217 {
1218 AssertBreakpoint();
1219 rc = VERR_INVALID_STATE;
1220 }
1221 return rc;
1222}
1223#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1224#else
1225static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1226{
1227 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1228 return VINF_SUCCESS;
1229}
1230#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1231#endif
1232
1233static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1234{
1235 int rc = VINF_SUCCESS;
1236
1237 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1238 if (pCmd)
1239 {
1240 pCmd->enmCtl = enmCtl;
1241 pCmd->u32Offset = pInfo->CmdHeap.Heap.area.offBase;
1242 pCmd->i32Result = VERR_NOT_SUPPORTED;
1243
1244 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1245 Assert(pHdr);
1246 if (pHdr)
1247 {
1248 do
1249 {
1250 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1251 Assert(offCmd != HGSMIOFFSET_VOID);
1252 if (offCmd != HGSMIOFFSET_VOID)
1253 {
1254 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1255 AssertRC(rc);
1256 if (RT_SUCCESS(rc))
1257 {
1258 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1259 AssertRC(rc);
1260 if (RT_SUCCESS(rc))
1261 {
1262 rc = pCmd->i32Result;
1263 AssertRC(rc);
1264 }
1265 break;
1266 }
1267 }
1268 else
1269 rc = VERR_INVALID_PARAMETER;
1270 /* fail to submit, cancel it */
1271 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1272 } while (0);
1273 }
1274
1275 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1276 }
1277 else
1278 {
1279 LOGREL(("HGSMIHeapAlloc failed"));
1280 rc = VERR_OUT_OF_RESOURCES;
1281 }
1282
1283 return rc;
1284}
1285#endif
1286
1287/* create a DMACommand buffer */
1288int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1289#ifdef VBOX_WITH_VDMA
1290 , ULONG offBuffer, ULONG cbBuffer
1291#endif
1292 )
1293{
1294 int rc;
1295 pInfo->fEnabled = FALSE;
1296
1297#ifdef VBOX_WITH_VDMA
1298 Assert((offBuffer & 0xfff) == 0);
1299 Assert((cbBuffer & 0xfff) == 0);
1300 Assert(offBuffer);
1301 Assert(cbBuffer);
1302
1303 if((offBuffer & 0xfff)
1304 || (cbBuffer & 0xfff)
1305 || !offBuffer
1306 || !cbBuffer)
1307 {
1308 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1309 return VERR_INVALID_PARAMETER;
1310 }
1311 PVOID pvBuffer;
1312
1313 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1314 &pvBuffer,
1315 offBuffer,
1316 cbBuffer);
1317 Assert(RT_SUCCESS(rc));
1318 if (RT_SUCCESS(rc))
1319 {
1320 /* Setup a HGSMI heap within the adapter information area. */
1321 rc = VBoxSHGSMIInit(&pInfo->CmdHeap,
1322 pvBuffer,
1323 cbBuffer,
1324 offBuffer,
1325 false /*fOffsetBased*/);
1326 Assert(RT_SUCCESS(rc));
1327 if(RT_SUCCESS(rc))
1328#endif
1329 {
1330 NTSTATUS Status = vboxVdmaGgConstruct(pDevExt);
1331 Assert(Status == STATUS_SUCCESS);
1332 if (Status == STATUS_SUCCESS)
1333 return VINF_SUCCESS;
1334 rc = VERR_GENERAL_FAILURE;
1335 }
1336#ifdef VBOX_WITH_VDMA
1337 else
1338 LOGREL(("HGSMIHeapSetup failed rc = 0x%x", rc));
1339
1340 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), &pvBuffer);
1341 }
1342 else
1343 LOGREL(("VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
1344#endif
1345 return rc;
1346}
1347
1348int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1349{
1350 LOGF(("."));
1351
1352 Assert(pInfo->fEnabled);
1353 if (!pInfo->fEnabled)
1354 return VINF_ALREADY_INITIALIZED;
1355
1356 /* ensure nothing else is submitted */
1357 pInfo->fEnabled = FALSE;
1358#ifdef VBOX_WITH_VDMA
1359 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1360 AssertRC(rc);
1361 return rc;
1362#else
1363 return VINF_SUCCESS;
1364#endif
1365}
1366
1367int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1368{
1369 LOGF(("."));
1370
1371 Assert(!pInfo->fEnabled);
1372 if (pInfo->fEnabled)
1373 return VINF_ALREADY_INITIALIZED;
1374#ifdef VBOX_WITH_VDMA
1375 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1376 Assert(RT_SUCCESS(rc));
1377 if (RT_SUCCESS(rc))
1378 pInfo->fEnabled = TRUE;
1379
1380 return rc;
1381#else
1382 return VINF_SUCCESS;
1383#endif
1384}
1385
1386#ifdef VBOX_WITH_VDMA
1387int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1388{
1389 LOGF(("."));
1390
1391 Assert(pInfo->fEnabled);
1392 if (!pInfo->fEnabled)
1393 return VINF_ALREADY_INITIALIZED;
1394
1395 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1396 Assert(RT_SUCCESS(rc));
1397
1398 return rc;
1399}
1400#endif
1401
1402int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1403{
1404 int rc = VINF_SUCCESS;
1405 NTSTATUS Status = vboxVdmaGgDestruct(pDevExt);
1406 Assert(Status == STATUS_SUCCESS);
1407 if (Status == STATUS_SUCCESS)
1408 {
1409 Assert(!pInfo->fEnabled);
1410 if (pInfo->fEnabled)
1411 rc = vboxVdmaDisable (pDevExt, pInfo);
1412#ifdef VBOX_WITH_VDMA
1413 VBoxSHGSMITerm(&pInfo->CmdHeap);
1414 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base);
1415#endif
1416 }
1417 else
1418 rc = VERR_GENERAL_FAILURE;
1419 return rc;
1420}
1421
1422#ifdef VBOX_WITH_VDMA
1423void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1424{
1425 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1426}
1427
1428PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1429{
1430 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1431 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1432 Assert(pDr);
1433 if (pDr)
1434 memset (pDr, 0, cbDr);
1435 else
1436 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1437
1438 return pDr;
1439}
1440
1441static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext)
1442{
1443 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1444 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1445
1446 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1447}
1448
1449static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext,
1450 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
1451{
1452 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1453 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1454 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1455
1456 DXGK_INTERRUPT_TYPE enmComplType;
1457
1458 if (RT_SUCCESS(pDr->rc))
1459 {
1460 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1461 }
1462 else if (pDr->rc == VERR_INTERRUPTED)
1463 {
1464 Assert(0);
1465 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1466 }
1467 else
1468 {
1469 Assert(0);
1470 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1471 }
1472
1473 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1474 {
1475 pDevExt->bNotifyDxDpc = TRUE;
1476 }
1477
1478 /* inform SHGSMI we DO NOT want to be called at DPC later */
1479 *ppfnCompletion = NULL;
1480// *ppvCompletion = pvContext;
1481}
1482
1483int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1484{
1485 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1486 Assert(pHdr);
1487 int rc = VERR_GENERAL_FAILURE;
1488 if (pHdr)
1489 {
1490 do
1491 {
1492 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1493 Assert(offCmd != HGSMIOFFSET_VOID);
1494 if (offCmd != HGSMIOFFSET_VOID)
1495 {
1496 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1497 AssertRC(rc);
1498 if (RT_SUCCESS(rc))
1499 {
1500 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1501 AssertRC(rc);
1502 break;
1503 }
1504 }
1505 else
1506 rc = VERR_INVALID_PARAMETER;
1507 /* fail to submit, cancel it */
1508 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1509 } while (0);
1510 }
1511 else
1512 rc = VERR_INVALID_PARAMETER;
1513 return rc;
1514}
1515
1516int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1517{
1518 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1519 Assert(pHdr);
1520 int rc = VERR_GENERAL_FAILURE;
1521 if (pHdr)
1522 {
1523 do
1524 {
1525 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1526 Assert(offCmd != HGSMIOFFSET_VOID);
1527 if (offCmd != HGSMIOFFSET_VOID)
1528 {
1529 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1530 AssertRC(rc);
1531 if (RT_SUCCESS(rc))
1532 {
1533 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1534 AssertRC(rc);
1535 break;
1536 }
1537 }
1538 else
1539 rc = VERR_INVALID_PARAMETER;
1540 /* fail to submit, cancel it */
1541 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1542 } while (0);
1543 }
1544 else
1545 rc = VERR_INVALID_PARAMETER;
1546 return rc;
1547}
1548#endif
1549
1550
1551/* ddi dma command queue */
1552
1553VOID vboxVdmaDdiCmdGetCompletedListIsr(PVBOXMP_DEVEXT pDevExt, LIST_ENTRY *pList)
1554{
1555 vboxVideoLeDetach(&pDevExt->DpcCmdQueue, pList);
1556}
1557
1558BOOLEAN vboxVdmaDdiCmdIsCompletedListEmptyIsr(PVBOXMP_DEVEXT pDevExt)
1559{
1560 return IsListEmpty(&pDevExt->DpcCmdQueue);
1561}
1562
1563DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
1564{
1565 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
1566 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1567}
1568
1569DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1570{
1571 vboxWddmMemFree(pCmd);
1572}
1573
1574static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1575{
1576 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
1577 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1578 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1579 switch (enmComplType)
1580 {
1581 case DXGK_INTERRUPT_DMA_COMPLETED:
1582 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1583 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
1584 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
1585 pNode->uLastCompletedFenceId = u32FenceId;
1586 break;
1587
1588 case DXGK_INTERRUPT_DMA_PREEMPTED:
1589 Assert(0);
1590 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1591 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
1592 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
1593 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
1594 break;
1595
1596 case DXGK_INTERRUPT_DMA_FAULTED:
1597 Assert(0);
1598 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1599 notify.DmaFaulted.FaultedFenceId = u32FenceId;
1600 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1601 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
1602 break;
1603
1604 default:
1605 Assert(0);
1606 break;
1607 }
1608
1609 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1610}
1611
1612static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1613{
1614 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
1615 switch (enmComplType)
1616 {
1617 case DXGK_INTERRUPT_DMA_COMPLETED:
1618 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1619 break;
1620 default:
1621 AssertFailed();
1622 break;
1623 }
1624}
1625
1626DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1627{
1628 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1629 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1630 RemoveEntryList(&pCmd->QueueEntry);
1631}
1632
1633DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1634{
1635 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1636 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1637 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1638}
1639
1640VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
1641{
1642 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
1643 {
1644 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
1645 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
1646 pQueue->cQueuedCmds = 0;
1647 InitializeListHead(&pQueue->CmdQueue);
1648 }
1649 InitializeListHead(&pDevExt->DpcCmdQueue);
1650}
1651
1652BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1653{
1654 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1655 {
1656 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1657 return FALSE;
1658 }
1659
1660 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1661 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1662 BOOLEAN bComplete = FALSE;
1663 Assert(!bQueued || pQueue->cQueuedCmds);
1664 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1665 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1666 if (bQueued)
1667 {
1668 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1669 {
1670 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1671 bComplete = TRUE;
1672 }
1673 }
1674 else if (IsListEmpty(&pQueue->CmdQueue))
1675 {
1676 bComplete = TRUE;
1677 }
1678 else
1679 {
1680 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1681 }
1682
1683 if (bComplete)
1684 {
1685 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
1686
1687 while (!IsListEmpty(&pQueue->CmdQueue))
1688 {
1689 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1690 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1691 {
1692 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1693 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
1694 }
1695 else
1696 break;
1697 }
1698 }
1699 else
1700 {
1701 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1702 pCmd->enmComplType = enmComplType;
1703 }
1704
1705 return bComplete;
1706}
1707
1708VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1709{
1710 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
1711 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
1712 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
1713 if (!bQueued)
1714 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1715}
1716
1717typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
1718{
1719 PVBOXMP_DEVEXT pDevExt;
1720 PVBOXVDMADDI_CMD pCmd;
1721 DXGK_INTERRUPT_TYPE enmComplType;
1722} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
1723
1724static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
1725{
1726 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
1727 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1728 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
1729 pDevExt->bNotifyDxDpc |= bNeedDpc;
1730
1731 if (bNeedDpc)
1732 {
1733 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1734 }
1735
1736 return bNeedDpc;
1737}
1738
1739NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1740{
1741 VBOXVDMADDI_CMD_COMPLETED_CB context;
1742 context.pDevExt = pDevExt;
1743 context.pCmd = pCmd;
1744 context.enmComplType = enmComplType;
1745 BOOLEAN bNeedDps;
1746 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1747 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1748 vboxVdmaDdiCmdCompletedCb,
1749 &context,
1750 0, /* IN ULONG MessageNumber */
1751 &bNeedDps);
1752 Assert(Status == STATUS_SUCCESS);
1753 return Status;
1754}
1755
1756typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
1757{
1758 PVBOXMP_DEVEXT pDevExt;
1759 PVBOXVDMADDI_CMD pCmd;
1760} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
1761
1762static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
1763{
1764 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
1765 vboxVdmaDdiCmdSubmittedIrq(pdc->pDevExt, pdc->pCmd);
1766
1767 return FALSE;
1768}
1769
1770NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1771{
1772 VBOXVDMADDI_CMD_SUBMITTED_CB context;
1773 context.pDevExt = pDevExt;
1774 context.pCmd = pCmd;
1775 BOOLEAN bRc;
1776 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1777 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1778 vboxVdmaDdiCmdSubmittedCb,
1779 &context,
1780 0, /* IN ULONG MessageNumber */
1781 &bRc);
1782 Assert(Status == STATUS_SUCCESS);
1783 return Status;
1784}
1785
1786typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
1787{
1788 PVBOXMP_DEVEXT pDevExt;
1789 UINT u32NodeOrdinal;
1790 uint32_t u32FenceId;
1791} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
1792
1793static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
1794{
1795 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
1796 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1797
1798 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
1799
1800 pDevExt->bNotifyDxDpc = TRUE;
1801 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1802
1803 return TRUE;
1804}
1805
1806static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
1807{
1808 VBOXVDMADDI_CMD_COMPLETE_CB context;
1809 context.pDevExt = pDevExt;
1810 context.u32NodeOrdinal = u32NodeOrdinal;
1811 context.u32FenceId = u32FenceId;
1812 BOOLEAN bRet;
1813 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1814 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1815 vboxVdmaDdiCmdFenceCompleteCb,
1816 &context,
1817 0, /* IN ULONG MessageNumber */
1818 &bRet);
1819 Assert(Status == STATUS_SUCCESS);
1820 return Status;
1821}
1822
1823NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1824{
1825 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
1826 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
1827
1828 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
1829 Assert(pCmd);
1830 if (pCmd)
1831 {
1832 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
1833 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
1834 Assert(Status == STATUS_SUCCESS);
1835 if (Status == STATUS_SUCCESS)
1836 return STATUS_SUCCESS;
1837 vboxWddmMemFree(pCmd);
1838 return Status;
1839 }
1840 return STATUS_NO_MEMORY;
1841}
1842
1843#ifdef VBOXWDDM_RENDER_FROM_SHADOW
1844NTSTATUS vboxVdmaHlpUpdatePrimary(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT* pRect)
1845{
1846 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1847 Assert(pSource->pPrimaryAllocation);
1848 Assert(pSource->pShadowAllocation);
1849 if (!pSource->pPrimaryAllocation)
1850 return STATUS_INVALID_PARAMETER;
1851 if (!pSource->pShadowAllocation)
1852 return STATUS_INVALID_PARAMETER;
1853
1854 Assert(pSource->pPrimaryAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1855 Assert(pSource->pShadowAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1856 if (pSource->pPrimaryAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1857 return STATUS_INVALID_PARAMETER;
1858 if (pSource->pShadowAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1859 return STATUS_INVALID_PARAMETER;
1860
1861 NTSTATUS Status = vboxVdmaGgDmaBltPerform(pDevExt, pSource->pShadowAllocation, pRect, pSource->pPrimaryAllocation, pRect);
1862 Assert(Status == STATUS_SUCCESS);
1863 return Status;
1864}
1865#endif
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