VirtualBox

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

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

wddm/2d: bugfix, video working (debug still needed)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.1 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) * bytestPP;
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 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, &pSource->Vbva, &UnionRect);
565 }
566 }
567 else
568 {
569 AssertBreakpoint();
570 }
571 }
572 }
573 }
574
575
576 uint32_t cNew = ASMAtomicDecU32(&pDevExt->cDMACmdsOutstanding);
577 Assert(cNew < UINT32_MAX/2);
578
579 return Status;
580}
581
582static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
583{
584 PVBOXVDMAGG pVdma = (PVBOXVDMAGG)pvUser;
585
586 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
587 Assert(Status == STATUS_SUCCESS);
588 if (Status == STATUS_SUCCESS)
589 {
590 do
591 {
592 LIST_ENTRY CmdList;
593 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
594 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
595 if (Status == STATUS_SUCCESS)
596 {
597 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList; pCur = CmdList.Blink)
598 {
599 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
600 switch (pDr->enmType)
601 {
602 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
603 {
604 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
605 Status = vboxVdmaGgDirtyRectsProcess(pRects);
606 Assert(Status == STATUS_SUCCESS);
607 break;
608 }
609 case VBOXVDMAPIPE_CMD_TYPE_DMACMD_CLRFILL:
610 {
611 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDr;
612 Status = vboxVdmaGgDmaColorFill(pCF);
613 Assert(Status == STATUS_SUCCESS);
614 break;
615 }
616 default:
617 AssertBreakpoint();
618 }
619 RemoveEntryList(pCur);
620 vboxVdmaGgCmdDestroy(pDr);
621 }
622 }
623 else
624 break;
625 } while (1);
626 }
627
628 /* always try to close the pipe to make sure the client side is notified */
629 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
630 Assert(Status == STATUS_SUCCESS);
631}
632
633NTSTATUS vboxVdmaGgConstruct(PVBOXVDMAGG pVdma)
634{
635 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
636 Assert(Status == STATUS_SUCCESS);
637 if (Status == STATUS_SUCCESS)
638 {
639 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pVdma);
640 Assert(Status == STATUS_SUCCESS);
641 if (Status == STATUS_SUCCESS)
642 return STATUS_SUCCESS;
643
644 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
645 Assert(tmpStatus == STATUS_SUCCESS);
646 }
647
648 /* we're here ONLY in case of an error */
649 Assert(Status != STATUS_SUCCESS);
650 return Status;
651}
652
653NTSTATUS vboxVdmaGgDestruct(PVBOXVDMAGG pVdma)
654{
655 /* this informs the server thread that it should complete all current commands and exit */
656 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
657 Assert(Status == STATUS_SUCCESS);
658 if (Status == STATUS_SUCCESS)
659 {
660 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
661 Assert(Status == STATUS_SUCCESS);
662 if (Status == STATUS_SUCCESS)
663 {
664 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
665 Assert(Status == STATUS_SUCCESS);
666 }
667 }
668
669 return Status;
670}
671
672NTSTATUS vboxVdmaGgCmdSubmit(PVBOXVDMAGG pVdma, PVBOXVDMAPIPE_CMD_DR pCmd)
673{
674 return vboxVdmaPipeCltCmdPut(&pVdma->CmdPipe, &pCmd->PipeHdr);
675}
676
677/* end */
678
679/*
680 * This is currently used by VDMA. It is invisible for Vdma API clients since
681 * Vdma transport may change if we choose to use another (e.g. more light-weight)
682 * transport for DMA commands submission
683 */
684
685#ifdef VBOXVDMA_WITH_VBVA
686static int vboxWddmVdmaSubmitVbva(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
687{
688 int rc;
689 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
690 {
691 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
692 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
693 }
694 else
695 {
696 AssertBreakpoint();
697 rc = VERR_INVALID_STATE;
698 }
699 return rc;
700}
701#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
702#else
703static int vboxWddmVdmaSubmitHgsmi(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
704{
705 VBoxHGSMIGuestWrite(pDevExt, offDr);
706 return VINF_SUCCESS;
707}
708#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
709#endif
710
711static int vboxVdmaInformHost(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
712{
713 int rc = VINF_SUCCESS;
714
715 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&pDevExt->u.primary.hgsmiAdapterHeap, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
716 if (pCmd)
717 {
718 pCmd->enmCtl = enmCtl;
719 pCmd->u32Offset = pInfo->CmdHeap.area.offBase;
720 pCmd->i32Result = VERR_NOT_SUPPORTED;
721
722 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
723 Assert(pHdr);
724 if (pHdr)
725 {
726 do
727 {
728 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
729 Assert(offCmd != HGSMIOFFSET_VOID);
730 if (offCmd != HGSMIOFFSET_VOID)
731 {
732 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
733 AssertRC(rc);
734 if (RT_SUCCESS(rc))
735 {
736 rc = VBoxSHGSMICommandDoneSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
737 AssertRC(rc);
738 if (RT_SUCCESS(rc))
739 {
740 rc = pCmd->i32Result;
741 AssertRC(rc);
742 }
743 break;
744 }
745 }
746 else
747 rc = VERR_INVALID_PARAMETER;
748 /* fail to submit, cancel it */
749 VBoxSHGSMICommandCancelSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
750 } while (0);
751 }
752
753 VBoxSHGSMICommandFree (&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
754 }
755 else
756 {
757 drprintf((__FUNCTION__": HGSMIHeapAlloc failed\n"));
758 rc = VERR_OUT_OF_RESOURCES;
759 }
760
761 return rc;
762}
763
764/* create a DMACommand buffer */
765int vboxVdmaCreate(PDEVICE_EXTENSION pDevExt, VBOXVDMAINFO *pInfo, ULONG offBuffer, ULONG cbBuffer)
766{
767 Assert((offBuffer & 0xfff) == 0);
768 Assert((cbBuffer & 0xfff) == 0);
769 Assert(offBuffer);
770 Assert(cbBuffer);
771
772 if((offBuffer & 0xfff)
773 || (cbBuffer & 0xfff)
774 || !offBuffer
775 || !cbBuffer)
776 {
777 drprintf((__FUNCTION__": invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
778 return VERR_INVALID_PARAMETER;
779 }
780
781 pInfo->fEnabled = FALSE;
782 PVOID pvBuffer;
783
784 int rc = VBoxMapAdapterMemory (pDevExt,
785 &pvBuffer,
786 offBuffer,
787 cbBuffer);
788 Assert(RT_SUCCESS(rc));
789 if (RT_SUCCESS(rc))
790 {
791 /* Setup a HGSMI heap within the adapter information area. */
792 rc = HGSMIHeapSetup (&pInfo->CmdHeap,
793 pvBuffer,
794 cbBuffer,
795 offBuffer,
796 false /*fOffsetBased*/);
797 Assert(RT_SUCCESS(rc));
798 if(RT_SUCCESS(rc))
799 {
800 NTSTATUS Status = vboxVdmaGgConstruct(&pInfo->DmaGg);
801 Assert(Status == STATUS_SUCCESS);
802 if (Status == STATUS_SUCCESS)
803 return VINF_SUCCESS;
804 rc = VERR_GENERAL_FAILURE;
805 }
806 else
807 drprintf((__FUNCTION__": HGSMIHeapSetup failed rc = 0x%x\n", rc));
808
809 VBoxUnmapAdapterMemory(pDevExt, &pvBuffer, cbBuffer);
810 }
811 else
812 drprintf((__FUNCTION__": VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
813
814 return rc;
815}
816
817int vboxVdmaDisable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
818{
819 dfprintf((__FUNCTION__"\n"));
820
821 Assert(pInfo->fEnabled);
822 if (!pInfo->fEnabled)
823 return VINF_ALREADY_INITIALIZED;
824
825 /* ensure nothing else is submitted */
826 pInfo->fEnabled = FALSE;
827
828 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
829 AssertRC(rc);
830 return rc;
831}
832
833int vboxVdmaEnable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
834{
835 dfprintf((__FUNCTION__"\n"));
836
837 Assert(!pInfo->fEnabled);
838 if (pInfo->fEnabled)
839 return VINF_ALREADY_INITIALIZED;
840
841 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
842 Assert(RT_SUCCESS(rc));
843 if (RT_SUCCESS(rc))
844 pInfo->fEnabled = TRUE;
845
846 return rc;
847}
848
849int vboxVdmaFlush (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
850{
851 dfprintf((__FUNCTION__"\n"));
852
853 Assert(pInfo->fEnabled);
854 if (!pInfo->fEnabled)
855 return VINF_ALREADY_INITIALIZED;
856
857 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
858 Assert(RT_SUCCESS(rc));
859
860 return rc;
861}
862
863int vboxVdmaDestroy (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
864{
865 int rc = VINF_SUCCESS;
866 NTSTATUS Status = vboxVdmaGgDestruct(&pInfo->DmaGg);
867 Assert(Status == STATUS_SUCCESS);
868 if (Status == STATUS_SUCCESS)
869 {
870 Assert(!pInfo->fEnabled);
871 if (pInfo->fEnabled)
872 rc = vboxVdmaDisable (pDevExt, pInfo);
873 VBoxUnmapAdapterMemory (pDevExt, (void**)&pInfo->CmdHeap.area.pu8Base, pInfo->CmdHeap.area.cbArea);
874 }
875 else
876 rc = VERR_GENERAL_FAILURE;
877 return rc;
878}
879
880void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
881{
882 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
883}
884
885PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
886{
887 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
888 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
889 Assert(pDr);
890 if (pDr)
891 memset (pDr, 0, cbDr);
892 else
893 drprintf((__FUNCTION__": VBoxSHGSMICommandAlloc returned NULL\n"));
894
895 return pDr;
896}
897
898static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext)
899{
900 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
901 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
902
903 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
904}
905
906static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext,
907 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
908{
909 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
910 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
911 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
912 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
913
914 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
915
916 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pDr->u64GuestContext;
917
918 if (RT_SUCCESS(pDr->rc))
919 {
920 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
921 notify.DmaCompleted.SubmissionFenceId = pDr->u32FenceId;
922 if (pContext)
923 {
924 notify.DmaCompleted.NodeOrdinal = pContext->NodeOrdinal;
925 notify.DmaCompleted.EngineOrdinal = 0;
926 pContext->uLastCompletedCmdFenceId = pDr->u32FenceId;
927 }
928 else
929 pVdma->uLastCompletedPagingBufferCmdFenceId = pDr->u32FenceId;
930 pDevExt->bSetNotifyDxDpc = TRUE;
931 }
932 else if (pDr->rc == VERR_INTERRUPTED)
933 {
934 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
935 notify.DmaPreempted.PreemptionFenceId = pDr->u32FenceId;
936 if (pContext)
937 {
938 notify.DmaPreempted.LastCompletedFenceId = pContext->uLastCompletedCmdFenceId;
939 notify.DmaPreempted.NodeOrdinal = pContext->NodeOrdinal;
940 notify.DmaPreempted.EngineOrdinal = 0;
941 }
942 else
943 notify.DmaPreempted.LastCompletedFenceId = pVdma->uLastCompletedPagingBufferCmdFenceId;
944
945 pDevExt->bSetNotifyDxDpc = TRUE;
946 }
947 else
948 {
949 AssertBreakpoint();
950 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
951 notify.DmaFaulted.FaultedFenceId = pDr->u32FenceId;
952 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
953 if (pContext)
954 {
955 notify.DmaFaulted.NodeOrdinal = pContext->NodeOrdinal;
956 notify.DmaFaulted.EngineOrdinal = 0;
957 }
958 pDevExt->bSetNotifyDxDpc = TRUE;
959 }
960
961 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
962
963 /* inform SHGSMI we want to be called at DPC later */
964 *ppfnCompletion = vboxVdmaCBufDrCompletion;
965 *ppvCompletion = pvContext;
966}
967
968int vboxVdmaCBufDrSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
969{
970 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
971 Assert(pHdr);
972 int rc = VERR_GENERAL_FAILURE;
973 if (pHdr)
974 {
975 do
976 {
977 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
978 Assert(offCmd != HGSMIOFFSET_VOID);
979 if (offCmd != HGSMIOFFSET_VOID)
980 {
981 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
982 AssertRC(rc);
983 if (RT_SUCCESS(rc))
984 {
985 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
986 AssertRC(rc);
987 break;
988 }
989 }
990 else
991 rc = VERR_INVALID_PARAMETER;
992 /* fail to submit, cancel it */
993 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
994 } while (0);
995 }
996 else
997 rc = VERR_INVALID_PARAMETER;
998 return rc;
999}
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