VirtualBox

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

Last change on this file since 30508 was 30505, checked in by vboxsync, 15 years ago

wddm/3d: visible regions working (more debug still needed)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette