VirtualBox

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

Last change on this file since 41638 was 41638, checked in by vboxsync, 12 years ago

wddm: vsync support fixes + missing commit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.5 KB
Line 
1/* $Id: VBoxMPVdma.cpp 41638 2012-06-09 16:58:09Z 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 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
812 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->SurfDesc.VidPnSourceId];
813 vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->SurfDesc.VidPnSourceId);
814 if (pFlip->Hdr.fFlags.fVisibleRegions)
815 {
816 Status = STATUS_MORE_PROCESSING_REQUIRED;
817 vboxWddmAllocationRetain(pFlip->Flip.Alloc.pAlloc);
818 }
819
820 break;
821 }
822 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
823 {
824 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDmaCmd;
825 Assert(pCF->Hdr.fFlags.fRealOp);
826 Assert(!pCF->Hdr.fFlags.fVisibleRegions);
827 Status = vboxVdmaGgDmaColorFill(pDevExt, pCF);
828 Assert(Status == STATUS_SUCCESS);
829 break;
830 }
831
832 default:
833 Assert(0);
834 break;
835 }
836
837 /* Corresponding Release is done by dma command completion handler */
838 vboxVdmaGgCmdAddRef(&pDmaCmd->Hdr);
839
840 NTSTATUS tmpStatus = vboxVdmaGgCmdDmaNotifyCompleted(pDevExt, pDmaCmd, enmComplType);
841 if (!NT_SUCCESS(tmpStatus))
842 {
843 WARN(("vboxVdmaGgCmdDmaNotifyCompleted failed, Status 0x%x", tmpStatus));
844 /* the command was NOT submitted, and thus will not be released, release it here */
845 vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr);
846 Status = tmpStatus;
847 }
848
849 return Status;
850}
851
852static NTSTATUS vboxVdmaGgDmaCmdProcessSlow(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd)
853{
854 NTSTATUS Status = STATUS_SUCCESS;
855 PVBOXWDDM_CONTEXT pContext = pDmaCmd->pContext;
856 DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
857
858 Assert(pDmaCmd->fFlags.Value);
859 Assert(!pDmaCmd->fFlags.fRealOp);
860
861 switch (pDmaCmd->enmCmd)
862 {
863 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
864 {
865 PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd;
866 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
867 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
868 BOOLEAN bComplete = TRUE;
869 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->SurfDesc.VidPnSourceId];
870 Assert(pDstAlloc->SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
871
872 if (pBlt->Hdr.fFlags.fVisibleRegions)
873 {
874 PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc);
875 POINT pos = pSource->VScreenPos;
876 if (pos.x || pos.y)
877 {
878 /* note: do NOT translate the src rect since it is used for screen pos calculation */
879 vboxWddmBltPipeRectsTranslate(&pBlt->Blt.DstRects, pos.x, pos.y);
880 }
881
882 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects);
883 Assert(Status == STATUS_SUCCESS);
884
885 if (pSwapchain)
886 vboxWddmSwapchainRelease(pSwapchain);
887 }
888 else
889 {
890 WARN(("not expected!"));
891 }
892
893 vboxWddmAllocationRelease(pDstAlloc);
894 vboxWddmAllocationRelease(pSrcAlloc);
895
896 break;
897 }
898
899 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
900 {
901 PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd;
902 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
903 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->SurfDesc.VidPnSourceId];
904 if (pFlip->Hdr.fFlags.fVisibleRegions)
905 {
906 PVBOXWDDM_SWAPCHAIN pSwapchain;
907 pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pAlloc);
908 if (pSwapchain)
909 {
910 POINT pos = pSource->VScreenPos;
911 RECT SrcRect;
912 VBOXVDMAPIPE_RECTS Rects;
913 SrcRect.left = 0;
914 SrcRect.top = 0;
915 SrcRect.right = pAlloc->SurfDesc.width;
916 SrcRect.bottom = pAlloc->SurfDesc.height;
917 Rects.ContextRect.left = pos.x;
918 Rects.ContextRect.top = pos.y;
919 Rects.ContextRect.right = pAlloc->SurfDesc.width + pos.x;
920 Rects.ContextRect.bottom = pAlloc->SurfDesc.height + pos.y;
921 Rects.UpdateRects.cRects = 1;
922 Rects.UpdateRects.aRects[0] = Rects.ContextRect;
923 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &SrcRect, &Rects);
924 Assert(Status == STATUS_SUCCESS);
925 vboxWddmSwapchainRelease(pSwapchain);
926 }
927 }
928 else
929 {
930 WARN(("not expected!"));
931 }
932
933 vboxWddmAllocationRelease(pAlloc);
934
935 break;
936 }
937
938 default:
939 {
940 WARN(("not expected!"));
941 break;
942 }
943 }
944
945 vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr);
946
947 return Status;
948}
949
950static DECLCALLBACK(UINT) vboxVdmaGgCmdCancelVisitor(PVBOXVIDEOCM_CTX pContext, PVOID pvCmd, uint32_t cbCmd, PVOID pvVisitor)
951{
952 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)pvVisitor;
953 if (!pSwapchain)
954 return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD;
955 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)pvCmd;
956 if (pCmdInternal->hSwapchainUm == pSwapchain->hSwapchainUm)
957 return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD;
958 return 0;
959}
960
961static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
962{
963 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvUser;
964 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
965
966 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
967 Assert(Status == STATUS_SUCCESS);
968 if (Status == STATUS_SUCCESS)
969 {
970 do
971 {
972 LIST_ENTRY CmdList;
973 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
974 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
975 if (Status == STATUS_SUCCESS)
976 {
977 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList;)
978 {
979 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
980 RemoveEntryList(pCur);
981 pCur = CmdList.Blink;
982 switch (pDr->enmType)
983 {
984 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
985 {
986 PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pDr;
987 Status = vboxVdmaGgDmaCmdProcessSlow(pDevExt, pDmaCmd);
988 Assert(Status == STATUS_SUCCESS);
989 } break;
990#if 0
991 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
992 {
993 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
994 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pRects->pContext, pRects->pSwapchain, &pRects->ContextsRects);
995 Assert(Status == STATUS_SUCCESS);
996 vboxVdmaGgCmdRelease(pDevExt, pDr);
997 break;
998 }
999#endif
1000 case VBOXVDMAPIPE_CMD_TYPE_FINISH:
1001 {
1002 PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)pDr;
1003 PVBOXWDDM_CONTEXT pContext = pCmd->pContext;
1004 Assert(pCmd->pEvent);
1005 Status = vboxVideoCmCmdSubmitCompleteEvent(&pContext->CmContext, pCmd->pEvent);
1006 if (Status != STATUS_SUCCESS)
1007 {
1008 WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status));
1009 }
1010 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1011 break;
1012 }
1013 case VBOXVDMAPIPE_CMD_TYPE_CANCEL:
1014 {
1015 PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)pDr;
1016 PVBOXWDDM_CONTEXT pContext = pCmd->pContext;
1017 Status = vboxVideoCmCmdVisit(&pContext->CmContext, FALSE, vboxVdmaGgCmdCancelVisitor, pCmd->pSwapchain);
1018 if (Status != STATUS_SUCCESS)
1019 {
1020 WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status));
1021 }
1022 Assert(pCmd->pEvent);
1023 KeSetEvent(pCmd->pEvent, 0, FALSE);
1024 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1025 break;
1026 }
1027 default:
1028 AssertBreakpoint();
1029 }
1030 }
1031 }
1032 else
1033 break;
1034 } while (1);
1035 }
1036
1037 /* always try to close the pipe to make sure the client side is notified */
1038 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
1039 Assert(Status == STATUS_SUCCESS);
1040}
1041
1042NTSTATUS vboxVdmaGgConstruct(PVBOXMP_DEVEXT pDevExt)
1043{
1044 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
1045 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
1046 Assert(Status == STATUS_SUCCESS);
1047 if (Status == STATUS_SUCCESS)
1048 {
1049 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pDevExt);
1050 Assert(Status == STATUS_SUCCESS);
1051 if (Status == STATUS_SUCCESS)
1052 return STATUS_SUCCESS;
1053
1054 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
1055 Assert(tmpStatus == STATUS_SUCCESS);
1056 }
1057
1058 /* we're here ONLY in case of an error */
1059 Assert(Status != STATUS_SUCCESS);
1060 return Status;
1061}
1062
1063NTSTATUS vboxVdmaGgDestruct(PVBOXMP_DEVEXT pDevExt)
1064{
1065 PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg;
1066 /* this informs the server thread that it should complete all current commands and exit */
1067 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
1068 Assert(Status == STATUS_SUCCESS);
1069 if (Status == STATUS_SUCCESS)
1070 {
1071 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
1072 Assert(Status == STATUS_SUCCESS);
1073 if (Status == STATUS_SUCCESS)
1074 {
1075 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
1076 Assert(Status == STATUS_SUCCESS);
1077 }
1078 }
1079
1080 return Status;
1081}
1082
1083NTSTATUS vboxVdmaGgCmdSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pCmd)
1084{
1085 switch (pCmd->enmType)
1086 {
1087 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
1088 {
1089 PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pCmd;
1090 NTSTATUS Status = vboxVdmaGgDmaCmdProcessFast(pDevExt, pDmaCmd);
1091 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
1092 break;
1093 return Status;
1094 }
1095 default:
1096 break;
1097 }
1098 /* correspondinf Release is done by the pipe command handler */
1099 vboxVdmaGgCmdAddRef(pCmd);
1100 return vboxVdmaPipeCltCmdPut(&pDevExt->u.primary.Vdma.DmaGg.CmdPipe, &pCmd->PipeHdr);
1101}
1102
1103NTSTATUS vboxVdmaGgCmdDmaNotifySubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd)
1104{
1105 PVBOXVDMADDI_CMD pDdiCmd;
1106#ifdef VBOX_WDDM_IRQ_COMPLETION
1107 pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd);
1108#else
1109 pDdiCmd = &pCmd->DdiCmd;
1110#endif
1111 NTSTATUS Status = vboxVdmaDdiCmdSubmitted(pDevExt, pDdiCmd);
1112 Assert(Status == STATUS_SUCCESS);
1113 return Status;
1114}
1115
1116NTSTATUS vboxVdmaGgCmdDmaNotifyCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1117{
1118#ifdef VBOX_WDDM_IRQ_COMPLETION
1119 VBOXVDMACBUF_DR* pDr = vboxVdmaGgCmdDmaGetDr(pCmd);
1120 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1121 Assert(rc == VINF_SUCCESS);
1122 if (RT_SUCCESS(rc))
1123 {
1124 return STATUS_SUCCESS;
1125 }
1126 return STATUS_UNSUCCESSFUL;
1127#else
1128 return vboxVdmaDdiCmdCompleted(pDevExt, &pCmd->DdiCmd, enmComplType);
1129#endif
1130}
1131
1132VOID vboxVdmaGgCmdDmaNotifyInit(PVBOXVDMAPIPE_CMD_DMACMD pCmd,
1133 uint32_t u32NodeOrdinal, uint32_t u32FenceId,
1134 PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete, PVOID pvComplete)
1135{
1136 PVBOXVDMADDI_CMD pDdiCmd;
1137#ifdef VBOX_WDDM_IRQ_COMPLETION
1138 pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd);
1139#else
1140 pDdiCmd = &pCmd->DdiCmd;
1141#endif
1142 vboxVdmaDdiCmdInit(pDdiCmd, u32NodeOrdinal, u32FenceId, pfnComplete, pvComplete);
1143}
1144
1145NTSTATUS vboxVdmaGgCmdFinish(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PKEVENT pEvent)
1146{
1147 NTSTATUS Status = STATUS_SUCCESS;
1148
1149 PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_FINISH, sizeof (*pCmd));
1150 if (pCmd)
1151 {
1152 pCmd->pContext = pContext;
1153 pCmd->pEvent = pEvent;
1154 Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr);
1155 if (!NT_SUCCESS(Status))
1156 {
1157 WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status));
1158 }
1159 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1160 }
1161 else
1162 {
1163 WARN(("vboxVdmaGgCmdCreate failed"));
1164 Status = STATUS_NO_MEMORY;
1165 }
1166 return Status;
1167}
1168
1169NTSTATUS vboxVdmaGgCmdCancel(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
1170{
1171 NTSTATUS Status = STATUS_SUCCESS;
1172
1173 PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_CANCEL, sizeof (*pCmd));
1174 if (pCmd)
1175 {
1176 KEVENT Event;
1177 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1178 pCmd->pContext = pContext;
1179 pCmd->pSwapchain = pSwapchain;
1180 pCmd->pEvent = &Event;
1181 Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr);
1182 if (NT_SUCCESS(Status))
1183 {
1184 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1185 Assert(Status == STATUS_SUCCESS);
1186 }
1187 else
1188 {
1189 WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status));
1190 }
1191 vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr);
1192 }
1193 else
1194 {
1195 WARN(("vboxVdmaGgCmdCreate failed"));
1196 Status = STATUS_NO_MEMORY;
1197 }
1198 return Status;
1199}
1200
1201/* end */
1202
1203#ifdef VBOX_WITH_VDMA
1204/*
1205 * This is currently used by VDMA. It is invisible for Vdma API clients since
1206 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1207 * transport for DMA commands submission
1208 */
1209
1210#ifdef VBOXVDMA_WITH_VBVA
1211static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1212{
1213 int rc;
1214 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1215 {
1216 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1217 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1218 }
1219 else
1220 {
1221 AssertBreakpoint();
1222 rc = VERR_INVALID_STATE;
1223 }
1224 return rc;
1225}
1226#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1227#else
1228static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1229{
1230 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1231 return VINF_SUCCESS;
1232}
1233#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1234#endif
1235
1236static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1237{
1238 int rc = VINF_SUCCESS;
1239
1240 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1241 if (pCmd)
1242 {
1243 pCmd->enmCtl = enmCtl;
1244 pCmd->u32Offset = pInfo->CmdHeap.Heap.area.offBase;
1245 pCmd->i32Result = VERR_NOT_SUPPORTED;
1246
1247 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1248 Assert(pHdr);
1249 if (pHdr)
1250 {
1251 do
1252 {
1253 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1254 Assert(offCmd != HGSMIOFFSET_VOID);
1255 if (offCmd != HGSMIOFFSET_VOID)
1256 {
1257 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1258 AssertRC(rc);
1259 if (RT_SUCCESS(rc))
1260 {
1261 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1262 AssertRC(rc);
1263 if (RT_SUCCESS(rc))
1264 {
1265 rc = pCmd->i32Result;
1266 AssertRC(rc);
1267 }
1268 break;
1269 }
1270 }
1271 else
1272 rc = VERR_INVALID_PARAMETER;
1273 /* fail to submit, cancel it */
1274 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1275 } while (0);
1276 }
1277
1278 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1279 }
1280 else
1281 {
1282 LOGREL(("HGSMIHeapAlloc failed"));
1283 rc = VERR_OUT_OF_RESOURCES;
1284 }
1285
1286 return rc;
1287}
1288#endif
1289
1290/* create a DMACommand buffer */
1291int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1292#ifdef VBOX_WITH_VDMA
1293 , ULONG offBuffer, ULONG cbBuffer
1294#endif
1295 )
1296{
1297 int rc;
1298 pInfo->fEnabled = FALSE;
1299
1300#ifdef VBOX_WITH_VDMA
1301 Assert((offBuffer & 0xfff) == 0);
1302 Assert((cbBuffer & 0xfff) == 0);
1303 Assert(offBuffer);
1304 Assert(cbBuffer);
1305
1306 if((offBuffer & 0xfff)
1307 || (cbBuffer & 0xfff)
1308 || !offBuffer
1309 || !cbBuffer)
1310 {
1311 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1312 return VERR_INVALID_PARAMETER;
1313 }
1314 PVOID pvBuffer;
1315
1316 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1317 &pvBuffer,
1318 offBuffer,
1319 cbBuffer);
1320 Assert(RT_SUCCESS(rc));
1321 if (RT_SUCCESS(rc))
1322 {
1323 /* Setup a HGSMI heap within the adapter information area. */
1324 rc = VBoxSHGSMIInit(&pInfo->CmdHeap,
1325 pvBuffer,
1326 cbBuffer,
1327 offBuffer,
1328 false /*fOffsetBased*/);
1329 Assert(RT_SUCCESS(rc));
1330 if(RT_SUCCESS(rc))
1331#endif
1332 {
1333 NTSTATUS Status = vboxVdmaGgConstruct(pDevExt);
1334 Assert(Status == STATUS_SUCCESS);
1335 if (Status == STATUS_SUCCESS)
1336 return VINF_SUCCESS;
1337 rc = VERR_GENERAL_FAILURE;
1338 }
1339#ifdef VBOX_WITH_VDMA
1340 else
1341 LOGREL(("HGSMIHeapSetup failed rc = 0x%x", rc));
1342
1343 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), &pvBuffer);
1344 }
1345 else
1346 LOGREL(("VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
1347#endif
1348 return rc;
1349}
1350
1351int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1352{
1353 LOGF(("."));
1354
1355 Assert(pInfo->fEnabled);
1356 if (!pInfo->fEnabled)
1357 return VINF_ALREADY_INITIALIZED;
1358
1359 /* ensure nothing else is submitted */
1360 pInfo->fEnabled = FALSE;
1361#ifdef VBOX_WITH_VDMA
1362 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1363 AssertRC(rc);
1364 return rc;
1365#else
1366 return VINF_SUCCESS;
1367#endif
1368}
1369
1370int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1371{
1372 LOGF(("."));
1373
1374 Assert(!pInfo->fEnabled);
1375 if (pInfo->fEnabled)
1376 return VINF_ALREADY_INITIALIZED;
1377#ifdef VBOX_WITH_VDMA
1378 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1379 Assert(RT_SUCCESS(rc));
1380 if (RT_SUCCESS(rc))
1381 pInfo->fEnabled = TRUE;
1382
1383 return rc;
1384#else
1385 return VINF_SUCCESS;
1386#endif
1387}
1388
1389#ifdef VBOX_WITH_VDMA
1390int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1391{
1392 LOGF(("."));
1393
1394 Assert(pInfo->fEnabled);
1395 if (!pInfo->fEnabled)
1396 return VINF_ALREADY_INITIALIZED;
1397
1398 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1399 Assert(RT_SUCCESS(rc));
1400
1401 return rc;
1402}
1403#endif
1404
1405int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1406{
1407 int rc = VINF_SUCCESS;
1408 NTSTATUS Status = vboxVdmaGgDestruct(pDevExt);
1409 Assert(Status == STATUS_SUCCESS);
1410 if (Status == STATUS_SUCCESS)
1411 {
1412 Assert(!pInfo->fEnabled);
1413 if (pInfo->fEnabled)
1414 rc = vboxVdmaDisable (pDevExt, pInfo);
1415#ifdef VBOX_WITH_VDMA
1416 VBoxSHGSMITerm(&pInfo->CmdHeap);
1417 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base);
1418#endif
1419 }
1420 else
1421 rc = VERR_GENERAL_FAILURE;
1422 return rc;
1423}
1424
1425#ifdef VBOX_WITH_VDMA
1426void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1427{
1428 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1429}
1430
1431PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1432{
1433 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1434 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1435 Assert(pDr);
1436 if (pDr)
1437 memset (pDr, 0, cbDr);
1438 else
1439 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1440
1441 return pDr;
1442}
1443
1444static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext)
1445{
1446 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1447 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1448
1449 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1450}
1451
1452static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext,
1453 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
1454{
1455 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1456 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1457 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1458
1459 DXGK_INTERRUPT_TYPE enmComplType;
1460
1461 if (RT_SUCCESS(pDr->rc))
1462 {
1463 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1464 }
1465 else if (pDr->rc == VERR_INTERRUPTED)
1466 {
1467 Assert(0);
1468 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1469 }
1470 else
1471 {
1472 Assert(0);
1473 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1474 }
1475
1476 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1477 {
1478 pDevExt->bNotifyDxDpc = TRUE;
1479 }
1480
1481 /* inform SHGSMI we DO NOT want to be called at DPC later */
1482 *ppfnCompletion = NULL;
1483// *ppvCompletion = pvContext;
1484}
1485
1486int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1487{
1488 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1489 Assert(pHdr);
1490 int rc = VERR_GENERAL_FAILURE;
1491 if (pHdr)
1492 {
1493 do
1494 {
1495 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1496 Assert(offCmd != HGSMIOFFSET_VOID);
1497 if (offCmd != HGSMIOFFSET_VOID)
1498 {
1499 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1500 AssertRC(rc);
1501 if (RT_SUCCESS(rc))
1502 {
1503 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1504 AssertRC(rc);
1505 break;
1506 }
1507 }
1508 else
1509 rc = VERR_INVALID_PARAMETER;
1510 /* fail to submit, cancel it */
1511 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1512 } while (0);
1513 }
1514 else
1515 rc = VERR_INVALID_PARAMETER;
1516 return rc;
1517}
1518
1519int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1520{
1521 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1522 Assert(pHdr);
1523 int rc = VERR_GENERAL_FAILURE;
1524 if (pHdr)
1525 {
1526 do
1527 {
1528 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1529 Assert(offCmd != HGSMIOFFSET_VOID);
1530 if (offCmd != HGSMIOFFSET_VOID)
1531 {
1532 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1533 AssertRC(rc);
1534 if (RT_SUCCESS(rc))
1535 {
1536 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1537 AssertRC(rc);
1538 break;
1539 }
1540 }
1541 else
1542 rc = VERR_INVALID_PARAMETER;
1543 /* fail to submit, cancel it */
1544 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1545 } while (0);
1546 }
1547 else
1548 rc = VERR_INVALID_PARAMETER;
1549 return rc;
1550}
1551#endif
1552
1553
1554/* ddi dma command queue */
1555
1556VOID vboxVdmaDdiCmdGetCompletedListIsr(PVBOXMP_DEVEXT pDevExt, LIST_ENTRY *pList)
1557{
1558 vboxVideoLeDetach(&pDevExt->DpcCmdQueue, pList);
1559}
1560
1561BOOLEAN vboxVdmaDdiCmdIsCompletedListEmptyIsr(PVBOXMP_DEVEXT pDevExt)
1562{
1563 return IsListEmpty(&pDevExt->DpcCmdQueue);
1564}
1565
1566DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
1567{
1568 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
1569 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1570}
1571
1572DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1573{
1574 vboxWddmMemFree(pCmd);
1575}
1576
1577static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1578{
1579 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
1580 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1581 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1582 switch (enmComplType)
1583 {
1584 case DXGK_INTERRUPT_DMA_COMPLETED:
1585 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1586 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
1587 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
1588 pNode->uLastCompletedFenceId = u32FenceId;
1589 break;
1590
1591 case DXGK_INTERRUPT_DMA_PREEMPTED:
1592 Assert(0);
1593 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1594 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
1595 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
1596 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
1597 break;
1598
1599 case DXGK_INTERRUPT_DMA_FAULTED:
1600 Assert(0);
1601 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1602 notify.DmaFaulted.FaultedFenceId = u32FenceId;
1603 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1604 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
1605 break;
1606
1607 default:
1608 Assert(0);
1609 break;
1610 }
1611
1612 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1613}
1614
1615static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1616{
1617 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
1618 switch (enmComplType)
1619 {
1620 case DXGK_INTERRUPT_DMA_COMPLETED:
1621 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1622 break;
1623 default:
1624 AssertFailed();
1625 break;
1626 }
1627}
1628
1629DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1630{
1631 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1632 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1633 RemoveEntryList(&pCmd->QueueEntry);
1634}
1635
1636DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1637{
1638 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1639 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1640 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1641}
1642
1643VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
1644{
1645 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
1646 {
1647 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
1648 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
1649 pQueue->cQueuedCmds = 0;
1650 InitializeListHead(&pQueue->CmdQueue);
1651 }
1652 InitializeListHead(&pDevExt->DpcCmdQueue);
1653}
1654
1655BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1656{
1657 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1658 {
1659 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1660 return FALSE;
1661 }
1662
1663 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1664 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1665 BOOLEAN bComplete = FALSE;
1666 Assert(!bQueued || pQueue->cQueuedCmds);
1667 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1668 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1669 if (bQueued)
1670 {
1671 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1672 {
1673 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1674 bComplete = TRUE;
1675 }
1676 }
1677 else if (IsListEmpty(&pQueue->CmdQueue))
1678 {
1679 bComplete = TRUE;
1680 }
1681 else
1682 {
1683 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1684 }
1685
1686 if (bComplete)
1687 {
1688 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
1689
1690 while (!IsListEmpty(&pQueue->CmdQueue))
1691 {
1692 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1693 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1694 {
1695 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1696 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
1697 }
1698 else
1699 break;
1700 }
1701 }
1702 else
1703 {
1704 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1705 pCmd->enmComplType = enmComplType;
1706 }
1707
1708 return bComplete;
1709}
1710
1711VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1712{
1713 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
1714 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
1715 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
1716 if (!bQueued)
1717 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1718}
1719
1720typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
1721{
1722 PVBOXMP_DEVEXT pDevExt;
1723 PVBOXVDMADDI_CMD pCmd;
1724 DXGK_INTERRUPT_TYPE enmComplType;
1725} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
1726
1727static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
1728{
1729 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
1730 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1731 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
1732 pDevExt->bNotifyDxDpc |= bNeedDpc;
1733
1734 if (bNeedDpc)
1735 {
1736 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1737 }
1738
1739 return bNeedDpc;
1740}
1741
1742NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1743{
1744 VBOXVDMADDI_CMD_COMPLETED_CB context;
1745 context.pDevExt = pDevExt;
1746 context.pCmd = pCmd;
1747 context.enmComplType = enmComplType;
1748 BOOLEAN bNeedDps;
1749 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1750 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1751 vboxVdmaDdiCmdCompletedCb,
1752 &context,
1753 0, /* IN ULONG MessageNumber */
1754 &bNeedDps);
1755 Assert(Status == STATUS_SUCCESS);
1756 return Status;
1757}
1758
1759typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
1760{
1761 PVBOXMP_DEVEXT pDevExt;
1762 PVBOXVDMADDI_CMD pCmd;
1763} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
1764
1765static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
1766{
1767 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
1768 vboxVdmaDdiCmdSubmittedIrq(pdc->pDevExt, pdc->pCmd);
1769
1770 return FALSE;
1771}
1772
1773NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1774{
1775 VBOXVDMADDI_CMD_SUBMITTED_CB context;
1776 context.pDevExt = pDevExt;
1777 context.pCmd = pCmd;
1778 BOOLEAN bRc;
1779 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1780 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1781 vboxVdmaDdiCmdSubmittedCb,
1782 &context,
1783 0, /* IN ULONG MessageNumber */
1784 &bRc);
1785 Assert(Status == STATUS_SUCCESS);
1786 return Status;
1787}
1788
1789typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
1790{
1791 PVBOXMP_DEVEXT pDevExt;
1792 UINT u32NodeOrdinal;
1793 uint32_t u32FenceId;
1794} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
1795
1796static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
1797{
1798 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
1799 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1800
1801 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
1802
1803 pDevExt->bNotifyDxDpc = TRUE;
1804 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1805
1806 return TRUE;
1807}
1808
1809static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
1810{
1811 VBOXVDMADDI_CMD_COMPLETE_CB context;
1812 context.pDevExt = pDevExt;
1813 context.u32NodeOrdinal = u32NodeOrdinal;
1814 context.u32FenceId = u32FenceId;
1815 BOOLEAN bRet;
1816 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1817 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1818 vboxVdmaDdiCmdFenceCompleteCb,
1819 &context,
1820 0, /* IN ULONG MessageNumber */
1821 &bRet);
1822 Assert(Status == STATUS_SUCCESS);
1823 return Status;
1824}
1825
1826NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1827{
1828 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
1829 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
1830
1831 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
1832 Assert(pCmd);
1833 if (pCmd)
1834 {
1835 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
1836 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
1837 Assert(Status == STATUS_SUCCESS);
1838 if (Status == STATUS_SUCCESS)
1839 return STATUS_SUCCESS;
1840 vboxWddmMemFree(pCmd);
1841 return Status;
1842 }
1843 return STATUS_NO_MEMORY;
1844}
1845
1846#ifdef VBOXWDDM_RENDER_FROM_SHADOW
1847NTSTATUS vboxVdmaHlpUpdatePrimary(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT* pRect)
1848{
1849 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1850 Assert(pSource->pPrimaryAllocation);
1851 Assert(pSource->pShadowAllocation);
1852 if (!pSource->pPrimaryAllocation)
1853 return STATUS_INVALID_PARAMETER;
1854 if (!pSource->pShadowAllocation)
1855 return STATUS_INVALID_PARAMETER;
1856
1857 Assert(pSource->pPrimaryAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1858 Assert(pSource->pShadowAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1859 if (pSource->pPrimaryAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1860 return STATUS_INVALID_PARAMETER;
1861 if (pSource->pShadowAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1862 return STATUS_INVALID_PARAMETER;
1863
1864 NTSTATUS Status = vboxVdmaGgDmaBltPerform(pDevExt, pSource->pShadowAllocation, pRect, pSource->pPrimaryAllocation, pRect);
1865 Assert(Status == STATUS_SUCCESS);
1866 return Status;
1867}
1868#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