VirtualBox

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

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

wddm: multimonitor support

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.2 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#include <iprt/asm.h>
22
23NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe)
24{
25 KeInitializeSpinLock(&pPipe->SinchLock);
26 KeInitializeEvent(&pPipe->Event, SynchronizationEvent, FALSE);
27 InitializeListHead(&pPipe->CmdListHead);
28 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
29 pPipe->bNeedNotify = true;
30 return STATUS_SUCCESS;
31}
32
33NTSTATUS vboxVdmaPipeSvrOpen(PVBOXVDMAPIPE pPipe)
34{
35 NTSTATUS Status = STATUS_SUCCESS;
36 KIRQL OldIrql;
37 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
38 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
39 switch (pPipe->enmState)
40 {
41 case VBOXVDMAPIPE_STATE_CREATED:
42 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
43 pPipe->bNeedNotify = false;
44 break;
45 case VBOXVDMAPIPE_STATE_OPENNED:
46 pPipe->bNeedNotify = false;
47 break;
48 default:
49 AssertBreakpoint();
50 Status = STATUS_INVALID_PIPE_STATE;
51 break;
52 }
53
54 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
55 return Status;
56}
57
58NTSTATUS vboxVdmaPipeSvrClose(PVBOXVDMAPIPE pPipe)
59{
60 NTSTATUS Status = STATUS_SUCCESS;
61 KIRQL OldIrql;
62 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
63 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
64 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
65 switch (pPipe->enmState)
66 {
67 case VBOXVDMAPIPE_STATE_CLOSING:
68 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
69 break;
70 case VBOXVDMAPIPE_STATE_CLOSED:
71 break;
72 default:
73 AssertBreakpoint();
74 Status = STATUS_INVALID_PIPE_STATE;
75 break;
76 }
77
78 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
79 return Status;
80}
81
82NTSTATUS vboxVdmaPipeCltClose(PVBOXVDMAPIPE pPipe)
83{
84 NTSTATUS Status = STATUS_SUCCESS;
85 KIRQL OldIrql;
86 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
87 bool bNeedNotify = false;
88 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
89 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
90 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
91 switch (pPipe->enmState)
92 {
93 case VBOXVDMAPIPE_STATE_OPENNED:
94 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
95 bNeedNotify = pPipe->bNeedNotify;
96 pPipe->bNeedNotify = false;
97 break;
98 case VBOXVDMAPIPE_STATE_CREATED:
99 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
100 pPipe->bNeedNotify = false;
101 break;
102 case VBOXVDMAPIPE_STATE_CLOSED:
103 break;
104 default:
105 AssertBreakpoint();
106 Status = STATUS_INVALID_PIPE_STATE;
107 break;
108 }
109
110 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
111
112 if (bNeedNotify)
113 {
114 KeSetEvent(&pPipe->Event, 0, FALSE);
115 }
116 return Status;
117}
118
119NTSTATUS vboxVdmaPipeDestruct(PVBOXVDMAPIPE pPipe)
120{
121 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
122 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
123 /* ensure the pipe is closed */
124 NTSTATUS Status = vboxVdmaPipeCltClose(pPipe);
125 Assert(Status == STATUS_SUCCESS);
126
127 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
128
129 return Status;
130}
131
132NTSTATUS vboxVdmaPipeSvrCmdGetList(PVBOXVDMAPIPE pPipe, PLIST_ENTRY pDetachHead)
133{
134 PLIST_ENTRY pEntry = NULL;
135 KIRQL OldIrql;
136 NTSTATUS Status = STATUS_SUCCESS;
137 VBOXVDMAPIPE_STATE enmState = VBOXVDMAPIPE_STATE_CLOSED;
138 do
139 {
140 bool bListEmpty = true;
141 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
142 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
143 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
144 Assert(pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED);
145 enmState = pPipe->enmState;
146 if (enmState >= VBOXVDMAPIPE_STATE_OPENNED)
147 {
148 vboxVideoLeDetach(&pPipe->CmdListHead, pDetachHead);
149 bListEmpty = !!(IsListEmpty(pDetachHead));
150 pPipe->bNeedNotify = bListEmpty;
151 }
152 else
153 {
154 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
155 Status = STATUS_INVALID_PIPE_STATE;
156 break;
157 }
158
159 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
160
161 if (!bListEmpty)
162 {
163 Assert(Status == STATUS_SUCCESS);
164 break;
165 }
166
167 if (enmState == VBOXVDMAPIPE_STATE_OPENNED)
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 else
175 {
176 Assert(enmState == VBOXVDMAPIPE_STATE_CLOSING);
177 Status = STATUS_PIPE_CLOSING;
178 break;
179 }
180 } while (1);
181
182 return Status;
183}
184
185NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd)
186{
187 NTSTATUS Status = STATUS_SUCCESS;
188 KIRQL OldIrql;
189 bool bNeedNotify = false;
190
191 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
192
193 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
194 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
195 {
196 bNeedNotify = pPipe->bNeedNotify;
197 InsertHeadList(&pPipe->CmdListHead, &pCmd->ListEntry);
198 pPipe->bNeedNotify = false;
199 }
200 else
201 Status = STATUS_INVALID_PIPE_STATE;
202
203 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
204
205 if (bNeedNotify)
206 {
207 KeSetEvent(&pPipe->Event, 0, FALSE);
208 }
209
210 return Status;
211}
212
213PVBOXVDMAPIPE_CMD_DR vboxVdmaGgCmdCreate(PVBOXVDMAGG pVdma, VBOXVDMAPIPE_CMD_TYPE enmType, uint32_t cbCmd)
214{
215 PVBOXVDMAPIPE_CMD_DR pHdr = (PVBOXVDMAPIPE_CMD_DR)vboxWddmMemAllocZero(cbCmd);
216 Assert(pHdr);
217 if (pHdr)
218 {
219 pHdr->enmType = enmType;
220 return pHdr;
221 }
222 return NULL;
223}
224
225void vboxVdmaGgCmdDestroy(PVBOXVDMAPIPE_CMD_DR pDr)
226{
227 vboxWddmMemFree(pDr);
228}
229
230
231/**
232 * helper function used for system thread creation
233 */
234static NTSTATUS vboxVdmaGgThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
235{
236 NTSTATUS fStatus;
237 HANDLE hThread;
238 OBJECT_ATTRIBUTES fObjectAttributes;
239
240 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
241
242 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
243 NULL, NULL);
244
245 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
246 &fObjectAttributes, NULL, NULL,
247 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
248 if (!NT_SUCCESS(fStatus))
249 return fStatus;
250
251 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
252 KernelMode, (PVOID*) ppThread, NULL);
253 ZwClose(hThread);
254 return STATUS_SUCCESS;
255}
256
257DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const PVBOXWDDM_RECTS_INFO pRects, PVBOXWDDM_RECTS_INFO pResult)
258{
259 pResult->cRects = 0;
260 for (uint32_t i = 0; i < pRects->cRects; ++i)
261 {
262 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[pResult->cRects]))
263 {
264 ++pResult->cRects;
265 }
266 }
267}
268
269DECLINLINE(bool) vboxVdmaDirtyRectsHasIntersections(const RECT *paRects1, uint32_t cRects1, const RECT *paRects2, uint32_t cRects2)
270{
271 RECT tmpRect;
272 for (uint32_t i = 0; i < cRects1; ++i)
273 {
274 const RECT * pRect1 = &paRects1[i];
275 for (uint32_t j = 0; j < cRects2; ++j)
276 {
277 const RECT * pRect2 = &paRects2[j];
278 if (vboxWddmRectIntersection(pRect1, pRect2, &tmpRect))
279 return true;
280 }
281 }
282 return false;
283}
284
285DECLINLINE(bool) vboxVdmaDirtyRectsIsCover(const RECT *paRects, uint32_t cRects, const RECT *paRectsCovered, uint32_t cRectsCovered)
286{
287 for (uint32_t i = 0; i < cRectsCovered; ++i)
288 {
289 const RECT * pRectCovered = &paRectsCovered[i];
290 uint32_t j = 0;
291 for (; j < cRects; ++j)
292 {
293 const RECT * pRect = &paRects[j];
294 if (vboxWddmRectIsCoveres(pRect, pRectCovered))
295 break;
296 }
297 if (j == cRects)
298 return false;
299 }
300 return true;
301}
302
303/**
304 * @param pDevExt
305 */
306static NTSTATUS vboxVdmaGgDirtyRectsProcess(VBOXVDMAPIPE_CMD_RECTSINFO *pRectsInfo)
307{
308 PVBOXWDDM_CONTEXT pContext = pRectsInfo->pContext;
309 PDEVICE_EXTENSION pDevExt = pContext->pDevice->pAdapter;
310 PVBOXWDDM_RECTS_INFO pRects = &pRectsInfo->ContextsRects.UpdateRects;
311 NTSTATUS Status = STATUS_SUCCESS;
312 PVBOXVIDEOCM_CMD_RECTS pCmd = NULL;
313 uint32_t cbCmd = VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pRects->cRects);
314 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
315 ExAcquireFastMutex(&pDevExt->ContextMutex);
316 for (PLIST_ENTRY pCur = pDevExt->ContextList3D.Flink; pCur != &pDevExt->ContextList3D; pCur = pCur->Flink)
317 {
318 if (pCur != &pContext->ListEntry)
319 {
320 PVBOXWDDM_CONTEXT pCurContext = VBOXWDDMENTRY_2_CONTEXT(pCur);
321 if (!pCmd)
322 {
323 pCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pCurContext->CmContext, cbCmd);
324 Assert(pCmd);
325 if (!pCmd)
326 {
327 Status = STATUS_NO_MEMORY;
328 break;
329 }
330 }
331 else
332 {
333 pCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdReinitForContext(pCmd, &pCurContext->CmContext);
334 }
335
336 vboxVdmaDirtyRectsCalcIntersection(&pCurContext->ViewRect, pRects, &pCmd->RectsInfo);
337 if (pCmd->RectsInfo.cRects)
338 {
339 bool bSend = false;
340 pCmd->fFlags.Value = 0;
341 pCmd->fFlags.bAddHiddenRects = 1;
342 if (pCurContext->pLastReportedRects)
343 {
344 if (pCurContext->pLastReportedRects->fFlags.bSetVisibleRects)
345 {
346 RECT *paPrevRects;
347 uint32_t cPrevRects;
348 if (pCurContext->pLastReportedRects->fFlags.bSetViewRect)
349 {
350 paPrevRects = &pCurContext->pLastReportedRects->RectsInfo.aRects[1];
351 cPrevRects = pCurContext->pLastReportedRects->RectsInfo.cRects - 1;
352 }
353 else
354 {
355 paPrevRects = &pCurContext->pLastReportedRects->RectsInfo.aRects[0];
356 cPrevRects = pCurContext->pLastReportedRects->RectsInfo.cRects;
357 }
358
359 if (vboxVdmaDirtyRectsHasIntersections(paPrevRects, cPrevRects, pCmd->RectsInfo.aRects, pCmd->RectsInfo.cRects))
360 {
361 bSend = true;
362 }
363 }
364 else
365 {
366 Assert(pCurContext->pLastReportedRects->fFlags.bAddHiddenRects);
367 if (!vboxVdmaDirtyRectsIsCover(pCurContext->pLastReportedRects->RectsInfo.aRects,
368 pCurContext->pLastReportedRects->RectsInfo.cRects,
369 pCmd->RectsInfo.aRects, pCmd->RectsInfo.cRects))
370 {
371 bSend = true;
372 }
373 }
374 }
375 else
376 bSend = true;
377
378 if (bSend)
379 {
380 if (pCurContext->pLastReportedRects)
381 vboxVideoCmCmdRelease(pCurContext->pLastReportedRects);
382 vboxVideoCmCmdRetain(pCmd);
383 pCurContext->pLastReportedRects = pCmd;
384 vboxVideoCmCmdSubmit(pCmd, VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pCmd->RectsInfo.cRects));
385 pCmd = NULL;
386 }
387 }
388 }
389 else
390 {
391 RECT * pContextRect = &pRectsInfo->ContextsRects.ContextRect;
392 bool bRectShanged = (pContext->ViewRect.left != pContextRect->left
393 || pContext->ViewRect.top != pContextRect->top
394 || pContext->ViewRect.right != pContextRect->right
395 || pContext->ViewRect.bottom != pContextRect->bottom);
396 PVBOXVIDEOCM_CMD_RECTS pDrCmd;
397
398 bool bSend = false;
399
400 if (bRectShanged)
401 {
402 uint32_t cbDrCmd = VBOXVIDEOCM_CMD_RECTS_SIZE4CRECTS(pRects->cRects + 1);
403 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pContext->CmContext, cbDrCmd);
404 Assert(pDrCmd);
405 if (!pDrCmd)
406 {
407 Status = STATUS_NO_MEMORY;
408 break;
409 }
410 pDrCmd->fFlags.Value = 0;
411 pDrCmd->RectsInfo.cRects = pRects->cRects + 1;
412 pDrCmd->fFlags.bSetViewRect = 1;
413 pDrCmd->RectsInfo.aRects[0] = *pContextRect;
414 pContext->ViewRect = *pContextRect;
415 memcpy(&pDrCmd->RectsInfo.aRects[1], pRects->aRects, sizeof (RECT) * pRects->cRects);
416 bSend = true;
417 }
418 else
419 {
420 if (pCmd)
421 {
422 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdReinitForContext(pCmd, &pContext->CmContext);
423 pCmd = NULL;
424 }
425 else
426 {
427 pDrCmd = (PVBOXVIDEOCM_CMD_RECTS)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmd);
428 Assert(pDrCmd);
429 if (!pDrCmd)
430 {
431 Status = STATUS_NO_MEMORY;
432 break;
433 }
434 }
435 pDrCmd->fFlags.Value = 0;
436 pDrCmd->RectsInfo.cRects = pRects->cRects;
437 memcpy(&pDrCmd->RectsInfo.aRects[0], pRects->aRects, sizeof (RECT) * pRects->cRects);
438
439 if (pContext->pLastReportedRects)
440 {
441 if (pContext->pLastReportedRects->fFlags.bSetVisibleRects)
442 {
443 RECT *paRects;
444 uint32_t cRects;
445 if (pContext->pLastReportedRects->fFlags.bSetViewRect)
446 {
447 paRects = &pContext->pLastReportedRects->RectsInfo.aRects[1];
448 cRects = pContext->pLastReportedRects->RectsInfo.cRects - 1;
449 }
450 else
451 {
452 paRects = &pContext->pLastReportedRects->RectsInfo.aRects[0];
453 cRects = pContext->pLastReportedRects->RectsInfo.cRects;
454 }
455 bSend = (pDrCmd->RectsInfo.cRects != cRects)
456 || memcmp(paRects, pDrCmd->RectsInfo.aRects, cRects * sizeof (RECT));
457 }
458 else
459 {
460 Assert(pContext->pLastReportedRects->fFlags.bAddHiddenRects);
461 bSend = true;
462 }
463 }
464 else
465 bSend = true;
466
467 }
468
469 Assert(pRects->cRects);
470 if (bSend)
471 {
472 if (pContext->pLastReportedRects)
473 vboxVideoCmCmdRelease(pContext->pLastReportedRects);
474
475 pDrCmd->fFlags.bSetVisibleRects = 1;
476
477 vboxVideoCmCmdRetain(pDrCmd);
478 pContext->pLastReportedRects = pDrCmd;
479 vboxVideoCmCmdSubmit(pDrCmd, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
480 }
481 else
482 {
483 if (!pCmd)
484 pCmd = pDrCmd;
485 else
486 vboxVideoCmCmdRelease(pDrCmd);
487 }
488 }
489 }
490 ExReleaseFastMutex(&pDevExt->ContextMutex);
491
492
493 if (pCmd)
494 vboxVideoCmCmdRelease(pCmd);
495
496 return Status;
497}
498
499static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF)
500{
501 NTSTATUS Status = STATUS_UNSUCCESSFUL;
502 PVBOXWDDM_CONTEXT pContext = pCF->pContext;
503 PDEVICE_EXTENSION pDevExt = pContext->pDevice->pAdapter;
504 Assert (pDevExt->pvVisibleVram);
505 if (pDevExt->pvVisibleVram)
506 {
507 PVBOXWDDM_ALLOCATION pAlloc = pCF->pAllocation;
508 Assert(pAlloc->offVram != VBOXVIDEOOFFSET_VOID);
509 if (pAlloc->offVram != VBOXVIDEOOFFSET_VOID)
510 {
511 RECT UnionRect = {0};
512 uint8_t *pvMem = pDevExt->pvVisibleVram + pAlloc->offVram;
513 UINT bpp = pAlloc->SurfDesc.bpp;
514 Assert(bpp);
515 Assert(((bpp * pAlloc->SurfDesc.width) >> 3) == pAlloc->SurfDesc.pitch);
516 switch (bpp)
517 {
518 case 32:
519 {
520 uint8_t bytestPP = bpp >> 3;
521 for (UINT i = 0; i < pCF->Rects.cRects; ++i)
522 {
523 RECT *pRect = &pCF->Rects.aRects[i];
524 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
525 {
526 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->SurfDesc.pitch) + (pRect->left * bytestPP));
527 uint32_t cRaw = pRect->right - pRect->left;
528 Assert(pRect->left >= 0);
529 Assert(pRect->right <= (LONG)pAlloc->SurfDesc.width);
530 Assert(pRect->top >= 0);
531 Assert(pRect->bottom <= (LONG)pAlloc->SurfDesc.height);
532 for (UINT j = 0; j < cRaw; ++j)
533 {
534 *pvU32Mem = pCF->Color;
535 ++pvU32Mem;
536 }
537 }
538 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
539 }
540 Status = STATUS_SUCCESS;
541 break;
542 }
543 case 16:
544 case 8:
545 default:
546 AssertBreakpoint();
547 break;
548 }
549
550 if (Status == STATUS_SUCCESS)
551 {
552 if (pCF->VidPnSourceId != D3DDDI_ID_UNINITIALIZED
553 && pAlloc->bAssigned
554#ifdef VBOXWDDM_RENDER_FROM_SHADOW
555 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
556#else
557 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE
558#endif
559 )
560 {
561 if (!vboxWddmRectIsEmpty(&UnionRect))
562 {
563 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->VidPnSourceId];
564 vboxWddmRectTranslate(&UnionRect, pSource->VScreenPos.x, pSource->VScreenPos.y);
565 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, &pSource->Vbva, &UnionRect);
566 }
567 }
568 else
569 {
570 AssertBreakpoint();
571 }
572 }
573 }
574 }
575
576
577 uint32_t cNew = ASMAtomicDecU32(&pDevExt->cDMACmdsOutstanding);
578 Assert(cNew < UINT32_MAX/2);
579
580 return Status;
581}
582
583static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
584{
585 PVBOXVDMAGG pVdma = (PVBOXVDMAGG)pvUser;
586
587 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
588 Assert(Status == STATUS_SUCCESS);
589 if (Status == STATUS_SUCCESS)
590 {
591 do
592 {
593 LIST_ENTRY CmdList;
594 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
595 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
596 if (Status == STATUS_SUCCESS)
597 {
598 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList; pCur = CmdList.Blink)
599 {
600 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
601 switch (pDr->enmType)
602 {
603 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
604 {
605 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
606 Status = vboxVdmaGgDirtyRectsProcess(pRects);
607 Assert(Status == STATUS_SUCCESS);
608 break;
609 }
610 case VBOXVDMAPIPE_CMD_TYPE_DMACMD_CLRFILL:
611 {
612 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDr;
613 Status = vboxVdmaGgDmaColorFill(pCF);
614 Assert(Status == STATUS_SUCCESS);
615 break;
616 }
617 default:
618 AssertBreakpoint();
619 }
620 RemoveEntryList(pCur);
621 vboxVdmaGgCmdDestroy(pDr);
622 }
623 }
624 else
625 break;
626 } while (1);
627 }
628
629 /* always try to close the pipe to make sure the client side is notified */
630 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
631 Assert(Status == STATUS_SUCCESS);
632}
633
634NTSTATUS vboxVdmaGgConstruct(PVBOXVDMAGG pVdma)
635{
636 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
637 Assert(Status == STATUS_SUCCESS);
638 if (Status == STATUS_SUCCESS)
639 {
640 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pVdma);
641 Assert(Status == STATUS_SUCCESS);
642 if (Status == STATUS_SUCCESS)
643 return STATUS_SUCCESS;
644
645 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
646 Assert(tmpStatus == STATUS_SUCCESS);
647 }
648
649 /* we're here ONLY in case of an error */
650 Assert(Status != STATUS_SUCCESS);
651 return Status;
652}
653
654NTSTATUS vboxVdmaGgDestruct(PVBOXVDMAGG pVdma)
655{
656 /* this informs the server thread that it should complete all current commands and exit */
657 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
658 Assert(Status == STATUS_SUCCESS);
659 if (Status == STATUS_SUCCESS)
660 {
661 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
662 Assert(Status == STATUS_SUCCESS);
663 if (Status == STATUS_SUCCESS)
664 {
665 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
666 Assert(Status == STATUS_SUCCESS);
667 }
668 }
669
670 return Status;
671}
672
673NTSTATUS vboxVdmaGgCmdSubmit(PVBOXVDMAGG pVdma, PVBOXVDMAPIPE_CMD_DR pCmd)
674{
675 return vboxVdmaPipeCltCmdPut(&pVdma->CmdPipe, &pCmd->PipeHdr);
676}
677
678/* end */
679
680/*
681 * This is currently used by VDMA. It is invisible for Vdma API clients since
682 * Vdma transport may change if we choose to use another (e.g. more light-weight)
683 * transport for DMA commands submission
684 */
685
686#ifdef VBOXVDMA_WITH_VBVA
687static int vboxWddmVdmaSubmitVbva(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
688{
689 int rc;
690 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
691 {
692 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
693 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
694 }
695 else
696 {
697 AssertBreakpoint();
698 rc = VERR_INVALID_STATE;
699 }
700 return rc;
701}
702#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
703#else
704static int vboxWddmVdmaSubmitHgsmi(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
705{
706 VBoxHGSMIGuestWrite(pDevExt, offDr);
707 return VINF_SUCCESS;
708}
709#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
710#endif
711
712static int vboxVdmaInformHost(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
713{
714 int rc = VINF_SUCCESS;
715
716 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&pDevExt->u.primary.hgsmiAdapterHeap, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
717 if (pCmd)
718 {
719 pCmd->enmCtl = enmCtl;
720 pCmd->u32Offset = pInfo->CmdHeap.area.offBase;
721 pCmd->i32Result = VERR_NOT_SUPPORTED;
722
723 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
724 Assert(pHdr);
725 if (pHdr)
726 {
727 do
728 {
729 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
730 Assert(offCmd != HGSMIOFFSET_VOID);
731 if (offCmd != HGSMIOFFSET_VOID)
732 {
733 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
734 AssertRC(rc);
735 if (RT_SUCCESS(rc))
736 {
737 rc = VBoxSHGSMICommandDoneSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
738 AssertRC(rc);
739 if (RT_SUCCESS(rc))
740 {
741 rc = pCmd->i32Result;
742 AssertRC(rc);
743 }
744 break;
745 }
746 }
747 else
748 rc = VERR_INVALID_PARAMETER;
749 /* fail to submit, cancel it */
750 VBoxSHGSMICommandCancelSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
751 } while (0);
752 }
753
754 VBoxSHGSMICommandFree (&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
755 }
756 else
757 {
758 drprintf((__FUNCTION__": HGSMIHeapAlloc failed\n"));
759 rc = VERR_OUT_OF_RESOURCES;
760 }
761
762 return rc;
763}
764
765/* create a DMACommand buffer */
766int vboxVdmaCreate(PDEVICE_EXTENSION pDevExt, VBOXVDMAINFO *pInfo, ULONG offBuffer, ULONG cbBuffer)
767{
768 Assert((offBuffer & 0xfff) == 0);
769 Assert((cbBuffer & 0xfff) == 0);
770 Assert(offBuffer);
771 Assert(cbBuffer);
772
773 if((offBuffer & 0xfff)
774 || (cbBuffer & 0xfff)
775 || !offBuffer
776 || !cbBuffer)
777 {
778 drprintf((__FUNCTION__": invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
779 return VERR_INVALID_PARAMETER;
780 }
781
782 pInfo->fEnabled = FALSE;
783 PVOID pvBuffer;
784
785 int rc = VBoxMapAdapterMemory (pDevExt,
786 &pvBuffer,
787 offBuffer,
788 cbBuffer);
789 Assert(RT_SUCCESS(rc));
790 if (RT_SUCCESS(rc))
791 {
792 /* Setup a HGSMI heap within the adapter information area. */
793 rc = HGSMIHeapSetup (&pInfo->CmdHeap,
794 pvBuffer,
795 cbBuffer,
796 offBuffer,
797 false /*fOffsetBased*/);
798 Assert(RT_SUCCESS(rc));
799 if(RT_SUCCESS(rc))
800 {
801 NTSTATUS Status = vboxVdmaGgConstruct(&pInfo->DmaGg);
802 Assert(Status == STATUS_SUCCESS);
803 if (Status == STATUS_SUCCESS)
804 return VINF_SUCCESS;
805 rc = VERR_GENERAL_FAILURE;
806 }
807 else
808 drprintf((__FUNCTION__": HGSMIHeapSetup failed rc = 0x%x\n", rc));
809
810 VBoxUnmapAdapterMemory(pDevExt, &pvBuffer, cbBuffer);
811 }
812 else
813 drprintf((__FUNCTION__": VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
814
815 return rc;
816}
817
818int vboxVdmaDisable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
819{
820 dfprintf((__FUNCTION__"\n"));
821
822 Assert(pInfo->fEnabled);
823 if (!pInfo->fEnabled)
824 return VINF_ALREADY_INITIALIZED;
825
826 /* ensure nothing else is submitted */
827 pInfo->fEnabled = FALSE;
828
829 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
830 AssertRC(rc);
831 return rc;
832}
833
834int vboxVdmaEnable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
835{
836 dfprintf((__FUNCTION__"\n"));
837
838 Assert(!pInfo->fEnabled);
839 if (pInfo->fEnabled)
840 return VINF_ALREADY_INITIALIZED;
841
842 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
843 Assert(RT_SUCCESS(rc));
844 if (RT_SUCCESS(rc))
845 pInfo->fEnabled = TRUE;
846
847 return rc;
848}
849
850int vboxVdmaFlush (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
851{
852 dfprintf((__FUNCTION__"\n"));
853
854 Assert(pInfo->fEnabled);
855 if (!pInfo->fEnabled)
856 return VINF_ALREADY_INITIALIZED;
857
858 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
859 Assert(RT_SUCCESS(rc));
860
861 return rc;
862}
863
864int vboxVdmaDestroy (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
865{
866 int rc = VINF_SUCCESS;
867 NTSTATUS Status = vboxVdmaGgDestruct(&pInfo->DmaGg);
868 Assert(Status == STATUS_SUCCESS);
869 if (Status == STATUS_SUCCESS)
870 {
871 Assert(!pInfo->fEnabled);
872 if (pInfo->fEnabled)
873 rc = vboxVdmaDisable (pDevExt, pInfo);
874 VBoxUnmapAdapterMemory (pDevExt, (void**)&pInfo->CmdHeap.area.pu8Base, pInfo->CmdHeap.area.cbArea);
875 }
876 else
877 rc = VERR_GENERAL_FAILURE;
878 return rc;
879}
880
881void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
882{
883 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
884}
885
886PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
887{
888 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
889 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
890 Assert(pDr);
891 if (pDr)
892 memset (pDr, 0, cbDr);
893 else
894 drprintf((__FUNCTION__": VBoxSHGSMICommandAlloc returned NULL\n"));
895
896 return pDr;
897}
898
899static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext)
900{
901 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
902 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
903
904 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
905}
906
907static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext,
908 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
909{
910 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
911 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
912 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
913 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
914
915 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
916
917 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pDr->u64GuestContext;
918
919 if (RT_SUCCESS(pDr->rc))
920 {
921 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
922 notify.DmaCompleted.SubmissionFenceId = pDr->u32FenceId;
923 if (pContext)
924 {
925 notify.DmaCompleted.NodeOrdinal = pContext->NodeOrdinal;
926 notify.DmaCompleted.EngineOrdinal = 0;
927 pContext->uLastCompletedCmdFenceId = pDr->u32FenceId;
928 }
929 else
930 pVdma->uLastCompletedPagingBufferCmdFenceId = pDr->u32FenceId;
931 pDevExt->bSetNotifyDxDpc = TRUE;
932 }
933 else if (pDr->rc == VERR_INTERRUPTED)
934 {
935 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
936 notify.DmaPreempted.PreemptionFenceId = pDr->u32FenceId;
937 if (pContext)
938 {
939 notify.DmaPreempted.LastCompletedFenceId = pContext->uLastCompletedCmdFenceId;
940 notify.DmaPreempted.NodeOrdinal = pContext->NodeOrdinal;
941 notify.DmaPreempted.EngineOrdinal = 0;
942 }
943 else
944 notify.DmaPreempted.LastCompletedFenceId = pVdma->uLastCompletedPagingBufferCmdFenceId;
945
946 pDevExt->bSetNotifyDxDpc = TRUE;
947 }
948 else
949 {
950 AssertBreakpoint();
951 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
952 notify.DmaFaulted.FaultedFenceId = pDr->u32FenceId;
953 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
954 if (pContext)
955 {
956 notify.DmaFaulted.NodeOrdinal = pContext->NodeOrdinal;
957 notify.DmaFaulted.EngineOrdinal = 0;
958 }
959 pDevExt->bSetNotifyDxDpc = TRUE;
960 }
961
962 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
963
964 /* inform SHGSMI we want to be called at DPC later */
965 *ppfnCompletion = vboxVdmaCBufDrCompletion;
966 *ppvCompletion = pvContext;
967}
968
969int vboxVdmaCBufDrSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
970{
971 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
972 Assert(pHdr);
973 int rc = VERR_GENERAL_FAILURE;
974 if (pHdr)
975 {
976 do
977 {
978 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
979 Assert(offCmd != HGSMIOFFSET_VOID);
980 if (offCmd != HGSMIOFFSET_VOID)
981 {
982 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
983 AssertRC(rc);
984 if (RT_SUCCESS(rc))
985 {
986 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
987 AssertRC(rc);
988 break;
989 }
990 }
991 else
992 rc = VERR_INVALID_PARAMETER;
993 /* fail to submit, cancel it */
994 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
995 } while (0);
996 }
997 else
998 rc = VERR_INVALID_PARAMETER;
999 return rc;
1000}
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