VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/wddm/VBoxVideoVdma.cpp@ 30462

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

wddm/3d: more visible rects support & fixes, enhances to dma command handling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/*
2 * Copyright (C) 2010 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 */
12
13#include "../VBoxVideo.h"
14#include "../Helper.h"
15
16#include <VBox/VBoxGuestLib.h>
17#include <VBox/VBoxVideo.h>
18#include "VBoxVideoVdma.h"
19#include "../VBoxVideo.h"
20
21
22NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe)
23{
24 KeInitializeSpinLock(&pPipe->SinchLock);
25 KeInitializeEvent(&pPipe->Event, SynchronizationEvent, FALSE);
26 InitializeListHead(&pPipe->CmdListHead);
27 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
28 pPipe->bNeedNotify = true;
29 return STATUS_SUCCESS;
30}
31
32NTSTATUS vboxVdmaPipeSvrOpen(PVBOXVDMAPIPE pPipe)
33{
34 NTSTATUS Status = STATUS_SUCCESS;
35 KIRQL OldIrql;
36 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
37 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
38 switch (pPipe->enmState)
39 {
40 case VBOXVDMAPIPE_STATE_CREATED:
41 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
42 pPipe->bNeedNotify = false;
43 break;
44 case VBOXVDMAPIPE_STATE_OPENNED:
45 pPipe->bNeedNotify = false;
46 break;
47 default:
48 AssertBreakpoint();
49 Status = STATUS_INVALID_PIPE_STATE;
50 break;
51 }
52
53 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
54 return Status;
55}
56
57NTSTATUS vboxVdmaPipeSvrClose(PVBOXVDMAPIPE pPipe)
58{
59 NTSTATUS Status = STATUS_SUCCESS;
60 KIRQL OldIrql;
61 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
62 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
63 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
64 switch (pPipe->enmState)
65 {
66 case VBOXVDMAPIPE_STATE_CLOSING:
67 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
68 break;
69 case VBOXVDMAPIPE_STATE_CLOSED:
70 break;
71 default:
72 AssertBreakpoint();
73 Status = STATUS_INVALID_PIPE_STATE;
74 break;
75 }
76
77 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
78 return Status;
79}
80
81NTSTATUS vboxVdmaPipeCltClose(PVBOXVDMAPIPE pPipe)
82{
83 NTSTATUS Status = STATUS_SUCCESS;
84 KIRQL OldIrql;
85 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
86 bool bNeedNotify = false;
87 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
88 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
89 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
90 switch (pPipe->enmState)
91 {
92 case VBOXVDMAPIPE_STATE_OPENNED:
93 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
94 bNeedNotify = pPipe->bNeedNotify;
95 pPipe->bNeedNotify = false;
96 break;
97 case VBOXVDMAPIPE_STATE_CREATED:
98 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
99 pPipe->bNeedNotify = false;
100 break;
101 case VBOXVDMAPIPE_STATE_CLOSED:
102 break;
103 default:
104 AssertBreakpoint();
105 Status = STATUS_INVALID_PIPE_STATE;
106 break;
107 }
108
109 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
110
111 if (bNeedNotify)
112 {
113 KeSetEvent(&pPipe->Event, 0, FALSE);
114 }
115 return Status;
116}
117
118NTSTATUS vboxVdmaPipeDestruct(PVBOXVDMAPIPE pPipe)
119{
120 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
121 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
122 /* ensure the pipe is closed */
123 NTSTATUS Status = vboxVdmaPipeCltClose(pPipe);
124 Assert(Status == STATUS_SUCCESS);
125
126 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
127
128 return Status;
129}
130
131NTSTATUS vboxVdmaPipeSvrCmdGetList(PVBOXVDMAPIPE pPipe, PLIST_ENTRY pDetachHead)
132{
133 PLIST_ENTRY pEntry = NULL;
134 KIRQL OldIrql;
135 NTSTATUS Status = STATUS_SUCCESS;
136 VBOXVDMAPIPE_STATE enmState = VBOXVDMAPIPE_STATE_CLOSED;
137 do
138 {
139 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
140 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
141 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
142 Assert(pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED);
143 enmState = pPipe->enmState;
144 if (enmState >= VBOXVDMAPIPE_STATE_OPENNED)
145 {
146 vboxVideoLeDetach(&pPipe->CmdListHead, pDetachHead);
147 pPipe->bNeedNotify = false;
148 }
149 else
150 {
151 Status = STATUS_INVALID_PIPE_STATE;
152 break;
153 }
154
155 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
156
157 if (!IsListEmpty(pDetachHead))
158 {
159 Assert(Status == STATUS_SUCCESS);
160 break;
161 }
162
163 if (enmState == VBOXVDMAPIPE_STATE_OPENNED)
164 {
165 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
166 pPipe->bNeedNotify = true;
167 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
168
169 Status = KeWaitForSingleObject(&pPipe->Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
170 Assert(Status == STATUS_SUCCESS);
171 if (Status != STATUS_SUCCESS)
172 break;
173 }
174 Assert(enmState > VBOXVDMAPIPE_STATE_OPENNED);
175 Status = STATUS_PIPE_CLOSING;
176 } while (1);
177
178 return Status;
179}
180
181NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd)
182{
183 NTSTATUS Status = STATUS_SUCCESS;
184 KIRQL OldIrql;
185 bool bNeedNotify = false;
186
187 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
188
189 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
190 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
191 {
192 bNeedNotify = pPipe->bNeedNotify;
193 InsertHeadList(&pPipe->CmdListHead, &pCmd->ListEntry);
194 pPipe->bNeedNotify = false;
195 }
196 else
197 Status = STATUS_INVALID_PIPE_STATE;
198
199 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
200
201 if (bNeedNotify)
202 {
203 KeSetEvent(&pPipe->Event, 0, FALSE);
204 }
205
206 return Status;
207}
208
209PVBOXVDMAPIPE_CMD_DR vboxVdmaGgCmdCreate(PVBOXVDMAGG pVdma, uint32_t cbCmd)
210{
211 return (PVBOXVDMAPIPE_CMD_DR)vboxWddmMemAllocZero(cbCmd);
212}
213
214void vboxVdmaGgCmdDestroy(PVBOXVDMAPIPE_CMD_DR pDr)
215{
216 vboxWddmMemFree(pDr);
217}
218
219
220/**
221 * helper function used for system thread creation
222 */
223static NTSTATUS vboxVdmaGgThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
224{
225 NTSTATUS fStatus;
226 HANDLE hThread;
227 OBJECT_ATTRIBUTES fObjectAttributes;
228
229 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
230
231 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
232 NULL, NULL);
233
234 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
235 &fObjectAttributes, NULL, NULL,
236 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
237 if (!NT_SUCCESS(fStatus))
238 return fStatus;
239
240 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
241 KernelMode, (PVOID*) ppThread, NULL);
242 ZwClose(hThread);
243 return STATUS_SUCCESS;
244}
245
246DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const PVBOXWDDM_RECTS_INFO pRects, PVBOXWDDM_RECTS_INFO pResult)
247{
248 pResult->cRects = 0;
249 for (uint32_t i = 0; i < pRects->cRects; ++i)
250 {
251 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[pResult->cRects]))
252 {
253 ++pResult->cRects;
254 }
255 }
256}
257/**
258 * @param pDevExt
259 */
260NTSTATUS vboxVdmaGgDirtyRectsProcess(VBOXVDMAPIPE_CMD_RECTSINFO *pRectsInfo)
261{
262 PVBOXWDDM_CONTEXT pContext = pRectsInfo->pContext;
263 PDEVICE_EXTENSION pDevExt = pContext->pDevice->pAdapter;
264 RECT * pContextRect = &pRectsInfo->ContextRect;
265 PVBOXWDDM_RECTS_INFO pRects = &pRectsInfo->UpdateRects;
266 NTSTATUS Status = STATUS_SUCCESS;
267 PVBOXVIDEOCM_CMD_RECTS pCmd = NULL;
268 uint32_t cbCmd = VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pRects->cRects);
269 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
270 ExAcquireFastMutex(&pDevExt->ContextMutex);
271 for (PLIST_ENTRY pCur = pDevExt->ContextList3D.Flink; pCur != &pDevExt->ContextList3D; pCur = pCur->Flink)
272 {
273 if (pCur != &pContext->ListEntry)
274 {
275 PVBOXWDDM_CONTEXT pCurContext = VBOXWDDMENTRY_2_CONTEXT(pCur);
276 if (!pCmd)
277 {
278 pCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pCurContext->CmContext, cbCmd);
279 Assert(pCmd);
280 if (!pCmd)
281 {
282 Status = STATUS_NO_MEMORY;
283 break;
284 }
285 }
286 else
287 {
288 pCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdReinitForContext(pCmd, &pCurContext->CmContext);
289 }
290
291 vboxVdmaDirtyRectsCalcIntersection(&pContext->ViewRect, pRects, &pCmd->RectsInfo);
292 if (pCmd->RectsInfo.cRects)
293 {
294 Assert(pCmd->fFlags.Value == 0);
295 pCmd->fFlags.bAddHiddenRects = 1;
296 vboxVideoCmCmdSubmit(pCmd, VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pCmd->RectsInfo.cRects));
297 pCmd = NULL;
298 }
299 }
300 else
301 {
302 bool bRectShanged = (pContext->ViewRect.left != pContextRect->left
303 || pContext->ViewRect.top != pContextRect->top
304 || pContext->ViewRect.right != pContextRect->right
305 || pContext->ViewRect.bottom != pContextRect->bottom);
306 PVBOXVIDEOCM_CMD_RECTS pDrCmd;
307
308 if (bRectShanged)
309 {
310 uint32_t cbDrCmd = VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pRects->cRects + 1);
311 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pContext->CmContext, cbDrCmd);
312 Assert(pDrCmd);
313 if (!pDrCmd)
314 {
315 Status = STATUS_NO_MEMORY;
316 break;
317 }
318 pDrCmd->RectsInfo.cRects = pRects->cRects + 1;
319 }
320 else
321 {
322 if (pCmd)
323 {
324 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdReinitForContext(pCmd, &pContext->CmContext);
325 pCmd = NULL;
326 }
327 else
328 {
329 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmd);
330 Assert(pDrCmd);
331 if (!pDrCmd)
332 {
333 Status = STATUS_NO_MEMORY;
334 break;
335 }
336 }
337 pDrCmd->RectsInfo.cRects = pRects->cRects;
338 }
339
340 Assert(pDrCmd->fFlags.Value == 0);
341 RECT *pDirtyRect;
342 if (bRectShanged)
343 {
344 pDrCmd->fFlags.bPositionRect = 1;
345 pDrCmd->RectsInfo.aRects[0] = *pContextRect;
346 pDirtyRect = &pDrCmd->RectsInfo.aRects[1];
347 }
348 else
349 pDirtyRect = &pDrCmd->RectsInfo.aRects[0];
350
351 pDrCmd->fFlags.bAddVisibleRects = 1;
352 memcpy (pDirtyRect, pRects->aRects, sizeof (RECT) * pRects->cRects);
353
354 vboxVideoCmCmdSubmit(pDrCmd, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
355 }
356 }
357 InsertHeadList(&pDevExt->ContextList3D, &pContext->ListEntry);
358 ExReleaseFastMutex(&pDevExt->ContextMutex);
359
360
361 if (pCmd)
362 vboxVideoCmCmdRelease(pCmd);
363
364 return Status;
365}
366
367
368static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
369{
370 PVBOXVDMAGG pVdma = (PVBOXVDMAGG)pvUser;
371
372 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
373 Assert(Status == STATUS_SUCCESS);
374 if (Status == STATUS_SUCCESS)
375 {
376 do
377 {
378 LIST_ENTRY CmdList;
379 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
380 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
381 if (Status == STATUS_SUCCESS)
382 {
383 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList; pCur = CmdList.Blink)
384 {
385 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
386 switch (pDr->enmType)
387 {
388 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
389 {
390 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
391 Status = vboxVdmaGgDirtyRectsProcess(pRects);
392 Assert(Status == STATUS_SUCCESS);
393 break;
394 }
395 case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
396 default:
397 AssertBreakpoint();
398 }
399 RemoveEntryList(pCur);
400 vboxVdmaGgCmdDestroy(pDr);
401 }
402 }
403 else
404 break;
405 } while (1);
406 }
407
408 /* always try to close the pipe to make sure the client side is notified */
409 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
410 Assert(Status == STATUS_SUCCESS);
411}
412
413NTSTATUS vboxVdmaGgConstruct(PVBOXVDMAGG pVdma)
414{
415 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
416 Assert(Status == STATUS_SUCCESS);
417 if (Status == STATUS_SUCCESS)
418 {
419 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pVdma);
420 Assert(Status == STATUS_SUCCESS);
421 if (Status == STATUS_SUCCESS)
422 return STATUS_SUCCESS;
423
424 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
425 Assert(tmpStatus == STATUS_SUCCESS);
426 }
427
428 /* we're here ONLY in case of an error */
429 Assert(Status != STATUS_SUCCESS);
430 return Status;
431}
432
433NTSTATUS vboxVdmaGgDestruct(PVBOXVDMAGG pVdma)
434{
435 /* this informs the server thread that it should complete all current commands and exit */
436 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
437 Assert(Status == STATUS_SUCCESS);
438 if (Status == STATUS_SUCCESS)
439 {
440 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
441 Assert(Status == STATUS_SUCCESS);
442 if (Status == STATUS_SUCCESS)
443 {
444 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
445 Assert(Status == STATUS_SUCCESS);
446 }
447 }
448
449 return Status;
450}
451
452NTSTATUS vboxVdmaGgCmdPost(PVBOXVDMAGG pVdma, PVBOXVDMAPIPE_CMD_DR pCmd)
453{
454 return vboxVdmaPipeCltCmdPut(&pVdma->CmdPipe, &pCmd->PipeHdr);
455}
456
457/* end */
458
459/*
460 * This is currently used by VDMA. It is invisible for Vdma API clients since
461 * Vdma transport may change if we choose to use another (e.g. more light-weight)
462 * transport for DMA commands submission
463 */
464
465#ifdef VBOXVDMA_WITH_VBVA
466static int vboxWddmVdmaSubmitVbva(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
467{
468 int rc;
469 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
470 {
471 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
472 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
473 }
474 else
475 {
476 AssertBreakpoint();
477 rc = VERR_INVALID_STATE;
478 }
479 return rc;
480}
481#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
482#else
483static int vboxWddmVdmaSubmitHgsmi(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
484{
485 VBoxHGSMIGuestWrite(pDevExt, offDr);
486 return VINF_SUCCESS;
487}
488#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
489#endif
490
491static int vboxVdmaInformHost (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
492{
493 int rc = VINF_SUCCESS;
494
495 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&pDevExt->u.primary.hgsmiAdapterHeap, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
496 if (pCmd)
497 {
498 pCmd->enmCtl = enmCtl;
499 pCmd->u32Offset = pInfo->CmdHeap.area.offBase;
500 pCmd->i32Result = VERR_NOT_SUPPORTED;
501
502 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
503 Assert(pHdr);
504 if (pHdr)
505 {
506 do
507 {
508 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
509 Assert(offCmd != HGSMIOFFSET_VOID);
510 if (offCmd != HGSMIOFFSET_VOID)
511 {
512 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
513 AssertRC(rc);
514 if (RT_SUCCESS(rc))
515 {
516 rc = VBoxSHGSMICommandDoneSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
517 AssertRC(rc);
518 if (RT_SUCCESS(rc))
519 {
520 rc = pCmd->i32Result;
521 AssertRC(rc);
522 }
523 break;
524 }
525 }
526 else
527 rc = VERR_INVALID_PARAMETER;
528 /* fail to submit, cancel it */
529 VBoxSHGSMICommandCancelSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
530 } while (0);
531 }
532
533 VBoxSHGSMICommandFree (&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
534 }
535 else
536 {
537 drprintf((__FUNCTION__": HGSMIHeapAlloc failed\n"));
538 rc = VERR_OUT_OF_RESOURCES;
539 }
540
541 return rc;
542}
543
544/* create a DMACommand buffer */
545int vboxVdmaCreate (PDEVICE_EXTENSION pDevExt, VBOXVDMAINFO *pInfo, ULONG offBuffer, ULONG cbBuffer)
546{
547 Assert((offBuffer & 0xfff) == 0);
548 Assert((cbBuffer & 0xfff) == 0);
549 Assert(offBuffer);
550 Assert(cbBuffer);
551
552 if((offBuffer & 0xfff)
553 || (cbBuffer & 0xfff)
554 || !offBuffer
555 || !cbBuffer)
556 {
557 drprintf((__FUNCTION__": invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
558 return VERR_INVALID_PARAMETER;
559 }
560
561 pInfo->fEnabled = FALSE;
562 PVOID pvBuffer;
563
564 int rc = VBoxMapAdapterMemory (pDevExt,
565 &pvBuffer,
566 offBuffer,
567 cbBuffer);
568 Assert(RT_SUCCESS(rc));
569 if (RT_SUCCESS(rc))
570 {
571 /* Setup a HGSMI heap within the adapter information area. */
572 rc = HGSMIHeapSetup (&pInfo->CmdHeap,
573 pvBuffer,
574 cbBuffer,
575 offBuffer,
576 false /*fOffsetBased*/);
577 Assert(RT_SUCCESS(rc));
578 if(RT_SUCCESS(rc))
579 {
580 NTSTATUS Status = vboxVdmaGgConstruct(&pInfo->DmaGg);
581 Assert(Status == STATUS_SUCCESS);
582 if (Status == STATUS_SUCCESS)
583 return VINF_SUCCESS;
584 rc = VERR_GENERAL_FAILURE;
585 }
586 else
587 drprintf((__FUNCTION__": HGSMIHeapSetup failed rc = 0x%x\n", rc));
588
589 VBoxUnmapAdapterMemory(pDevExt, &pvBuffer, cbBuffer);
590 }
591 else
592 drprintf((__FUNCTION__": VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
593
594 return rc;
595}
596
597int vboxVdmaDisable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
598{
599 dfprintf((__FUNCTION__"\n"));
600
601 Assert(pInfo->fEnabled);
602 if (!pInfo->fEnabled)
603 return VINF_ALREADY_INITIALIZED;
604
605 /* ensure nothing else is submitted */
606 pInfo->fEnabled = FALSE;
607
608 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
609 AssertRC(rc);
610 return rc;
611}
612
613int vboxVdmaEnable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
614{
615 dfprintf((__FUNCTION__"\n"));
616
617 Assert(!pInfo->fEnabled);
618 if (pInfo->fEnabled)
619 return VINF_ALREADY_INITIALIZED;
620
621 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
622 Assert(RT_SUCCESS(rc));
623 if (RT_SUCCESS(rc))
624 pInfo->fEnabled = TRUE;
625
626 return rc;
627}
628
629int vboxVdmaFlush (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
630{
631 dfprintf((__FUNCTION__"\n"));
632
633 Assert(pInfo->fEnabled);
634 if (!pInfo->fEnabled)
635 return VINF_ALREADY_INITIALIZED;
636
637 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
638 Assert(RT_SUCCESS(rc));
639
640 return rc;
641}
642
643int vboxVdmaDestroy (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
644{
645 int rc = VINF_SUCCESS;
646 NTSTATUS Status = vboxVdmaGgDestruct(&pInfo->DmaGg);
647 Assert(Status == STATUS_SUCCESS);
648 if (Status == STATUS_SUCCESS)
649 {
650 Assert(!pInfo->fEnabled);
651 if (pInfo->fEnabled)
652 rc = vboxVdmaDisable (pDevExt, pInfo);
653 VBoxUnmapAdapterMemory (pDevExt, (void**)&pInfo->CmdHeap.area.pu8Base, pInfo->CmdHeap.area.cbArea);
654 }
655 else
656 rc = VERR_GENERAL_FAILURE;
657 return rc;
658}
659
660void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
661{
662 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
663}
664
665PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
666{
667 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
668 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
669 Assert(pDr);
670 if (pDr)
671 memset (pDr, 0, cbDr);
672 else
673 drprintf((__FUNCTION__": VBoxSHGSMICommandAlloc returned NULL\n"));
674
675 return pDr;
676}
677
678static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext)
679{
680 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
681 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
682
683 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
684}
685
686static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext,
687 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
688{
689 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
690 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
691 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
692 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
693
694 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
695
696 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pDr->u64GuestContext;
697
698 if (RT_SUCCESS(pDr->rc))
699 {
700 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
701 notify.DmaCompleted.SubmissionFenceId = pDr->u32FenceId;
702 if (pContext)
703 {
704 notify.DmaCompleted.NodeOrdinal = pContext->NodeOrdinal;
705 notify.DmaCompleted.EngineOrdinal = 0;
706 pContext->uLastCompletedCmdFenceId = pDr->u32FenceId;
707 }
708 else
709 pVdma->uLastCompletedPagingBufferCmdFenceId = pDr->u32FenceId;
710 pDevExt->bSetNotifyDxDpc = TRUE;
711 }
712 else if (pDr->rc == VERR_INTERRUPTED)
713 {
714 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
715 notify.DmaPreempted.PreemptionFenceId = pDr->u32FenceId;
716 if (pContext)
717 {
718 notify.DmaPreempted.LastCompletedFenceId = pContext->uLastCompletedCmdFenceId;
719 notify.DmaPreempted.NodeOrdinal = pContext->NodeOrdinal;
720 notify.DmaPreempted.EngineOrdinal = 0;
721 }
722 else
723 notify.DmaPreempted.LastCompletedFenceId = pVdma->uLastCompletedPagingBufferCmdFenceId;
724
725 pDevExt->bSetNotifyDxDpc = TRUE;
726 }
727 else
728 {
729 AssertBreakpoint();
730 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
731 notify.DmaFaulted.FaultedFenceId = pDr->u32FenceId;
732 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
733 if (pContext)
734 {
735 notify.DmaFaulted.NodeOrdinal = pContext->NodeOrdinal;
736 notify.DmaFaulted.EngineOrdinal = 0;
737 }
738 pDevExt->bSetNotifyDxDpc = TRUE;
739 }
740
741 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
742
743 /* inform SHGSMI we want to be called at DPC later */
744 *ppfnCompletion = vboxVdmaCBufDrCompletion;
745 *ppvCompletion = pvContext;
746}
747
748int vboxVdmaCBufDrSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
749{
750 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
751 Assert(pHdr);
752 int rc = VERR_GENERAL_FAILURE;
753 if (pHdr)
754 {
755 do
756 {
757 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
758 Assert(offCmd != HGSMIOFFSET_VOID);
759 if (offCmd != HGSMIOFFSET_VOID)
760 {
761 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
762 AssertRC(rc);
763 if (RT_SUCCESS(rc))
764 {
765 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
766 AssertRC(rc);
767 break;
768 }
769 }
770 else
771 rc = VERR_INVALID_PARAMETER;
772 /* fail to submit, cancel it */
773 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
774 } while (0);
775 }
776 else
777 rc = VERR_INVALID_PARAMETER;
778 return rc;
779}
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