VirtualBox

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

Last change on this file since 36867 was 36867, checked in by vboxsync, 14 years ago

Additions/Video: display/miniport drivers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.8 KB
Line 
1/* $Id: VBoxMPVdma.cpp 36867 2011-04-28 07:27:03Z 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(PVBOXVDMAGG pVdma, VBOXVDMAPIPE_CMD_TYPE enmType, uint32_t cbCmd)
216{
217 PVBOXVDMAPIPE_CMD_DR pHdr = (PVBOXVDMAPIPE_CMD_DR)vboxWddmMemAllocZero(cbCmd);
218 Assert(pHdr);
219 if (pHdr)
220 {
221 pHdr->enmType = enmType;
222 return pHdr;
223 }
224 return NULL;
225}
226
227void vboxVdmaGgCmdDestroy(PVBOXVDMAPIPE_CMD_DR pDr)
228{
229 vboxWddmMemFree(pDr);
230}
231
232DECLCALLBACK(VOID) vboxVdmaGgDdiCmdDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
233{
234 vboxVdmaGgCmdDestroy((PVBOXVDMAPIPE_CMD_DR)pvContext);
235}
236
237/**
238 * helper function used for system thread creation
239 */
240static NTSTATUS vboxVdmaGgThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
241{
242 NTSTATUS fStatus;
243 HANDLE hThread;
244 OBJECT_ATTRIBUTES fObjectAttributes;
245
246 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
247
248 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
249 NULL, NULL);
250
251 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
252 &fObjectAttributes, NULL, NULL,
253 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
254 if (!NT_SUCCESS(fStatus))
255 return fStatus;
256
257 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
258 KernelMode, (PVOID*) ppThread, NULL);
259 ZwClose(hThread);
260 return STATUS_SUCCESS;
261}
262
263DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const PVBOXWDDM_RECTS_INFO pRects, PVBOXWDDM_RECTS_INFO pResult)
264{
265 uint32_t cRects = 0;
266 for (uint32_t i = 0; i < pRects->cRects; ++i)
267 {
268 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[cRects]))
269 {
270 ++cRects;
271 }
272 }
273
274 pResult->cRects = cRects;
275}
276
277DECLINLINE(bool) vboxVdmaDirtyRectsHasIntersections(const RECT *paRects1, uint32_t cRects1, const RECT *paRects2, uint32_t cRects2)
278{
279 RECT tmpRect;
280 for (uint32_t i = 0; i < cRects1; ++i)
281 {
282 const RECT * pRect1 = &paRects1[i];
283 for (uint32_t j = 0; j < cRects2; ++j)
284 {
285 const RECT * pRect2 = &paRects2[j];
286 if (vboxWddmRectIntersection(pRect1, pRect2, &tmpRect))
287 return true;
288 }
289 }
290 return false;
291}
292
293DECLINLINE(bool) vboxVdmaDirtyRectsIsCover(const RECT *paRects, uint32_t cRects, const RECT *paRectsCovered, uint32_t cRectsCovered)
294{
295 for (uint32_t i = 0; i < cRectsCovered; ++i)
296 {
297 const RECT * pRectCovered = &paRectsCovered[i];
298 uint32_t j = 0;
299 for (; j < cRects; ++j)
300 {
301 const RECT * pRect = &paRects[j];
302 if (vboxWddmRectIsCoveres(pRect, pRectCovered))
303 break;
304 }
305 if (j == cRects)
306 return false;
307 }
308 return true;
309}
310
311NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain)
312{
313 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
314 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(0);
315 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal =
316 (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pSwapchain->pContext->CmContext, cbCmdInternal);
317 Assert(pCmdInternal);
318 if (pCmdInternal)
319 {
320 pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
321 pCmdInternal->Cmd.fFlags.Value = 0;
322 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
323 pCmdInternal->Cmd.fFlags.bHide = 1;
324 pCmdInternal->Cmd.RectsInfo.cRects = 0;
325 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
326 return STATUS_SUCCESS;
327 }
328 return STATUS_NO_MEMORY;
329}
330
331/**
332 * @param pDevExt
333 */
334static NTSTATUS vboxVdmaGgDirtyRectsProcess(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain, VBOXVDMAPIPE_RECTS *pContextRects)
335{
336 PVBOXWDDM_RECTS_INFO pRects = &pContextRects->UpdateRects;
337 NTSTATUS Status = STATUS_SUCCESS;
338 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = NULL;
339 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects);
340 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
341 ExAcquireFastMutex(&pDevExt->ContextMutex);
342 for (PLIST_ENTRY pCur = pDevExt->SwapchainList3D.Flink; pCur != &pDevExt->SwapchainList3D; pCur = pCur->Flink)
343 {
344 if (pCur != &pSwapchain->DevExtListEntry)
345 {
346 PVBOXWDDM_SWAPCHAIN pCurSwapchain = VBOXWDDMENTRY_2_SWAPCHAIN(pCur);
347 if (!pCmdInternal)
348 {
349 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pCurSwapchain->pContext->CmContext, cbCmdInternal);
350 Assert(pCmdInternal);
351 if (!pCmdInternal)
352 {
353 Status = STATUS_NO_MEMORY;
354 break;
355 }
356 }
357 else
358 {
359 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pCurSwapchain->pContext->CmContext);
360 }
361
362 vboxVdmaDirtyRectsCalcIntersection(&pCurSwapchain->ViewRect, pRects, &pCmdInternal->Cmd.RectsInfo);
363 if (pCmdInternal->Cmd.RectsInfo.cRects)
364 {
365 bool bSend = false;
366 pCmdInternal->Cmd.fFlags.Value = 0;
367 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
368 if (pCurSwapchain->pLastReportedRects)
369 {
370 if (pCurSwapchain->pLastReportedRects->Cmd.fFlags.bSetVisibleRects)
371 {
372 RECT *paPrevRects;
373 uint32_t cPrevRects;
374 if (pCurSwapchain->pLastReportedRects->Cmd.fFlags.bSetViewRect)
375 {
376 paPrevRects = &pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[1];
377 cPrevRects = pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects - 1;
378 }
379 else
380 {
381 paPrevRects = &pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[0];
382 cPrevRects = pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects;
383 }
384
385 if (vboxVdmaDirtyRectsHasIntersections(paPrevRects, cPrevRects,
386 pCmdInternal->Cmd.RectsInfo.aRects, pCmdInternal->Cmd.RectsInfo.cRects))
387 {
388 bSend = true;
389 }
390 }
391 else
392 {
393 Assert(pCurSwapchain->pLastReportedRects->Cmd.fFlags.bAddHiddenRects);
394 if (!vboxVdmaDirtyRectsIsCover(pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects,
395 pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects,
396 pCmdInternal->Cmd.RectsInfo.aRects, pCmdInternal->Cmd.RectsInfo.cRects))
397 {
398 bSend = true;
399 }
400 }
401 }
402 else
403 bSend = true;
404
405 if (bSend)
406 {
407 if (pCurSwapchain->pLastReportedRects)
408 vboxVideoCmCmdRelease(pCurSwapchain->pLastReportedRects);
409
410 pCmdInternal->hSwapchainUm = pCurSwapchain->hSwapchainUm;
411
412 vboxVideoCmCmdRetain(pCmdInternal);
413 pCurSwapchain->pLastReportedRects = pCmdInternal;
414 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects));
415 pCmdInternal = NULL;
416 }
417 }
418 }
419 else
420 {
421 RECT * pContextRect = &pContextRects->ContextRect;
422 bool bRectShanged = (pSwapchain->ViewRect.left != pContextRect->left
423 || pSwapchain->ViewRect.top != pContextRect->top
424 || pSwapchain->ViewRect.right != pContextRect->right
425 || pSwapchain->ViewRect.bottom != pContextRect->bottom);
426 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pDrCmdInternal;
427
428 bool bSend = false;
429
430 if (bRectShanged)
431 {
432 uint32_t cbDrCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects + 1);
433 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbDrCmdInternal);
434 Assert(pDrCmdInternal);
435 if (!pDrCmdInternal)
436 {
437 Status = STATUS_NO_MEMORY;
438 break;
439 }
440 pDrCmdInternal->Cmd.fFlags.Value = 0;
441 pDrCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects + 1;
442 pDrCmdInternal->Cmd.fFlags.bSetViewRect = 1;
443 pDrCmdInternal->Cmd.RectsInfo.aRects[0] = *pContextRect;
444 pSwapchain->ViewRect = *pContextRect;
445 memcpy(&pDrCmdInternal->Cmd.RectsInfo.aRects[1], pRects->aRects, sizeof (RECT) * pRects->cRects);
446 bSend = true;
447 }
448 else
449 {
450 if (pCmdInternal)
451 {
452 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pContext->CmContext);
453 pCmdInternal = NULL;
454 }
455 else
456 {
457 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal);
458 Assert(pDrCmdInternal);
459 if (!pDrCmdInternal)
460 {
461 Status = STATUS_NO_MEMORY;
462 break;
463 }
464 }
465 pDrCmdInternal->Cmd.fFlags.Value = 0;
466 pDrCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects;
467 memcpy(&pDrCmdInternal->Cmd.RectsInfo.aRects[0], pRects->aRects, sizeof (RECT) * pRects->cRects);
468
469 if (pSwapchain->pLastReportedRects)
470 {
471 if (pSwapchain->pLastReportedRects->Cmd.fFlags.bSetVisibleRects)
472 {
473 RECT *paRects;
474 uint32_t cRects;
475 if (pSwapchain->pLastReportedRects->Cmd.fFlags.bSetViewRect)
476 {
477 paRects = &pSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[1];
478 cRects = pSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects - 1;
479 }
480 else
481 {
482 paRects = &pSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[0];
483 cRects = pSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects;
484 }
485 bSend = (pDrCmdInternal->Cmd.RectsInfo.cRects != cRects)
486 || memcmp(paRects, pDrCmdInternal->Cmd.RectsInfo.aRects, cRects * sizeof (RECT));
487 }
488 else
489 {
490 Assert(pSwapchain->pLastReportedRects->Cmd.fFlags.bAddHiddenRects);
491 bSend = true;
492 }
493 }
494 else
495 bSend = true;
496
497 }
498
499 Assert(pRects->cRects);
500 if (bSend)
501 {
502 if (pSwapchain->pLastReportedRects)
503 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
504
505 pDrCmdInternal->Cmd.fFlags.bSetVisibleRects = 1;
506 pDrCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
507
508 vboxVideoCmCmdRetain(pDrCmdInternal);
509 pSwapchain->pLastReportedRects = pDrCmdInternal;
510 vboxVideoCmCmdSubmit(pDrCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
511 }
512 else
513 {
514 if (!pCmdInternal)
515 pCmdInternal = pDrCmdInternal;
516 else
517 vboxVideoCmCmdRelease(pDrCmdInternal);
518 }
519 }
520 }
521 ExReleaseFastMutex(&pDevExt->ContextMutex);
522
523
524 if (pCmdInternal)
525 vboxVideoCmCmdRelease(pCmdInternal);
526
527 return Status;
528}
529
530static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF)
531{
532 NTSTATUS Status = STATUS_UNSUCCESSFUL;
533 PVBOXWDDM_CONTEXT pContext = pCF->Hdr.DdiCmd.pContext;
534 PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter;
535 Assert (pDevExt->pvVisibleVram);
536 if (pDevExt->pvVisibleVram)
537 {
538 PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
539 Assert(pAlloc->offVram != VBOXVIDEOOFFSET_VOID);
540 if (pAlloc->offVram != VBOXVIDEOOFFSET_VOID)
541 {
542 RECT UnionRect = {0};
543 uint8_t *pvMem = pDevExt->pvVisibleVram + pAlloc->offVram;
544 UINT bpp = pAlloc->SurfDesc.bpp;
545 Assert(bpp);
546 Assert(((bpp * pAlloc->SurfDesc.width) >> 3) == pAlloc->SurfDesc.pitch);
547 switch (bpp)
548 {
549 case 32:
550 {
551 uint8_t bytestPP = bpp >> 3;
552 for (UINT i = 0; i < pCF->ClrFill.Rects.cRects; ++i)
553 {
554 RECT *pRect = &pCF->ClrFill.Rects.aRects[i];
555 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
556 {
557 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->SurfDesc.pitch) + (pRect->left * bytestPP));
558 uint32_t cRaw = pRect->right - pRect->left;
559 Assert(pRect->left >= 0);
560 Assert(pRect->right <= (LONG)pAlloc->SurfDesc.width);
561 Assert(pRect->top >= 0);
562 Assert(pRect->bottom <= (LONG)pAlloc->SurfDesc.height);
563 for (UINT j = 0; j < cRaw; ++j)
564 {
565 *pvU32Mem = pCF->ClrFill.Color;
566 ++pvU32Mem;
567 }
568 }
569 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
570 }
571 Status = STATUS_SUCCESS;
572 break;
573 }
574 case 16:
575 case 8:
576 default:
577 AssertBreakpoint();
578 break;
579 }
580
581 if (Status == STATUS_SUCCESS)
582 {
583 if (pAlloc->SurfDesc.VidPnSourceId != D3DDDI_ID_UNINITIALIZED
584 && pAlloc->bAssigned
585#if 0//def VBOXWDDM_RENDER_FROM_SHADOW
586 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
587#else
588 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE
589#endif
590 )
591 {
592 if (!vboxWddmRectIsEmpty(&UnionRect))
593 {
594 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->ClrFill.Alloc.pAlloc->SurfDesc.VidPnSourceId];
595 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UnionRect);
596 }
597 }
598 else
599 {
600 AssertBreakpoint();
601 }
602 }
603 }
604 }
605
606 return Status;
607}
608
609NTSTATUS vboxVdmaGgDmaBltPerform(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSrcAlloc, RECT* pSrcRect,
610 PVBOXWDDM_ALLOCATION pDstAlloc, RECT* pDstRect)
611{
612 uint8_t* pvVramBase = pDevExt->pvVisibleVram;
613 /* we do not support color conversion */
614 Assert(pSrcAlloc->SurfDesc.format == pDstAlloc->SurfDesc.format);
615 /* we do not support stretching */
616 uint32_t srcWidth = pSrcRect->right - pSrcRect->left;
617 uint32_t srcHeight = pSrcRect->bottom - pSrcRect->top;
618 uint32_t dstWidth = pDstRect->right - pDstRect->left;
619 uint32_t dstHeight = pDstRect->bottom - pDstRect->top;
620 Assert(srcHeight == dstHeight);
621 Assert(dstWidth == srcWidth);
622 Assert(pDstAlloc->offVram != VBOXVIDEOOFFSET_VOID);
623 Assert(pSrcAlloc->offVram != VBOXVIDEOOFFSET_VOID);
624
625 if (pSrcAlloc->SurfDesc.format != pDstAlloc->SurfDesc.format)
626 return STATUS_INVALID_PARAMETER;
627 if (srcHeight != dstHeight)
628 return STATUS_INVALID_PARAMETER;
629 if (srcWidth != dstWidth)
630 return STATUS_INVALID_PARAMETER;
631 if (pDstAlloc->offVram == VBOXVIDEOOFFSET_VOID)
632 return STATUS_INVALID_PARAMETER;
633 if (pSrcAlloc->offVram == VBOXVIDEOOFFSET_VOID)
634 return STATUS_INVALID_PARAMETER;
635
636 uint8_t *pvDstSurf = pvVramBase + pDstAlloc->offVram;
637 uint8_t *pvSrcSurf = pvVramBase + pSrcAlloc->offVram;
638
639 if (pDstAlloc->SurfDesc.width == dstWidth
640 && pSrcAlloc->SurfDesc.width == srcWidth
641 && pSrcAlloc->SurfDesc.width == pDstAlloc->SurfDesc.width)
642 {
643 Assert(!pDstRect->left);
644 Assert(!pSrcRect->left);
645 uint32_t cbOff = pDstAlloc->SurfDesc.pitch * pDstRect->top;
646 uint32_t cbSize = pDstAlloc->SurfDesc.pitch * dstHeight;
647 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
648 }
649 else
650 {
651 uint32_t offDstLineStart = pDstRect->left * pDstAlloc->SurfDesc.bpp >> 3;
652 uint32_t offDstLineEnd = ((pDstRect->left * pDstAlloc->SurfDesc.bpp + 7) >> 3) + ((pDstAlloc->SurfDesc.bpp * dstWidth + 7) >> 3);
653 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
654 uint32_t offDstStart = pDstAlloc->SurfDesc.pitch * pDstRect->top + offDstLineStart;
655 Assert(cbDstLine <= pDstAlloc->SurfDesc.pitch);
656 uint32_t cbDstSkip = pDstAlloc->SurfDesc.pitch;
657 uint8_t * pvDstStart = pvDstSurf + offDstStart;
658
659 uint32_t offSrcLineStart = pSrcRect->left * pSrcAlloc->SurfDesc.bpp >> 3;
660 uint32_t offSrcLineEnd = ((pSrcRect->left * pSrcAlloc->SurfDesc.bpp + 7) >> 3) + ((pSrcAlloc->SurfDesc.bpp * srcWidth + 7) >> 3);
661 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
662 uint32_t offSrcStart = pSrcAlloc->SurfDesc.pitch * pSrcRect->top + offSrcLineStart;
663 Assert(cbSrcLine <= pSrcAlloc->SurfDesc.pitch);
664 uint32_t cbSrcSkip = pSrcAlloc->SurfDesc.pitch;
665 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
666
667 Assert(cbDstLine == cbSrcLine);
668
669 for (uint32_t i = 0; ; ++i)
670 {
671 memcpy (pvDstStart, pvSrcStart, cbDstLine);
672 if (i == dstHeight)
673 break;
674 pvDstStart += cbDstSkip;
675 pvSrcStart += cbSrcSkip;
676 }
677 }
678 return STATUS_SUCCESS;
679}
680
681/*
682 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
683 */
684static NTSTATUS vboxVdmaGgDmaBlt(PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt)
685{
686 /* we do not support stretching for now */
687 Assert(pBlt->Blt.SrcRect.right - pBlt->Blt.SrcRect.left == pBlt->Blt.DstRects.ContextRect.right - pBlt->Blt.DstRects.ContextRect.left);
688 Assert(pBlt->Blt.SrcRect.bottom - pBlt->Blt.SrcRect.top == pBlt->Blt.DstRects.ContextRect.bottom - pBlt->Blt.DstRects.ContextRect.top);
689 if (pBlt->Blt.SrcRect.right - pBlt->Blt.SrcRect.left != pBlt->Blt.DstRects.ContextRect.right - pBlt->Blt.DstRects.ContextRect.left)
690 return STATUS_INVALID_PARAMETER;
691 if (pBlt->Blt.SrcRect.bottom - pBlt->Blt.SrcRect.top != pBlt->Blt.DstRects.ContextRect.bottom - pBlt->Blt.DstRects.ContextRect.top)
692 return STATUS_INVALID_PARAMETER;
693 Assert(pBlt->Blt.DstRects.UpdateRects.cRects);
694
695 NTSTATUS Status = STATUS_SUCCESS;
696 PVBOXMP_DEVEXT pDevExt = pBlt->Hdr.pDevExt;
697
698 if (pBlt->Blt.DstRects.UpdateRects.cRects)
699 {
700 for (uint32_t i = 0; i < pBlt->Blt.DstRects.UpdateRects.cRects; ++i)
701 {
702 RECT DstRect;
703 RECT SrcRect;
704 vboxWddmRectTranslated(&DstRect, &pBlt->Blt.DstRects.UpdateRects.aRects[i], pBlt->Blt.DstRects.ContextRect.left, pBlt->Blt.DstRects.ContextRect.top);
705 vboxWddmRectTranslated(&SrcRect, &pBlt->Blt.DstRects.UpdateRects.aRects[i], pBlt->Blt.SrcRect.left, pBlt->Blt.SrcRect.top);
706
707 Status = vboxVdmaGgDmaBltPerform(pDevExt, pBlt->Blt.SrcAlloc.pAlloc, &SrcRect,
708 pBlt->Blt.DstAlloc.pAlloc, &DstRect);
709 Assert(Status == STATUS_SUCCESS);
710 if (Status != STATUS_SUCCESS)
711 return Status;
712 }
713 }
714 else
715 {
716 Status = vboxVdmaGgDmaBltPerform(pDevExt, pBlt->Blt.SrcAlloc.pAlloc, &pBlt->Blt.SrcRect,
717 pBlt->Blt.DstAlloc.pAlloc, &pBlt->Blt.DstRects.ContextRect);
718 Assert(Status == STATUS_SUCCESS);
719 if (Status != STATUS_SUCCESS)
720 return Status;
721 }
722
723 return Status;
724}
725
726static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y)
727{
728 vboxWddmRectTranslate(&pRects->ContextRect, x, y);
729
730 for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i)
731 {
732 vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y);
733 }
734}
735
736static NTSTATUS vboxVdmaGgDmaCmdProcess(VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd)
737{
738 PVBOXMP_DEVEXT pDevExt = pDmaCmd->pDevExt;
739 PVBOXWDDM_CONTEXT pContext = pDmaCmd->DdiCmd.pContext;
740 NTSTATUS Status = STATUS_SUCCESS;
741 DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
742 switch (pDmaCmd->enmCmd)
743 {
744 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
745 {
746 PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd;
747 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
748 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
749 BOOLEAN bComplete = TRUE;
750 switch (pDstAlloc->enmType)
751 {
752 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE:
753 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
754 {
755 if (pDstAlloc->bAssigned)
756 {
757 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->SurfDesc.VidPnSourceId];
758 Assert(pSource->pPrimaryAllocation == pDstAlloc);
759 switch (pSrcAlloc->enmType)
760 {
761 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
762 {
763 Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_SYSTEM);
764
765 if (pBlt->Hdr.fFlags.b2DRelated || pBlt->Hdr.fFlags.b3DRelated)
766 {
767 POINT pos;
768 BOOLEAN bPosMoved = FALSE;
769 if (pBlt->Hdr.fFlags.b3DRelated)
770 {
771 pos = pSource->VScreenPos;
772 if (pos.x || pos.y)
773 {
774 vboxWddmBltPipeRectsTranslate(&pBlt->Blt.DstRects, pos.x, pos.y);
775 bPosMoved = TRUE;
776 }
777 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, NULL, &pBlt->Blt.DstRects);
778 Assert(Status == STATUS_SUCCESS);
779 }
780
781
782 if (pBlt->Hdr.fFlags.b2DRelated)
783 {
784 if (bPosMoved)
785 {
786 vboxWddmBltPipeRectsTranslate(&pBlt->Blt.DstRects, -pos.x, -pos.y);
787 }
788
789 RECT OverlayUnionRect;
790 RECT UpdateRect;
791 UpdateRect = pBlt->Blt.DstRects.UpdateRects.aRects[0];
792 for (UINT i = 1; i < pBlt->Blt.DstRects.UpdateRects.cRects; ++i)
793 {
794 vboxWddmRectUnite(&UpdateRect, &pBlt->Blt.DstRects.UpdateRects.aRects[i]);
795 }
796 vboxVhwaHlpOverlayDstRectUnion(pDevExt, pDstAlloc->SurfDesc.VidPnSourceId, &OverlayUnionRect);
797 Assert(pBlt->Blt.DstRects.ContextRect.left == 0); /* <-| otherwise we would probably need to translate the UpdateRects to left;top first??*/
798 Assert(pBlt->Blt.DstRects.ContextRect.top == 0); /* <--| */
799 vboxVdmaDirtyRectsCalcIntersection(&OverlayUnionRect, &pBlt->Blt.DstRects.UpdateRects, &pBlt->Blt.DstRects.UpdateRects);
800 if (pBlt->Blt.DstRects.UpdateRects.cRects)
801 {
802 vboxVdmaGgDmaBlt(pBlt);
803 }
804 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect);
805 }
806 }
807
808 break;
809 }
810 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC:
811 {
812 Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D);
813 Assert(pSrcAlloc->fRcFlags.RenderTarget);
814 if (pSrcAlloc->fRcFlags.RenderTarget)
815 {
816 if (pBlt->Hdr.fFlags.b3DRelated)
817 {
818 PVBOXWDDM_SWAPCHAIN pSwapchain;
819 pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc);
820 if (pSwapchain)
821 {
822 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &pBlt->Blt.DstRects);
823 Assert(Status == STATUS_SUCCESS);
824 vboxWddmSwapchainRelease(pSwapchain);
825 }
826 }
827 }
828 break;
829 }
830 default:
831 AssertBreakpoint();
832 break;
833 }
834 }
835 break;
836 }
837 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE:
838 {
839 if (pBlt->Hdr.fFlags.b2DRelated)
840 {
841 RECT OverlayUnionRect;
842 vboxVhwaHlpOverlayDstRectUnion(pDevExt, pDstAlloc->SurfDesc.VidPnSourceId, &OverlayUnionRect);
843 Assert(pBlt->Blt.DstRects.ContextRect.left == 0); /* <-| otherwise we would probably need to translate the UpdateRects to left;top first??*/
844 Assert(pBlt->Blt.DstRects.ContextRect.top == 0); /* <--| */
845 vboxVdmaDirtyRectsCalcIntersection(&OverlayUnionRect, &pBlt->Blt.DstRects.UpdateRects, &pBlt->Blt.DstRects.UpdateRects);
846 if (pBlt->Blt.DstRects.UpdateRects.cRects)
847 {
848 vboxVdmaGgDmaBlt(pBlt);
849 }
850 }
851 else
852 {
853 Assert(0);
854 }
855 break;
856 }
857 default:
858 Assert(0);
859 }
860
861 break;
862 }
863 case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP:
864 {
865 PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd;
866 Assert(pFlip->Hdr.fFlags.b3DRelated);
867 Assert(!pFlip->Hdr.fFlags.bDecVBVAUnlock);
868 Assert(!pFlip->Hdr.fFlags.b2DRelated);
869 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
870 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->SurfDesc.VidPnSourceId];
871 if (pFlip->Hdr.fFlags.b3DRelated)
872 {
873 PVBOXWDDM_SWAPCHAIN pSwapchain;
874 pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pAlloc);
875 if (pSwapchain)
876 {
877 POINT pos = pSource->VScreenPos;
878 VBOXVDMAPIPE_RECTS Rects;
879 Rects.ContextRect.left = pos.x;
880 Rects.ContextRect.top = pos.y;
881 Rects.ContextRect.right = pAlloc->SurfDesc.width + pos.x;
882 Rects.ContextRect.bottom = pAlloc->SurfDesc.height + pos.y;
883 Rects.UpdateRects.cRects = 1;
884 Rects.UpdateRects.aRects[0] = Rects.ContextRect;
885 Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &Rects);
886 Assert(Status == STATUS_SUCCESS);
887 vboxWddmSwapchainRelease(pSwapchain);
888 }
889 }
890
891 break;
892 }
893 case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL:
894 {
895 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDmaCmd;
896 Assert(pCF->Hdr.fFlags.b2DRelated);
897 Assert(pCF->Hdr.fFlags.bDecVBVAUnlock);
898 Assert(!pCF->Hdr.fFlags.b3DRelated);
899 Status = vboxVdmaGgDmaColorFill(pCF);
900 Assert(Status == STATUS_SUCCESS);
901 break;
902 }
903 default:
904 Assert(0);
905 break;
906 }
907
908 if (pDmaCmd->fFlags.bDecVBVAUnlock)
909 {
910 uint32_t cNew = ASMAtomicDecU32(&pDevExt->cUnlockedVBVADisabled);
911 Assert(cNew < UINT32_MAX/2);
912 }
913
914 Status = vboxVdmaDdiCmdCompleted(pDevExt, &pDevExt->DdiCmdQueue, &pDmaCmd->DdiCmd, enmComplType);
915 Assert(Status == STATUS_SUCCESS);
916
917 return Status;
918}
919
920static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
921{
922 PVBOXVDMAGG pVdma = (PVBOXVDMAGG)pvUser;
923
924 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
925 Assert(Status == STATUS_SUCCESS);
926 if (Status == STATUS_SUCCESS)
927 {
928 do
929 {
930 LIST_ENTRY CmdList;
931 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
932 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
933 if (Status == STATUS_SUCCESS)
934 {
935 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList;)
936 {
937 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
938 RemoveEntryList(pCur);
939 pCur = CmdList.Blink;
940 switch (pDr->enmType)
941 {
942#if 0
943 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
944 {
945 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
946 Status = vboxVdmaGgDirtyRectsProcess(pRects);
947 Assert(Status == STATUS_SUCCESS);
948 vboxVdmaGgCmdDestroy(pDr);
949 break;
950 }
951#endif
952 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
953 {
954 PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pDr;
955 Status = vboxVdmaGgDmaCmdProcess(pDmaCmd);
956 Assert(Status == STATUS_SUCCESS);
957 } break;
958 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
959 {
960 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
961 Status = vboxVdmaGgDirtyRectsProcess(pRects->pDevExt, pRects->pContext, pRects->pSwapchain, &pRects->ContextsRects);
962 Assert(Status == STATUS_SUCCESS);
963 vboxVdmaGgCmdDestroy(pDr);
964 break;
965 }
966 default:
967 AssertBreakpoint();
968 }
969 }
970 }
971 else
972 break;
973 } while (1);
974 }
975
976 /* always try to close the pipe to make sure the client side is notified */
977 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
978 Assert(Status == STATUS_SUCCESS);
979}
980
981NTSTATUS vboxVdmaGgConstruct(PVBOXVDMAGG pVdma)
982{
983 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
984 Assert(Status == STATUS_SUCCESS);
985 if (Status == STATUS_SUCCESS)
986 {
987 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pVdma);
988 Assert(Status == STATUS_SUCCESS);
989 if (Status == STATUS_SUCCESS)
990 return STATUS_SUCCESS;
991
992 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
993 Assert(tmpStatus == STATUS_SUCCESS);
994 }
995
996 /* we're here ONLY in case of an error */
997 Assert(Status != STATUS_SUCCESS);
998 return Status;
999}
1000
1001NTSTATUS vboxVdmaGgDestruct(PVBOXVDMAGG pVdma)
1002{
1003 /* this informs the server thread that it should complete all current commands and exit */
1004 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
1005 Assert(Status == STATUS_SUCCESS);
1006 if (Status == STATUS_SUCCESS)
1007 {
1008 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
1009 Assert(Status == STATUS_SUCCESS);
1010 if (Status == STATUS_SUCCESS)
1011 {
1012 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
1013 Assert(Status == STATUS_SUCCESS);
1014 }
1015 }
1016
1017 return Status;
1018}
1019
1020NTSTATUS vboxVdmaGgCmdSubmit(PVBOXVDMAGG pVdma, PVBOXVDMAPIPE_CMD_DR pCmd)
1021{
1022 return vboxVdmaPipeCltCmdPut(&pVdma->CmdPipe, &pCmd->PipeHdr);
1023}
1024
1025/* end */
1026
1027#ifdef VBOX_WITH_VDMA
1028/*
1029 * This is currently used by VDMA. It is invisible for Vdma API clients since
1030 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1031 * transport for DMA commands submission
1032 */
1033
1034#ifdef VBOXVDMA_WITH_VBVA
1035static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1036{
1037 int rc;
1038 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1039 {
1040 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1041 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1042 }
1043 else
1044 {
1045 AssertBreakpoint();
1046 rc = VERR_INVALID_STATE;
1047 }
1048 return rc;
1049}
1050#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1051#else
1052static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1053{
1054 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1055 return VINF_SUCCESS;
1056}
1057#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1058#endif
1059
1060static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1061{
1062 int rc = VINF_SUCCESS;
1063
1064 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1065 if (pCmd)
1066 {
1067 pCmd->enmCtl = enmCtl;
1068 pCmd->u32Offset = pInfo->CmdHeap.area.offBase;
1069 pCmd->i32Result = VERR_NOT_SUPPORTED;
1070
1071 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1072 Assert(pHdr);
1073 if (pHdr)
1074 {
1075 do
1076 {
1077 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1078 Assert(offCmd != HGSMIOFFSET_VOID);
1079 if (offCmd != HGSMIOFFSET_VOID)
1080 {
1081 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1082 AssertRC(rc);
1083 if (RT_SUCCESS(rc))
1084 {
1085 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1086 AssertRC(rc);
1087 if (RT_SUCCESS(rc))
1088 {
1089 rc = pCmd->i32Result;
1090 AssertRC(rc);
1091 }
1092 break;
1093 }
1094 }
1095 else
1096 rc = VERR_INVALID_PARAMETER;
1097 /* fail to submit, cancel it */
1098 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1099 } while (0);
1100 }
1101
1102 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1103 }
1104 else
1105 {
1106 LOGREL(("HGSMIHeapAlloc failed"));
1107 rc = VERR_OUT_OF_RESOURCES;
1108 }
1109
1110 return rc;
1111}
1112#endif
1113
1114/* create a DMACommand buffer */
1115int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1116#ifdef VBOX_WITH_VDMA
1117 , ULONG offBuffer, ULONG cbBuffer
1118#endif
1119 )
1120{
1121 int rc;
1122 pInfo->fEnabled = FALSE;
1123
1124#ifdef VBOX_WITH_VDMA
1125 KeInitializeSpinLock(&pInfo->HeapLock);
1126 Assert((offBuffer & 0xfff) == 0);
1127 Assert((cbBuffer & 0xfff) == 0);
1128 Assert(offBuffer);
1129 Assert(cbBuffer);
1130
1131 if((offBuffer & 0xfff)
1132 || (cbBuffer & 0xfff)
1133 || !offBuffer
1134 || !cbBuffer)
1135 {
1136 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1137 return VERR_INVALID_PARAMETER;
1138 }
1139 PVOID pvBuffer;
1140
1141 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1142 &pvBuffer,
1143 offBuffer,
1144 cbBuffer);
1145 Assert(RT_SUCCESS(rc));
1146 if (RT_SUCCESS(rc))
1147 {
1148 /* Setup a HGSMI heap within the adapter information area. */
1149 rc = HGSMIHeapSetup (&pInfo->CmdHeap,
1150 pvBuffer,
1151 cbBuffer,
1152 offBuffer,
1153 false /*fOffsetBased*/);
1154 Assert(RT_SUCCESS(rc));
1155 if(RT_SUCCESS(rc))
1156#endif
1157 {
1158 NTSTATUS Status = vboxVdmaGgConstruct(&pInfo->DmaGg);
1159 Assert(Status == STATUS_SUCCESS);
1160 if (Status == STATUS_SUCCESS)
1161 return VINF_SUCCESS;
1162 rc = VERR_GENERAL_FAILURE;
1163 }
1164#ifdef VBOX_WITH_VDMA
1165 else
1166 LOGREL(("HGSMIHeapSetup failed rc = 0x%x", rc));
1167
1168 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), &pvBuffer);
1169 }
1170 else
1171 LOGREL(("VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
1172#endif
1173 return rc;
1174}
1175
1176int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1177{
1178 LOGF(("."));
1179
1180 Assert(pInfo->fEnabled);
1181 if (!pInfo->fEnabled)
1182 return VINF_ALREADY_INITIALIZED;
1183
1184 /* ensure nothing else is submitted */
1185 pInfo->fEnabled = FALSE;
1186#ifdef VBOX_WITH_VDMA
1187 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1188 AssertRC(rc);
1189 return rc;
1190#else
1191 return VINF_SUCCESS;
1192#endif
1193}
1194
1195int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1196{
1197 LOGF(("."));
1198
1199 Assert(!pInfo->fEnabled);
1200 if (pInfo->fEnabled)
1201 return VINF_ALREADY_INITIALIZED;
1202#ifdef VBOX_WITH_VDMA
1203 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1204 Assert(RT_SUCCESS(rc));
1205 if (RT_SUCCESS(rc))
1206 pInfo->fEnabled = TRUE;
1207
1208 return rc;
1209#else
1210 return VINF_SUCCESS;
1211#endif
1212}
1213
1214#ifdef VBOX_WITH_VDMA
1215int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1216{
1217 LOGF(("."));
1218
1219 Assert(pInfo->fEnabled);
1220 if (!pInfo->fEnabled)
1221 return VINF_ALREADY_INITIALIZED;
1222
1223 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1224 Assert(RT_SUCCESS(rc));
1225
1226 return rc;
1227}
1228#endif
1229
1230int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1231{
1232 int rc = VINF_SUCCESS;
1233 NTSTATUS Status = vboxVdmaGgDestruct(&pInfo->DmaGg);
1234 Assert(Status == STATUS_SUCCESS);
1235 if (Status == STATUS_SUCCESS)
1236 {
1237 Assert(!pInfo->fEnabled);
1238 if (pInfo->fEnabled)
1239 rc = vboxVdmaDisable (pDevExt, pInfo);
1240#ifdef VBOX_WITH_VDMA
1241 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.area.pu8Base);
1242#endif
1243 }
1244 else
1245 rc = VERR_GENERAL_FAILURE;
1246 return rc;
1247}
1248
1249#ifdef VBOX_WITH_VDMA
1250void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1251{
1252 KIRQL OldIrql;
1253 KeAcquireSpinLock(&pInfo->HeapLock, &OldIrql);
1254 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1255 KeReleaseSpinLock(&pInfo->HeapLock, OldIrql);
1256}
1257
1258PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1259{
1260 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1261 KIRQL OldIrql;
1262 KeAcquireSpinLock(&pInfo->HeapLock, &OldIrql);
1263 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1264 KeReleaseSpinLock(&pInfo->HeapLock, OldIrql);
1265 Assert(pDr);
1266 if (pDr)
1267 memset (pDr, 0, cbDr);
1268 else
1269 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1270
1271 return pDr;
1272}
1273
1274static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext)
1275{
1276 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1277 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1278
1279 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1280}
1281
1282static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext,
1283 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
1284{
1285 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1286 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1287 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1288
1289 DXGK_INTERRUPT_TYPE enmComplType;
1290
1291 if (RT_SUCCESS(pDr->rc))
1292 {
1293 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1294 }
1295 else if (pDr->rc == VERR_INTERRUPTED)
1296 {
1297 Assert(0);
1298 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1299 }
1300 else
1301 {
1302 Assert(0);
1303 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1304 }
1305
1306 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, &pDevExt->DdiCmdQueue, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1307 {
1308 pDevExt->bNotifyDxDpc = TRUE;
1309 }
1310
1311 /* inform SHGSMI we DO NOT want to be called at DPC later */
1312 *ppfnCompletion = NULL;
1313// *ppvCompletion = pvContext;
1314}
1315
1316int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1317{
1318 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1319 Assert(pHdr);
1320 int rc = VERR_GENERAL_FAILURE;
1321 if (pHdr)
1322 {
1323 do
1324 {
1325 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1326 Assert(offCmd != HGSMIOFFSET_VOID);
1327 if (offCmd != HGSMIOFFSET_VOID)
1328 {
1329 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1330 AssertRC(rc);
1331 if (RT_SUCCESS(rc))
1332 {
1333 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1334 AssertRC(rc);
1335 break;
1336 }
1337 }
1338 else
1339 rc = VERR_INVALID_PARAMETER;
1340 /* fail to submit, cancel it */
1341 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1342 } while (0);
1343 }
1344 else
1345 rc = VERR_INVALID_PARAMETER;
1346 return rc;
1347}
1348
1349int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1350{
1351 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1352 Assert(pHdr);
1353 int rc = VERR_GENERAL_FAILURE;
1354 if (pHdr)
1355 {
1356 do
1357 {
1358 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1359 Assert(offCmd != HGSMIOFFSET_VOID);
1360 if (offCmd != HGSMIOFFSET_VOID)
1361 {
1362 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1363 AssertRC(rc);
1364 if (RT_SUCCESS(rc))
1365 {
1366 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1367 AssertRC(rc);
1368 break;
1369 }
1370 }
1371 else
1372 rc = VERR_INVALID_PARAMETER;
1373 /* fail to submit, cancel it */
1374 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1375 } while (0);
1376 }
1377 else
1378 rc = VERR_INVALID_PARAMETER;
1379 return rc;
1380}
1381#endif
1382
1383
1384/* ddi dma command queue */
1385DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXVDMADDI_CMD_QUEUE pQueue)
1386{
1387 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1388}
1389
1390DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1391{
1392 vboxWddmMemFree(pCmd);
1393}
1394
1395static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1396{
1397 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1398 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1399 switch (enmComplType)
1400 {
1401 case DXGK_INTERRUPT_DMA_COMPLETED:
1402 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1403 notify.DmaCompleted.SubmissionFenceId = pCmd->u32FenceId;
1404// if (pCmd->pContext)
1405// {
1406// notify.DmaCompleted.NodeOrdinal = pCmd->pContext->NodeOrdinal;
1407// pCmd->pContext->uLastCompletedCmdFenceId = pCmd->u32FenceId;
1408// }
1409// else
1410 {
1411 pDevExt->u.primary.Vdma.uLastCompletedPagingBufferCmdFenceId = pCmd->u32FenceId;
1412 }
1413
1414 InsertTailList(&pQueue->DpcCmdQueue, &pCmd->QueueEntry);
1415
1416 break;
1417 case DXGK_INTERRUPT_DMA_PREEMPTED:
1418 Assert(0);
1419 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1420 notify.DmaPreempted.PreemptionFenceId = pCmd->u32FenceId;
1421// if (pCmd->pContext)
1422// {
1423// notify.DmaPreempted.LastCompletedFenceId = pCmd->pContext->uLastCompletedCmdFenceId;
1424// notify.DmaPreempted.NodeOrdinal = pCmd->pContext->NodeOrdinal;
1425// }
1426// else
1427 {
1428 notify.DmaPreempted.LastCompletedFenceId = pDevExt->u.primary.Vdma.uLastCompletedPagingBufferCmdFenceId;
1429 }
1430 break;
1431
1432 case DXGK_INTERRUPT_DMA_FAULTED:
1433 Assert(0);
1434 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1435 notify.DmaFaulted.FaultedFenceId = pCmd->u32FenceId;
1436 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1437 if (pCmd->pContext)
1438 {
1439 notify.DmaFaulted.NodeOrdinal = pCmd->pContext->NodeOrdinal;
1440 }
1441 break;
1442 default:
1443 Assert(0);
1444 break;
1445 }
1446
1447 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1448}
1449
1450DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd)
1451{
1452 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1453 RemoveEntryList(&pCmd->QueueEntry);
1454}
1455
1456DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd)
1457{
1458 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1459 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1460}
1461
1462VOID vboxVdmaDdiQueueInit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD_QUEUE pQueue)
1463{
1464 pQueue->cQueuedCmds = 0;
1465 InitializeListHead(&pQueue->CmdQueue);
1466 InitializeListHead(&pQueue->DpcCmdQueue);
1467}
1468
1469BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1470{
1471 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1472 {
1473 InsertTailList(&pQueue->DpcCmdQueue, &pCmd->QueueEntry);
1474 return FALSE;
1475 }
1476
1477 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1478 BOOLEAN bComplete = FALSE;
1479 Assert(!bQueued || pQueue->cQueuedCmds);
1480 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1481 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1482 if (bQueued)
1483 {
1484 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1485 {
1486 vboxVdmaDdiCmdDequeueIrq(pQueue, pCmd);
1487 bComplete = TRUE;
1488 }
1489 }
1490 else if (IsListEmpty(&pQueue->CmdQueue))
1491 {
1492 bComplete = TRUE;
1493 }
1494 else
1495 {
1496 vboxVdmaDdiCmdEnqueueIrq(pQueue, pCmd);
1497 }
1498
1499 if (bComplete)
1500 {
1501 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pQueue, pCmd, enmComplType);
1502
1503 while (!IsListEmpty(&pQueue->CmdQueue))
1504 {
1505 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1506 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1507 {
1508 vboxVdmaDdiCmdDequeueIrq(pQueue, pCmd);
1509 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pQueue, pCmd, pCmd->enmComplType);
1510 }
1511 else
1512 break;
1513 }
1514 }
1515 else
1516 {
1517 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1518 pCmd->enmComplType = enmComplType;
1519 }
1520
1521 return bComplete;
1522}
1523
1524VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd)
1525{
1526 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
1527 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
1528 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
1529 if (!bQueued)
1530 vboxVdmaDdiCmdEnqueueIrq(pQueue, pCmd);
1531}
1532
1533typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
1534{
1535 PVBOXMP_DEVEXT pDevExt;
1536 PVBOXVDMADDI_CMD_QUEUE pQueue;
1537 PVBOXVDMADDI_CMD pCmd;
1538 DXGK_INTERRUPT_TYPE enmComplType;
1539} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
1540
1541static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
1542{
1543 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
1544 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pdc->pDevExt, pdc->pQueue, pdc->pCmd, pdc->enmComplType);
1545 pdc->pDevExt->bNotifyDxDpc |= bNeedDpc;
1546
1547 return bNeedDpc;
1548}
1549
1550NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1551{
1552 VBOXVDMADDI_CMD_COMPLETED_CB context;
1553 context.pDevExt = pDevExt;
1554 context.pQueue = pQueue;
1555 context.pCmd = pCmd;
1556 context.enmComplType = enmComplType;
1557 BOOLEAN bNeedDps;
1558 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1559 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1560 vboxVdmaDdiCmdCompletedCb,
1561 &context,
1562 0, /* IN ULONG MessageNumber */
1563 &bNeedDps);
1564 Assert(Status == STATUS_SUCCESS);
1565 if (Status == STATUS_SUCCESS && bNeedDps)
1566 {
1567 BOOLEAN bRc = pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1568 Assert(bRc);
1569 }
1570 return Status;
1571}
1572
1573typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
1574{
1575// PVBOXMP_DEVEXT pDevExt;
1576 PVBOXVDMADDI_CMD_QUEUE pQueue;
1577 PVBOXVDMADDI_CMD pCmd;
1578} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
1579
1580static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
1581{
1582 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
1583 vboxVdmaDdiCmdSubmittedIrq(pdc->pQueue, pdc->pCmd);
1584
1585 return FALSE;
1586}
1587
1588NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD_QUEUE pQueue, PVBOXVDMADDI_CMD pCmd)
1589{
1590 VBOXVDMADDI_CMD_SUBMITTED_CB context;
1591 context.pQueue = pQueue;
1592 context.pCmd = pCmd;
1593 BOOLEAN bRc;
1594 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1595 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1596 vboxVdmaDdiCmdSubmittedCb,
1597 &context,
1598 0, /* IN ULONG MessageNumber */
1599 &bRc);
1600 Assert(Status == STATUS_SUCCESS);
1601 return Status;
1602}
1603
1604typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
1605{
1606 PVBOXMP_DEVEXT pDevExt;
1607 PVBOXWDDM_CONTEXT pContext;
1608 uint32_t u32FenceId;
1609} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
1610
1611static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
1612{
1613 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
1614 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1615 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1616 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1617
1618 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1619 notify.DmaCompleted.SubmissionFenceId = pdc->u32FenceId;
1620 notify.DmaCompleted.NodeOrdinal = pdc->pContext->NodeOrdinal;
1621 notify.DmaCompleted.EngineOrdinal = 0;
1622
1623 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1624
1625 pDevExt->bNotifyDxDpc = TRUE;
1626 BOOLEAN bDpcQueued = pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1627
1628 return bDpcQueued;
1629}
1630
1631static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, uint32_t u32FenceId)
1632{
1633 VBOXVDMADDI_CMD_COMPLETE_CB context;
1634 context.pDevExt = pDevExt;
1635 context.pContext = pContext;
1636 context.u32FenceId = u32FenceId;
1637 BOOLEAN bRet;
1638 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1639 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1640 vboxVdmaDdiCmdFenceCompleteCb,
1641 &context,
1642 0, /* IN ULONG MessageNumber */
1643 &bRet);
1644 Assert(Status == STATUS_SUCCESS);
1645 return Status;
1646}
1647
1648NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1649{
1650 if (vboxVdmaDdiCmdCanComplete(&pDevExt->DdiCmdQueue))
1651 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, pContext, u32FenceId);
1652
1653 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
1654 Assert(pCmd);
1655 if (pCmd)
1656 {
1657 vboxVdmaDdiCmdInit(pCmd, u32FenceId, pContext, vboxVdmaDdiCmdCompletionCbFree, NULL);
1658 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, &pDevExt->DdiCmdQueue, pCmd, enmComplType);
1659 Assert(Status == STATUS_SUCCESS);
1660 if (Status == STATUS_SUCCESS)
1661 return STATUS_SUCCESS;
1662 vboxWddmMemFree(pCmd);
1663 return Status;
1664 }
1665 return STATUS_NO_MEMORY;
1666}
1667
1668#ifdef VBOXWDDM_RENDER_FROM_SHADOW
1669NTSTATUS vboxVdmaHlpUpdatePrimary(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT* pRect)
1670{
1671 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1672 Assert(pSource->pPrimaryAllocation);
1673 Assert(pSource->pShadowAllocation);
1674 if (!pSource->pPrimaryAllocation)
1675 return STATUS_INVALID_PARAMETER;
1676 if (!pSource->pShadowAllocation)
1677 return STATUS_INVALID_PARAMETER;
1678
1679 Assert(pSource->pPrimaryAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1680 Assert(pSource->pShadowAllocation->offVram != VBOXVIDEOOFFSET_VOID);
1681 if (pSource->pPrimaryAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1682 return STATUS_INVALID_PARAMETER;
1683 if (pSource->pShadowAllocation->offVram == VBOXVIDEOOFFSET_VOID)
1684 return STATUS_INVALID_PARAMETER;
1685
1686 NTSTATUS Status = vboxVdmaGgDmaBltPerform(pDevExt, pSource->pShadowAllocation, pRect, pSource->pPrimaryAllocation, pRect);
1687 Assert(Status == STATUS_SUCCESS);
1688 return Status;
1689}
1690#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