VirtualBox

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

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

wddm/3d: multi-swapchain fixes (for win7 & multi-monitor)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.4 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 PVBOXWDDM_SWAPCHAIN pSwapchain = pRectsInfo->pSwapchain;
310 PDEVICE_EXTENSION pDevExt = pContext->pDevice->pAdapter;
311 PVBOXWDDM_RECTS_INFO pRects = &pRectsInfo->ContextsRects.UpdateRects;
312 NTSTATUS Status = STATUS_SUCCESS;
313 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = NULL;
314 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects);
315 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
316 ExAcquireFastMutex(&pDevExt->ContextMutex);
317 for (PLIST_ENTRY pCur = pDevExt->SwapchainList3D.Flink; pCur != &pDevExt->SwapchainList3D; pCur = pCur->Flink)
318 {
319 if (pCur != &pSwapchain->DevExtListEntry)
320 {
321 PVBOXWDDM_SWAPCHAIN pCurSwapchain = VBOXWDDMENTRY_2_SWAPCHAIN(pCur);
322 if (!pCmdInternal)
323 {
324 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pCurSwapchain->pContext->CmContext, cbCmdInternal);
325 Assert(pCmdInternal);
326 if (!pCmdInternal)
327 {
328 Status = STATUS_NO_MEMORY;
329 break;
330 }
331 }
332 else
333 {
334 pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pCurSwapchain->pContext->CmContext);
335 }
336
337 vboxVdmaDirtyRectsCalcIntersection(&pCurSwapchain->ViewRect, pRects, &pCmdInternal->Cmd.RectsInfo);
338 if (pCmdInternal->Cmd.RectsInfo.cRects)
339 {
340 bool bSend = false;
341 pCmdInternal->Cmd.fFlags.Value = 0;
342 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
343 if (pCurSwapchain->pLastReportedRects)
344 {
345 if (pCurSwapchain->pLastReportedRects->Cmd.fFlags.bSetVisibleRects)
346 {
347 RECT *paPrevRects;
348 uint32_t cPrevRects;
349 if (pCurSwapchain->pLastReportedRects->Cmd.fFlags.bSetViewRect)
350 {
351 paPrevRects = &pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[1];
352 cPrevRects = pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects - 1;
353 }
354 else
355 {
356 paPrevRects = &pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[0];
357 cPrevRects = pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects;
358 }
359
360 if (vboxVdmaDirtyRectsHasIntersections(paPrevRects, cPrevRects,
361 pCmdInternal->Cmd.RectsInfo.aRects, pCmdInternal->Cmd.RectsInfo.cRects))
362 {
363 bSend = true;
364 }
365 }
366 else
367 {
368 Assert(pCurSwapchain->pLastReportedRects->Cmd.fFlags.bAddHiddenRects);
369 if (!vboxVdmaDirtyRectsIsCover(pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects,
370 pCurSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects,
371 pCmdInternal->Cmd.RectsInfo.aRects, pCmdInternal->Cmd.RectsInfo.cRects))
372 {
373 bSend = true;
374 }
375 }
376 }
377 else
378 bSend = true;
379
380 if (bSend)
381 {
382 if (pCurSwapchain->pLastReportedRects)
383 vboxVideoCmCmdRelease(pCurSwapchain->pLastReportedRects);
384
385 pCmdInternal->hSwapchainUm = pCurSwapchain->hSwapchainUm;
386
387 vboxVideoCmCmdRetain(pCmdInternal);
388 pCurSwapchain->pLastReportedRects = pCmdInternal;
389 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects));
390 pCmdInternal = NULL;
391 }
392 }
393 }
394 else
395 {
396 RECT * pContextRect = &pRectsInfo->ContextsRects.ContextRect;
397 bool bRectShanged = (pSwapchain->ViewRect.left != pContextRect->left
398 || pSwapchain->ViewRect.top != pContextRect->top
399 || pSwapchain->ViewRect.right != pContextRect->right
400 || pSwapchain->ViewRect.bottom != pContextRect->bottom);
401 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pDrCmdInternal;
402
403 bool bSend = false;
404
405 if (bRectShanged)
406 {
407 uint32_t cbDrCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects + 1);
408 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbDrCmdInternal);
409 Assert(pDrCmdInternal);
410 if (!pDrCmdInternal)
411 {
412 Status = STATUS_NO_MEMORY;
413 break;
414 }
415 pDrCmdInternal->Cmd.fFlags.Value = 0;
416 pDrCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects + 1;
417 pDrCmdInternal->Cmd.fFlags.bSetViewRect = 1;
418 pDrCmdInternal->Cmd.RectsInfo.aRects[0] = *pContextRect;
419 pSwapchain->ViewRect = *pContextRect;
420 memcpy(&pDrCmdInternal->Cmd.RectsInfo.aRects[1], pRects->aRects, sizeof (RECT) * pRects->cRects);
421 bSend = true;
422 }
423 else
424 {
425 if (pCmdInternal)
426 {
427 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pContext->CmContext);
428 pCmdInternal = NULL;
429 }
430 else
431 {
432 pDrCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal);
433 Assert(pDrCmdInternal);
434 if (!pDrCmdInternal)
435 {
436 Status = STATUS_NO_MEMORY;
437 break;
438 }
439 }
440 pDrCmdInternal->Cmd.fFlags.Value = 0;
441 pDrCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects;
442 memcpy(&pDrCmdInternal->Cmd.RectsInfo.aRects[0], pRects->aRects, sizeof (RECT) * pRects->cRects);
443
444 if (pSwapchain->pLastReportedRects)
445 {
446 if (pSwapchain->pLastReportedRects->Cmd.fFlags.bSetVisibleRects)
447 {
448 RECT *paRects;
449 uint32_t cRects;
450 if (pSwapchain->pLastReportedRects->Cmd.fFlags.bSetViewRect)
451 {
452 paRects = &pSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[1];
453 cRects = pSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects - 1;
454 }
455 else
456 {
457 paRects = &pSwapchain->pLastReportedRects->Cmd.RectsInfo.aRects[0];
458 cRects = pSwapchain->pLastReportedRects->Cmd.RectsInfo.cRects;
459 }
460 bSend = (pDrCmdInternal->Cmd.RectsInfo.cRects != cRects)
461 || memcmp(paRects, pDrCmdInternal->Cmd.RectsInfo.aRects, cRects * sizeof (RECT));
462 }
463 else
464 {
465 Assert(pSwapchain->pLastReportedRects->Cmd.fFlags.bAddHiddenRects);
466 bSend = true;
467 }
468 }
469 else
470 bSend = true;
471
472 }
473
474 Assert(pRects->cRects);
475 if (bSend)
476 {
477 if (pSwapchain->pLastReportedRects)
478 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
479
480 pDrCmdInternal->Cmd.fFlags.bSetVisibleRects = 1;
481 pDrCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
482
483 vboxVideoCmCmdRetain(pDrCmdInternal);
484 pSwapchain->pLastReportedRects = pDrCmdInternal;
485 vboxVideoCmCmdSubmit(pDrCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
486 }
487 else
488 {
489 if (!pCmdInternal)
490 pCmdInternal = pDrCmdInternal;
491 else
492 vboxVideoCmCmdRelease(pDrCmdInternal);
493 }
494 }
495 }
496 ExReleaseFastMutex(&pDevExt->ContextMutex);
497
498
499 if (pCmdInternal)
500 vboxVideoCmCmdRelease(pCmdInternal);
501
502 return Status;
503}
504
505static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF)
506{
507 NTSTATUS Status = STATUS_UNSUCCESSFUL;
508 PVBOXWDDM_CONTEXT pContext = pCF->pContext;
509 PDEVICE_EXTENSION pDevExt = pContext->pDevice->pAdapter;
510 Assert (pDevExt->pvVisibleVram);
511 if (pDevExt->pvVisibleVram)
512 {
513 PVBOXWDDM_ALLOCATION pAlloc = pCF->pAllocation;
514 Assert(pAlloc->offVram != VBOXVIDEOOFFSET_VOID);
515 if (pAlloc->offVram != VBOXVIDEOOFFSET_VOID)
516 {
517 RECT UnionRect = {0};
518 uint8_t *pvMem = pDevExt->pvVisibleVram + pAlloc->offVram;
519 UINT bpp = pAlloc->SurfDesc.bpp;
520 Assert(bpp);
521 Assert(((bpp * pAlloc->SurfDesc.width) >> 3) == pAlloc->SurfDesc.pitch);
522 switch (bpp)
523 {
524 case 32:
525 {
526 uint8_t bytestPP = bpp >> 3;
527 for (UINT i = 0; i < pCF->Rects.cRects; ++i)
528 {
529 RECT *pRect = &pCF->Rects.aRects[i];
530 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
531 {
532 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->SurfDesc.pitch) + (pRect->left * bytestPP));
533 uint32_t cRaw = pRect->right - pRect->left;
534 Assert(pRect->left >= 0);
535 Assert(pRect->right <= (LONG)pAlloc->SurfDesc.width);
536 Assert(pRect->top >= 0);
537 Assert(pRect->bottom <= (LONG)pAlloc->SurfDesc.height);
538 for (UINT j = 0; j < cRaw; ++j)
539 {
540 *pvU32Mem = pCF->Color;
541 ++pvU32Mem;
542 }
543 }
544 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
545 }
546 Status = STATUS_SUCCESS;
547 break;
548 }
549 case 16:
550 case 8:
551 default:
552 AssertBreakpoint();
553 break;
554 }
555
556 if (Status == STATUS_SUCCESS)
557 {
558 if (pCF->VidPnSourceId != D3DDDI_ID_UNINITIALIZED
559 && pAlloc->bAssigned
560#ifdef VBOXWDDM_RENDER_FROM_SHADOW
561 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE
562#else
563 && pAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE
564#endif
565 )
566 {
567 if (!vboxWddmRectIsEmpty(&UnionRect))
568 {
569 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->VidPnSourceId];
570 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UnionRect);
571 }
572 }
573 else
574 {
575 AssertBreakpoint();
576 }
577 }
578 }
579 }
580
581
582 uint32_t cNew = ASMAtomicDecU32(&pDevExt->cDMACmdsOutstanding);
583 Assert(cNew < UINT32_MAX/2);
584
585 return Status;
586}
587
588static VOID vboxVdmaGgWorkerThread(PVOID pvUser)
589{
590 PVBOXVDMAGG pVdma = (PVBOXVDMAGG)pvUser;
591
592 NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe);
593 Assert(Status == STATUS_SUCCESS);
594 if (Status == STATUS_SUCCESS)
595 {
596 do
597 {
598 LIST_ENTRY CmdList;
599 Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList);
600 Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING);
601 if (Status == STATUS_SUCCESS)
602 {
603 for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList; pCur = CmdList.Blink)
604 {
605 PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur);
606 switch (pDr->enmType)
607 {
608 case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO:
609 {
610 PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr;
611 Status = vboxVdmaGgDirtyRectsProcess(pRects);
612 Assert(Status == STATUS_SUCCESS);
613 break;
614 }
615 case VBOXVDMAPIPE_CMD_TYPE_DMACMD_CLRFILL:
616 {
617 PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDr;
618 Status = vboxVdmaGgDmaColorFill(pCF);
619 Assert(Status == STATUS_SUCCESS);
620 break;
621 }
622 default:
623 AssertBreakpoint();
624 }
625 RemoveEntryList(pCur);
626 vboxVdmaGgCmdDestroy(pDr);
627 }
628 }
629 else
630 break;
631 } while (1);
632 }
633
634 /* always try to close the pipe to make sure the client side is notified */
635 Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe);
636 Assert(Status == STATUS_SUCCESS);
637}
638
639NTSTATUS vboxVdmaGgConstruct(PVBOXVDMAGG pVdma)
640{
641 NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe);
642 Assert(Status == STATUS_SUCCESS);
643 if (Status == STATUS_SUCCESS)
644 {
645 Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pVdma);
646 Assert(Status == STATUS_SUCCESS);
647 if (Status == STATUS_SUCCESS)
648 return STATUS_SUCCESS;
649
650 NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
651 Assert(tmpStatus == STATUS_SUCCESS);
652 }
653
654 /* we're here ONLY in case of an error */
655 Assert(Status != STATUS_SUCCESS);
656 return Status;
657}
658
659NTSTATUS vboxVdmaGgDestruct(PVBOXVDMAGG pVdma)
660{
661 /* this informs the server thread that it should complete all current commands and exit */
662 NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe);
663 Assert(Status == STATUS_SUCCESS);
664 if (Status == STATUS_SUCCESS)
665 {
666 Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
667 Assert(Status == STATUS_SUCCESS);
668 if (Status == STATUS_SUCCESS)
669 {
670 Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe);
671 Assert(Status == STATUS_SUCCESS);
672 }
673 }
674
675 return Status;
676}
677
678NTSTATUS vboxVdmaGgCmdSubmit(PVBOXVDMAGG pVdma, PVBOXVDMAPIPE_CMD_DR pCmd)
679{
680 return vboxVdmaPipeCltCmdPut(&pVdma->CmdPipe, &pCmd->PipeHdr);
681}
682
683/* end */
684
685#ifdef VBOXVDMA
686/*
687 * This is currently used by VDMA. It is invisible for Vdma API clients since
688 * Vdma transport may change if we choose to use another (e.g. more light-weight)
689 * transport for DMA commands submission
690 */
691
692#ifdef VBOXVDMA_WITH_VBVA
693static int vboxWddmVdmaSubmitVbva(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
694{
695 int rc;
696 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
697 {
698 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
699 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
700 }
701 else
702 {
703 AssertBreakpoint();
704 rc = VERR_INVALID_STATE;
705 }
706 return rc;
707}
708#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
709#else
710static int vboxWddmVdmaSubmitHgsmi(struct _DEVICE_EXTENSION* pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
711{
712 VBoxHGSMIGuestWrite(pDevExt, offDr);
713 return VINF_SUCCESS;
714}
715#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
716#endif
717
718static int vboxVdmaInformHost(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
719{
720 int rc = VINF_SUCCESS;
721
722 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&pDevExt->u.primary.hgsmiAdapterHeap, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
723 if (pCmd)
724 {
725 pCmd->enmCtl = enmCtl;
726 pCmd->u32Offset = pInfo->CmdHeap.area.offBase;
727 pCmd->i32Result = VERR_NOT_SUPPORTED;
728
729 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
730 Assert(pHdr);
731 if (pHdr)
732 {
733 do
734 {
735 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
736 Assert(offCmd != HGSMIOFFSET_VOID);
737 if (offCmd != HGSMIOFFSET_VOID)
738 {
739 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
740 AssertRC(rc);
741 if (RT_SUCCESS(rc))
742 {
743 rc = VBoxSHGSMICommandDoneSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
744 AssertRC(rc);
745 if (RT_SUCCESS(rc))
746 {
747 rc = pCmd->i32Result;
748 AssertRC(rc);
749 }
750 break;
751 }
752 }
753 else
754 rc = VERR_INVALID_PARAMETER;
755 /* fail to submit, cancel it */
756 VBoxSHGSMICommandCancelSynch(&pDevExt->u.primary.hgsmiAdapterHeap, pHdr);
757 } while (0);
758 }
759
760 VBoxSHGSMICommandFree (&pDevExt->u.primary.hgsmiAdapterHeap, pCmd);
761 }
762 else
763 {
764 drprintf((__FUNCTION__": HGSMIHeapAlloc failed\n"));
765 rc = VERR_OUT_OF_RESOURCES;
766 }
767
768 return rc;
769}
770#endif
771
772/* create a DMACommand buffer */
773int vboxVdmaCreate(PDEVICE_EXTENSION pDevExt, VBOXVDMAINFO *pInfo
774#ifdef VBOXVDMA
775 , ULONG offBuffer, ULONG cbBuffer
776#endif
777 )
778{
779 int rc;
780 pInfo->fEnabled = FALSE;
781
782#ifdef VBOXVDMA
783 Assert((offBuffer & 0xfff) == 0);
784 Assert((cbBuffer & 0xfff) == 0);
785 Assert(offBuffer);
786 Assert(cbBuffer);
787
788 if((offBuffer & 0xfff)
789 || (cbBuffer & 0xfff)
790 || !offBuffer
791 || !cbBuffer)
792 {
793 drprintf((__FUNCTION__": invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
794 return VERR_INVALID_PARAMETER;
795 }
796 PVOID pvBuffer;
797
798 rc = VBoxMapAdapterMemory (pDevExt,
799 &pvBuffer,
800 offBuffer,
801 cbBuffer);
802 Assert(RT_SUCCESS(rc));
803 if (RT_SUCCESS(rc))
804 {
805 /* Setup a HGSMI heap within the adapter information area. */
806 rc = HGSMIHeapSetup (&pInfo->CmdHeap,
807 pvBuffer,
808 cbBuffer,
809 offBuffer,
810 false /*fOffsetBased*/);
811 Assert(RT_SUCCESS(rc));
812 if(RT_SUCCESS(rc))
813#endif
814 {
815 NTSTATUS Status = vboxVdmaGgConstruct(&pInfo->DmaGg);
816 Assert(Status == STATUS_SUCCESS);
817 if (Status == STATUS_SUCCESS)
818 return VINF_SUCCESS;
819 rc = VERR_GENERAL_FAILURE;
820 }
821#ifdef VBOXVDMA
822 else
823 drprintf((__FUNCTION__": HGSMIHeapSetup failed rc = 0x%x\n", rc));
824
825 VBoxUnmapAdapterMemory(pDevExt, &pvBuffer, cbBuffer);
826 }
827 else
828 drprintf((__FUNCTION__": VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
829#endif
830 return rc;
831}
832
833int vboxVdmaDisable (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 /* ensure nothing else is submitted */
842 pInfo->fEnabled = FALSE;
843#ifdef VBOXVDMA
844 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
845 AssertRC(rc);
846 return rc;
847#else
848 return VINF_SUCCESS;
849#endif
850}
851
852int vboxVdmaEnable (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
853{
854 dfprintf((__FUNCTION__"\n"));
855
856 Assert(!pInfo->fEnabled);
857 if (pInfo->fEnabled)
858 return VINF_ALREADY_INITIALIZED;
859#ifdef VBOXVDMA
860 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
861 Assert(RT_SUCCESS(rc));
862 if (RT_SUCCESS(rc))
863 pInfo->fEnabled = TRUE;
864
865 return rc;
866#else
867 return VINF_SUCCESS;
868#endif
869}
870
871#ifdef VBOXVDMA
872int vboxVdmaFlush (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
873{
874 dfprintf((__FUNCTION__"\n"));
875
876 Assert(pInfo->fEnabled);
877 if (!pInfo->fEnabled)
878 return VINF_ALREADY_INITIALIZED;
879
880 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
881 Assert(RT_SUCCESS(rc));
882
883 return rc;
884}
885#endif
886
887int vboxVdmaDestroy (PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo)
888{
889 int rc = VINF_SUCCESS;
890 NTSTATUS Status = vboxVdmaGgDestruct(&pInfo->DmaGg);
891 Assert(Status == STATUS_SUCCESS);
892 if (Status == STATUS_SUCCESS)
893 {
894 Assert(!pInfo->fEnabled);
895 if (pInfo->fEnabled)
896 rc = vboxVdmaDisable (pDevExt, pInfo);
897#ifdef VBOXVDMA
898 VBoxUnmapAdapterMemory (pDevExt, (void**)&pInfo->CmdHeap.area.pu8Base, pInfo->CmdHeap.area.cbArea);
899#endif
900 }
901 else
902 rc = VERR_GENERAL_FAILURE;
903 return rc;
904}
905
906#ifdef VBOXVDMA
907void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
908{
909 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
910}
911
912PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
913{
914 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
915 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
916 Assert(pDr);
917 if (pDr)
918 memset (pDr, 0, cbDr);
919 else
920 drprintf((__FUNCTION__": VBoxSHGSMICommandAlloc returned NULL\n"));
921
922 return pDr;
923}
924
925static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext)
926{
927 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
928 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
929
930 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
931}
932
933static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(struct _HGSMIHEAP * pHeap, void *pvCmd, void *pvContext,
934 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
935{
936 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pvContext;
937 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
938 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
939 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
940
941 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
942
943 PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pDr->u64GuestContext;
944
945 if (RT_SUCCESS(pDr->rc))
946 {
947 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
948 notify.DmaCompleted.SubmissionFenceId = pDr->u32FenceId;
949 if (pContext)
950 {
951 notify.DmaCompleted.NodeOrdinal = pContext->NodeOrdinal;
952 notify.DmaCompleted.EngineOrdinal = 0;
953 pContext->uLastCompletedCmdFenceId = pDr->u32FenceId;
954 }
955 else
956 pVdma->uLastCompletedPagingBufferCmdFenceId = pDr->u32FenceId;
957 pDevExt->bSetNotifyDxDpc = TRUE;
958 }
959 else if (pDr->rc == VERR_INTERRUPTED)
960 {
961 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
962 notify.DmaPreempted.PreemptionFenceId = pDr->u32FenceId;
963 if (pContext)
964 {
965 notify.DmaPreempted.LastCompletedFenceId = pContext->uLastCompletedCmdFenceId;
966 notify.DmaPreempted.NodeOrdinal = pContext->NodeOrdinal;
967 notify.DmaPreempted.EngineOrdinal = 0;
968 }
969 else
970 notify.DmaPreempted.LastCompletedFenceId = pVdma->uLastCompletedPagingBufferCmdFenceId;
971
972 pDevExt->bSetNotifyDxDpc = TRUE;
973 }
974 else
975 {
976 AssertBreakpoint();
977 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
978 notify.DmaFaulted.FaultedFenceId = pDr->u32FenceId;
979 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
980 if (pContext)
981 {
982 notify.DmaFaulted.NodeOrdinal = pContext->NodeOrdinal;
983 notify.DmaFaulted.EngineOrdinal = 0;
984 }
985 pDevExt->bSetNotifyDxDpc = TRUE;
986 }
987
988 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
989
990 /* inform SHGSMI we want to be called at DPC later */
991 *ppfnCompletion = vboxVdmaCBufDrCompletion;
992 *ppvCompletion = pvContext;
993}
994
995int vboxVdmaCBufDrSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
996{
997 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
998 Assert(pHdr);
999 int rc = VERR_GENERAL_FAILURE;
1000 if (pHdr)
1001 {
1002 do
1003 {
1004 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1005 Assert(offCmd != HGSMIOFFSET_VOID);
1006 if (offCmd != HGSMIOFFSET_VOID)
1007 {
1008 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1009 AssertRC(rc);
1010 if (RT_SUCCESS(rc))
1011 {
1012 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1013 AssertRC(rc);
1014 break;
1015 }
1016 }
1017 else
1018 rc = VERR_INVALID_PARAMETER;
1019 /* fail to submit, cancel it */
1020 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1021 } while (0);
1022 }
1023 else
1024 rc = VERR_INVALID_PARAMETER;
1025 return rc;
1026}
1027#endif
Note: See TracBrowser for help on using the repository browser.

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