VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.cpp@ 51111

Last change on this file since 51111 was 50987, checked in by vboxsync, 11 years ago

wddm: do not allocate VRAM for host-side or dummy allocations

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.2 KB
Line 
1/* $Id: VBoxMPVdma.cpp 50987 2014-04-07 17:08:07Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMPWddm.h"
20#include "common/VBoxMPCommon.h"
21#include "VBoxMPVdma.h"
22#include "VBoxMPVhwa.h"
23#include <iprt/asm.h>
24#include "VBoxMPCr.h"
25#include <iprt/mem.h>
26
27#ifdef VBOX_WITH_CROGL
28# include <packer.h>
29#endif
30
31NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe)
32{
33 KeInitializeSpinLock(&pPipe->SinchLock);
34 KeInitializeEvent(&pPipe->Event, SynchronizationEvent, FALSE);
35 InitializeListHead(&pPipe->CmdListHead);
36 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
37 pPipe->bNeedNotify = true;
38 return STATUS_SUCCESS;
39}
40
41NTSTATUS vboxVdmaPipeSvrOpen(PVBOXVDMAPIPE pPipe)
42{
43 NTSTATUS Status = STATUS_SUCCESS;
44 KIRQL OldIrql;
45 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
46 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
47 switch (pPipe->enmState)
48 {
49 case VBOXVDMAPIPE_STATE_CREATED:
50 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
51 pPipe->bNeedNotify = false;
52 break;
53 case VBOXVDMAPIPE_STATE_OPENNED:
54 pPipe->bNeedNotify = false;
55 break;
56 default:
57 AssertBreakpoint();
58 Status = STATUS_INVALID_PIPE_STATE;
59 break;
60 }
61
62 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
63 return Status;
64}
65
66NTSTATUS vboxVdmaPipeSvrClose(PVBOXVDMAPIPE pPipe)
67{
68 NTSTATUS Status = STATUS_SUCCESS;
69 KIRQL OldIrql;
70 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
71 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
72 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
73 switch (pPipe->enmState)
74 {
75 case VBOXVDMAPIPE_STATE_CLOSING:
76 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
77 break;
78 case VBOXVDMAPIPE_STATE_CLOSED:
79 break;
80 default:
81 AssertBreakpoint();
82 Status = STATUS_INVALID_PIPE_STATE;
83 break;
84 }
85
86 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
87 return Status;
88}
89
90NTSTATUS vboxVdmaPipeCltClose(PVBOXVDMAPIPE pPipe)
91{
92 NTSTATUS Status = STATUS_SUCCESS;
93 KIRQL OldIrql;
94 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
95 bool bNeedNotify = false;
96 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
97 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
98 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
99 switch (pPipe->enmState)
100 {
101 case VBOXVDMAPIPE_STATE_OPENNED:
102 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
103 bNeedNotify = pPipe->bNeedNotify;
104 pPipe->bNeedNotify = false;
105 break;
106 case VBOXVDMAPIPE_STATE_CREATED:
107 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
108 pPipe->bNeedNotify = false;
109 break;
110 case VBOXVDMAPIPE_STATE_CLOSED:
111 break;
112 default:
113 AssertBreakpoint();
114 Status = STATUS_INVALID_PIPE_STATE;
115 break;
116 }
117
118 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
119
120 if (bNeedNotify)
121 {
122 KeSetEvent(&pPipe->Event, 0, FALSE);
123 }
124 return Status;
125}
126
127NTSTATUS vboxVdmaPipeDestruct(PVBOXVDMAPIPE pPipe)
128{
129 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
130 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
131 /* ensure the pipe is closed */
132 NTSTATUS Status = vboxVdmaPipeCltClose(pPipe);
133 Assert(Status == STATUS_SUCCESS);
134
135 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
136
137 return Status;
138}
139
140NTSTATUS vboxVdmaPipeSvrCmdGetList(PVBOXVDMAPIPE pPipe, PLIST_ENTRY pDetachHead)
141{
142 PLIST_ENTRY pEntry = NULL;
143 KIRQL OldIrql;
144 NTSTATUS Status = STATUS_SUCCESS;
145 VBOXVDMAPIPE_STATE enmState = VBOXVDMAPIPE_STATE_CLOSED;
146 do
147 {
148 bool bListEmpty = true;
149 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
150 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
151 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
152 Assert(pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED);
153 enmState = pPipe->enmState;
154 if (enmState >= VBOXVDMAPIPE_STATE_OPENNED)
155 {
156 vboxVideoLeDetach(&pPipe->CmdListHead, pDetachHead);
157 bListEmpty = !!(IsListEmpty(pDetachHead));
158 pPipe->bNeedNotify = bListEmpty;
159 }
160 else
161 {
162 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
163 Status = STATUS_INVALID_PIPE_STATE;
164 break;
165 }
166
167 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
168
169 if (!bListEmpty)
170 {
171 Assert(Status == STATUS_SUCCESS);
172 break;
173 }
174
175 if (enmState == VBOXVDMAPIPE_STATE_OPENNED)
176 {
177 Status = KeWaitForSingleObject(&pPipe->Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
178 Assert(Status == STATUS_SUCCESS);
179 if (Status != STATUS_SUCCESS)
180 break;
181 }
182 else
183 {
184 Assert(enmState == VBOXVDMAPIPE_STATE_CLOSING);
185 Status = STATUS_PIPE_CLOSING;
186 break;
187 }
188 } while (1);
189
190 return Status;
191}
192
193NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd)
194{
195 NTSTATUS Status = STATUS_SUCCESS;
196 KIRQL OldIrql;
197 bool bNeedNotify = false;
198
199 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
200
201 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
202 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
203 {
204 bNeedNotify = pPipe->bNeedNotify;
205 InsertHeadList(&pPipe->CmdListHead, &pCmd->ListEntry);
206 pPipe->bNeedNotify = false;
207 }
208 else
209 Status = STATUS_INVALID_PIPE_STATE;
210
211 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
212
213 if (bNeedNotify)
214 {
215 KeSetEvent(&pPipe->Event, 0, FALSE);
216 }
217
218 return Status;
219}
220
221DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const VBOXWDDM_RECTS_INFO *pRects, PVBOXWDDM_RECTS_INFO pResult)
222{
223 uint32_t cRects = 0;
224 for (uint32_t i = 0; i < pRects->cRects; ++i)
225 {
226 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[cRects]))
227 {
228 ++cRects;
229 }
230 }
231
232 pResult->cRects = cRects;
233}
234
235DECLINLINE(bool) vboxVdmaDirtyRectsHasIntersections(const RECT *paRects1, uint32_t cRects1, const RECT *paRects2, uint32_t cRects2)
236{
237 RECT tmpRect;
238 for (uint32_t i = 0; i < cRects1; ++i)
239 {
240 const RECT * pRect1 = &paRects1[i];
241 for (uint32_t j = 0; j < cRects2; ++j)
242 {
243 const RECT * pRect2 = &paRects2[j];
244 if (vboxWddmRectIntersection(pRect1, pRect2, &tmpRect))
245 return true;
246 }
247 }
248 return false;
249}
250
251DECLINLINE(bool) vboxVdmaDirtyRectsIsCover(const RECT *paRects, uint32_t cRects, const RECT *paRectsCovered, uint32_t cRectsCovered)
252{
253 for (uint32_t i = 0; i < cRectsCovered; ++i)
254 {
255 const RECT * pRectCovered = &paRectsCovered[i];
256 uint32_t j = 0;
257 for (; j < cRects; ++j)
258 {
259 const RECT * pRect = &paRects[j];
260 if (vboxWddmRectIsCoveres(pRect, pRectCovered))
261 break;
262 }
263 if (j == cRects)
264 return false;
265 }
266 return true;
267}
268#ifdef VBOX_WITH_CROGL
269NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain)
270{
271 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
272 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(0);
273 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal =
274 (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pSwapchain->pContext->CmContext, cbCmdInternal);
275 Assert(pCmdInternal);
276 if (pCmdInternal)
277 {
278 pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
279 pCmdInternal->Cmd.fFlags.Value = 0;
280 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
281 pCmdInternal->Cmd.fFlags.bHide = 1;
282 pCmdInternal->Cmd.RectsInfo.cRects = 0;
283 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
284 return STATUS_SUCCESS;
285 }
286 return STATUS_NO_MEMORY;
287}
288#endif
289static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y)
290{
291 vboxWddmRectTranslate(&pRects->ContextRect, x, y);
292
293 for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i)
294 {
295 vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y);
296 }
297}
298
299static VBOXVDMAPIPE_RECTS * vboxWddmBltPipeRectsDup(const VBOXVDMAPIPE_RECTS *pRects)
300{
301 const size_t cbDup = RT_OFFSETOF(VBOXVDMAPIPE_RECTS, UpdateRects.aRects[pRects->UpdateRects.cRects]);
302 VBOXVDMAPIPE_RECTS *pDup = (VBOXVDMAPIPE_RECTS*)vboxWddmMemAllocZero(cbDup);
303 if (!pDup)
304 {
305 WARN(("vboxWddmMemAllocZero failed"));
306 return NULL;
307 }
308 memcpy(pDup, pRects, cbDup);
309 return pDup;
310}
311#ifdef VBOX_WITH_CROGL
312typedef struct VBOXMP_VDMACR_WRITECOMPLETION
313{
314 void *pvBufferToFree;
315} VBOXMP_VDMACR_WRITECOMPLETION, *PVBOXMP_VDMACR_WRITECOMPLETION;
316
317static DECLCALLBACK(void) vboxVdmaCrWriteCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvCtx)
318{
319 PVBOXMP_VDMACR_WRITECOMPLETION pData = (PVBOXMP_VDMACR_WRITECOMPLETION)pvCtx;
320 void* pvBufferToFree = pData->pvBufferToFree;
321 if (pvBufferToFree)
322 VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree);
323
324 VBoxMpCrShgsmiTransportCmdTermWriteAsync(pCon, pvCtx);
325}
326
327typedef struct VBOXMP_VDMACR_WRITEREADCOMPLETION
328{
329 void *pvBufferToFree;
330 void *pvContext;
331} VBOXMP_VDMACR_WRITEREADCOMPLETION, *PVBOXMP_VDMACR_WRITEREADCOMPLETION;
332
333void vboxVdmaCrSubmitWriteReadAsyncGenericCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvCtx)
334{
335 PVBOXMP_VDMACR_WRITEREADCOMPLETION pData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)pvCtx;
336 void* pvBufferToFree = pData->pvBufferToFree;
337 if (pvBufferToFree)
338 VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree);
339
340 VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(pCon, pvCtx);
341}
342
343NTSTATUS vboxVdmaCrSubmitWriteReadAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID, PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion, void *pvCompletion)
344{
345 Assert(u32CrConClientID);
346 NTSTATUS Status = STATUS_SUCCESS;
347 uint32_t cbBuffer;
348 void * pvPackBuffer;
349 void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer);
350 if (pvBuffer)
351 {
352 PVBOXMP_VDMACR_WRITEREADCOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer,
353 pfnCompletion, sizeof (*pvCompletionData));
354 if (pvCompletionData)
355 {
356 pvCompletionData->pvBufferToFree = pvPackBuffer;
357 pvCompletionData->pvContext = pvCompletion;
358 int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
359 if (RT_SUCCESS(rc))
360 {
361 return STATUS_SUCCESS;
362 }
363 WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync failed, rc %d", rc));
364 Status = STATUS_UNSUCCESSFUL;
365 VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
366 }
367 else
368 {
369 WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync failed"));
370 Status = STATUS_INSUFFICIENT_RESOURCES;
371 }
372 }
373
374 return Status;
375}
376
377NTSTATUS vboxVdmaCrSubmitWriteAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID)
378{
379 Assert(u32CrConClientID);
380 NTSTATUS Status = STATUS_SUCCESS;
381 uint32_t cbBuffer;
382 void * pvPackBuffer;
383 void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer);
384 if (pvBuffer)
385 {
386 PVBOXMP_VDMACR_WRITECOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITECOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer,
387 vboxVdmaCrWriteCompletion, sizeof (*pvCompletionData));
388 if (pvCompletionData)
389 {
390 pvCompletionData->pvBufferToFree = pvPackBuffer;
391 int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
392 if (RT_SUCCESS(rc))
393 {
394 return STATUS_SUCCESS;
395 }
396 WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteAsync failed, rc %d", rc));
397 Status = STATUS_UNSUCCESSFUL;
398 VBoxMpCrShgsmiTransportCmdTermWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
399 }
400 else
401 {
402 WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteAsync failed"));
403 Status = STATUS_INSUFFICIENT_RESOURCES;
404 }
405 }
406
407 return Status;
408}
409
410static NTSTATUS vboxVdmaVRegGet(PVBOXWDDM_SWAPCHAIN pSwapchain, const RTRECT *pCtxRect, uint32_t *pcVRects, RTRECT **ppVRectsBuff, uint32_t *pcVRectsBuff)
411{
412 RTRECT *pVRectsBuff = *ppVRectsBuff;
413 uint32_t cVRectsBuff = *pcVRectsBuff;
414 uint32_t cVRects = VBoxVrListRectsCount(&pSwapchain->VisibleRegions);
415 if (cVRectsBuff < cVRects)
416 {
417 if (pVRectsBuff)
418 vboxWddmMemFree(pVRectsBuff);
419 pVRectsBuff = (RTRECT*)vboxWddmMemAlloc(cVRects * sizeof (pVRectsBuff[0]));
420 if (!pVRectsBuff)
421 {
422 WARN(("vboxWddmMemAlloc failed"));
423 *pcVRectsBuff = 0;
424 *ppVRectsBuff = NULL;
425 *pcVRects = NULL;
426 return STATUS_NO_MEMORY;
427 }
428
429 cVRectsBuff = cVRects;
430 *pcVRectsBuff = cVRectsBuff;
431 *ppVRectsBuff = pVRectsBuff;
432 }
433
434 int rc = VBoxVrListRectsGet(&pSwapchain->VisibleRegions, cVRects, pVRectsBuff);
435 AssertRC(rc);
436 if (pCtxRect->xLeft || pCtxRect->yTop)
437 {
438 for (UINT i = 0; i < cVRects; ++i)
439 {
440 VBoxRectTranslate(&pVRectsBuff[i], -pCtxRect->xLeft, -pCtxRect->yTop);
441 }
442 }
443
444 *pcVRects = cVRects;
445 return STATUS_SUCCESS;
446}
447
448
449/**
450 * @param pDevExt
451 */
452static NTSTATUS vboxVdmaProcessVRegCmdLegacy(PVBOXMP_DEVEXT pDevExt,
453 VBOXMP_CRPACKER *pCrPacker,
454 uint32_t u32CrConClientID,
455 PVBOXWDDM_SOURCE pSource,
456 PVBOXWDDM_SWAPCHAIN pSwapchain,
457 const RECT *pSrcRect,
458 const VBOXVDMAPIPE_RECTS *pContextRects)
459{
460 VBOXVDMAPIPE_RECTS *pRectsToFree = NULL;
461 POINT pos = pSource->VScreenPos;
462 if (pos.x || pos.y)
463 {
464 pRectsToFree = vboxWddmBltPipeRectsDup(pContextRects);
465 /* note: do NOT translate the src rect since it is used for screen pos calculation */
466 vboxWddmBltPipeRectsTranslate(pRectsToFree, pos.x, pos.y);
467 pContextRects = pRectsToFree;
468 }
469 const VBOXWDDM_RECTS_INFO *pRects = &pContextRects->UpdateRects;
470 NTSTATUS Status = STATUS_SUCCESS;
471 int rc;
472 bool fCurChanged = FALSE, fCurRectChanged = FALSE;
473 POINT CurPos;
474 RTRECT *pVRectsBuff = NULL;
475 uint32_t cVRectsBuff = 0;
476 VBOXWDDM_CTXLOCK_DATA
477
478 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
479
480 if (pSwapchain)
481 {
482 CurPos.x = pContextRects->ContextRect.left - pSrcRect->left;
483 CurPos.y = pContextRects->ContextRect.top - pSrcRect->top;
484
485 if (CurPos.x != pSwapchain->Pos.x || CurPos.y != pSwapchain->Pos.y)
486 {
487#if 0
488 if (pSwapchain->Pos.x != VBOXWDDM_INVALID_COORD)
489 VBoxVrListTranslate(&pSwapchain->VisibleRegions, pSwapchain->Pos.x - CurPos.x, pSwapchain->Pos.y - CurPos.y);
490 else
491#endif
492 VBoxVrListClear(&pSwapchain->VisibleRegions);
493 fCurRectChanged = TRUE;
494 pSwapchain->Pos = CurPos;
495 }
496
497 rc = VBoxVrListRectsAdd(&pSwapchain->VisibleRegions, pRects->cRects, (const RTRECT*)pRects->aRects, &fCurChanged);
498 if (!RT_SUCCESS(rc))
499 {
500 WARN(("VBoxWddmVrListRectsAdd failed, rc %d!", rc));
501 Status = STATUS_UNSUCCESSFUL;
502 goto done;
503 }
504
505
506 /* visible rects of different windows do not intersect,
507 * so if the given window visible rects did not increase, others have not changed either */
508 if (!fCurChanged && !fCurRectChanged)
509 goto done;
510 }
511
512 /* before posting the add visible rects diff, we need to first hide rects for other windows */
513
514 for (PLIST_ENTRY pCur = pDevExt->SwapchainList3D.Flink; pCur != &pDevExt->SwapchainList3D; pCur = pCur->Flink)
515 {
516 if (pCur != &pSwapchain->DevExtListEntry)
517 {
518 PVBOXWDDM_SWAPCHAIN pCurSwapchain = VBOXWDDMENTRY_2_SWAPCHAIN(pCur);
519 PVBOXWDDM_CONTEXT pCurContext = pCurSwapchain->pContext;
520 PVBOXMP_CRPACKER pCurPacker = &pCurContext->CrPacker;
521 bool fChanged = FALSE;
522
523 rc = VBoxVrListRectsSubst(&pCurSwapchain->VisibleRegions, pRects->cRects, (const RTRECT*)pRects->aRects, &fChanged);
524 if (!RT_SUCCESS(rc))
525 {
526 WARN(("VBoxWddmVrListRectsAdd failed, rc %d!", rc));
527 Status = STATUS_UNSUCCESSFUL;
528 goto done;
529 }
530
531 if (!fChanged)
532 continue;
533
534 uint32_t cVRects;
535 RTRECT CurCtxRect;
536 CurCtxRect.xLeft = pCurSwapchain->Pos.x;
537 CurCtxRect.yTop = pCurSwapchain->Pos.y;
538 CurCtxRect.xRight = CurCtxRect.xLeft + pCurSwapchain->width;
539 CurCtxRect.yBottom = CurCtxRect.yTop + pCurSwapchain->height;
540 Status = vboxVdmaVRegGet(pCurSwapchain, &CurCtxRect, &cVRects, &pVRectsBuff, &cVRectsBuff);
541 if (!NT_SUCCESS(Status))
542 {
543 WARN(("vboxVdmaVRegGet Status 0x%x", Status));
544 goto done;
545 }
546
547 void *pvCommandBuffer = NULL;
548 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE;
549 cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWVISIBLEREGIONS(cVRects);
550
551 pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer);
552 if (!pvCommandBuffer)
553 {
554 WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!"));
555 Status = VERR_OUT_OF_RESOURCES;
556 goto done;
557 }
558
559 VBoxMpCrPackerTxBufferInit(pCurPacker, pvCommandBuffer, cbCommandBuffer, 1);
560
561 Assert(pCurSwapchain->winHostID);
562 crPackWindowVisibleRegion(&pCurPacker->CrPacker, pCurSwapchain->winHostID, cVRects, (GLint*)pVRectsBuff);
563
564 Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCurPacker, pCurContext->u32CrConClientID);
565 if (!NT_SUCCESS(Status))
566 {
567 WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status));
568 VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer);
569 }
570 }
571 }
572
573 if (!pSwapchain)
574 goto done;
575
576 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE, cCommands = 0;
577
578 uint32_t cVRects;
579 Status = vboxVdmaVRegGet(pSwapchain, (const RTRECT *)&pContextRects->ContextRect, &cVRects, &pVRectsBuff, &cVRectsBuff);
580 if (!NT_SUCCESS(Status))
581 {
582 WARN(("vboxVdmaVRegGet Status 0x%x", Status));
583 goto done;
584 }
585
586 ++cCommands;
587 cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWVISIBLEREGIONS(cVRects);
588
589 if (fCurRectChanged && fCurChanged)
590 {
591 ++cCommands;
592 cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWPOSITION;
593 }
594
595 if (!pSwapchain->fExposed)
596 {
597 ++cCommands;
598 cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWSHOW;
599 ++cCommands;
600 cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWSIZE;
601 }
602
603 void *pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer);
604 if (!pvCommandBuffer)
605 {
606 WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!"));
607 Status = STATUS_INSUFFICIENT_RESOURCES;
608 goto done;
609 }
610
611 VBoxMpCrPackerTxBufferInit(pCrPacker, pvCommandBuffer, cbCommandBuffer, cCommands);
612
613 Assert(pSwapchain->winHostID);
614
615 if (fCurRectChanged && fCurChanged)
616 crPackWindowPosition(&pCrPacker->CrPacker, pSwapchain->winHostID, CurPos.x, CurPos.y);
617
618 if (!pSwapchain->fExposed)
619 {
620 crPackWindowSize(&pCrPacker->CrPacker, pSwapchain->winHostID, pSwapchain->width, pSwapchain->height);
621 crPackWindowShow(&pCrPacker->CrPacker, pSwapchain->winHostID, TRUE);
622 pSwapchain->fExposed = TRUE;
623 }
624
625 crPackWindowVisibleRegion(&pCrPacker->CrPacker, pSwapchain->winHostID, cVRects, (GLint*)pVRectsBuff);
626
627 Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCrPacker, u32CrConClientID);
628 if (!NT_SUCCESS(Status))
629 {
630 WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status));
631 VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer);
632 }
633
634done:
635 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
636
637 if (pRectsToFree)
638 vboxWddmMemFree(pRectsToFree);
639
640 if (pVRectsBuff)
641 vboxWddmMemFree(pVRectsBuff);
642
643 return Status;
644}
645#endif
646
647static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, VBOXVDMA_CLRFILL *pCF)
648{
649 NTSTATUS Status = STATUS_UNSUCCESSFUL;
650 Assert (pDevExt->pvVisibleVram);
651 if (pDevExt->pvVisibleVram)
652 {
653 PVBOXWDDM_ALLOCATION pAlloc = pCF->Alloc.pAlloc;
654 if (pAlloc->AllocData.Addr.SegmentId && pAlloc->AllocData.Addr.SegmentId != 1)
655 {
656 WARN(("request to collor fill invalid allocation"));
657 return STATUS_INVALID_PARAMETER;
658 }
659
660 VBOXVIDEOOFFSET offVram = vboxWddmAddrFramOffset(&pAlloc->AllocData.Addr);
661 if (offVram != VBOXVIDEOOFFSET_VOID)
662 {
663 RECT UnionRect = {0};
664 uint8_t *pvMem = pDevExt->pvVisibleVram + offVram;
665 UINT bpp = pAlloc->AllocData.SurfDesc.bpp;
666 Assert(bpp);
667 Assert(((bpp * pAlloc->AllocData.SurfDesc.width) >> 3) == pAlloc->AllocData.SurfDesc.pitch);
668 switch (bpp)
669 {
670 case 32:
671 {
672 uint8_t bytestPP = bpp >> 3;
673 for (UINT i = 0; i < pCF->Rects.cRects; ++i)
674 {
675 RECT *pRect = &pCF->Rects.aRects[i];
676 for (LONG ir = pRect->top; ir < pRect->bottom; ++ir)
677 {
678 uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->AllocData.SurfDesc.pitch) + (pRect->left * bytestPP));
679 uint32_t cRaw = pRect->right - pRect->left;
680 Assert(pRect->left >= 0);
681 Assert(pRect->right <= (LONG)pAlloc->AllocData.SurfDesc.width);
682 Assert(pRect->top >= 0);
683 Assert(pRect->bottom <= (LONG)pAlloc->AllocData.SurfDesc.height);
684 for (UINT j = 0; j < cRaw; ++j)
685 {
686 *pvU32Mem = pCF->Color;
687 ++pvU32Mem;
688 }
689 }
690 vboxWddmRectUnited(&UnionRect, &UnionRect, pRect);
691 }
692 Status = STATUS_SUCCESS;
693 break;
694 }
695 case 16:
696 case 8:
697 default:
698 AssertBreakpoint();
699 break;
700 }
701
702 if (Status == STATUS_SUCCESS)
703 {
704 if (pAlloc->AllocData.SurfDesc.VidPnSourceId != D3DDDI_ID_UNINITIALIZED
705 && VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pAlloc)
706 && pAlloc->bVisible
707 )
708 {
709 if (!vboxWddmRectIsEmpty(&UnionRect))
710 {
711 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->Alloc.pAlloc->AllocData.SurfDesc.VidPnSourceId];
712 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
713 if (!cUnlockedVBVADisabled)
714 {
715 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &UnionRect);
716 }
717 else
718 {
719 VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UnionRect);
720 }
721 }
722 }
723 else
724 {
725 AssertBreakpoint();
726 }
727 }
728 }
729 else
730 WARN(("invalid offVram"));
731 }
732
733 return Status;
734}
735
736NTSTATUS vboxVdmaGgDmaBltPerform(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOC_DATA pSrcAlloc, RECT* pSrcRect,
737 PVBOXWDDM_ALLOC_DATA pDstAlloc, RECT* pDstRect)
738{
739 uint8_t* pvVramBase = pDevExt->pvVisibleVram;
740 /* we do not support stretching */
741 uint32_t srcWidth = pSrcRect->right - pSrcRect->left;
742 uint32_t srcHeight = pSrcRect->bottom - pSrcRect->top;
743 uint32_t dstWidth = pDstRect->right - pDstRect->left;
744 uint32_t dstHeight = pDstRect->bottom - pDstRect->top;
745 Assert(srcHeight == dstHeight);
746 Assert(dstWidth == srcWidth);
747 Assert(pDstAlloc->Addr.offVram != VBOXVIDEOOFFSET_VOID);
748 Assert(pSrcAlloc->Addr.offVram != VBOXVIDEOOFFSET_VOID);
749 D3DDDIFORMAT enmSrcFormat, enmDstFormat;
750
751 enmSrcFormat = pSrcAlloc->SurfDesc.format;
752 enmDstFormat = pDstAlloc->SurfDesc.format;
753
754 if (pDstAlloc->Addr.SegmentId && pDstAlloc->Addr.SegmentId != 1)
755 {
756 WARN(("request to collor blit invalid allocation"));
757 return STATUS_INVALID_PARAMETER;
758 }
759
760 if (pSrcAlloc->Addr.SegmentId && pSrcAlloc->Addr.SegmentId != 1)
761 {
762 WARN(("request to collor blit invalid allocation"));
763 return STATUS_INVALID_PARAMETER;
764 }
765
766 if (enmSrcFormat != enmDstFormat)
767 {
768 /* just ignore the alpha component
769 * this is ok since our software-based stuff can not handle alpha channel in any way */
770 enmSrcFormat = vboxWddmFmtNoAlphaFormat(enmSrcFormat);
771 enmDstFormat = vboxWddmFmtNoAlphaFormat(enmDstFormat);
772 if (enmSrcFormat != enmDstFormat)
773 {
774 WARN(("color conversion src(%d), dst(%d) not supported!", pSrcAlloc->SurfDesc.format, pDstAlloc->SurfDesc.format));
775 return STATUS_INVALID_PARAMETER;
776 }
777 }
778 if (srcHeight != dstHeight)
779 return STATUS_INVALID_PARAMETER;
780 if (srcWidth != dstWidth)
781 return STATUS_INVALID_PARAMETER;
782 if (pDstAlloc->Addr.offVram == VBOXVIDEOOFFSET_VOID)
783 return STATUS_INVALID_PARAMETER;
784 if (pSrcAlloc->Addr.offVram == VBOXVIDEOOFFSET_VOID)
785 return STATUS_INVALID_PARAMETER;
786
787 uint8_t *pvDstSurf = pDstAlloc->Addr.SegmentId ? pvVramBase + pDstAlloc->Addr.offVram : (uint8_t*)pDstAlloc->Addr.pvMem;
788 uint8_t *pvSrcSurf = pSrcAlloc->Addr.SegmentId ? pvVramBase + pSrcAlloc->Addr.offVram : (uint8_t*)pSrcAlloc->Addr.pvMem;
789
790 if (pDstAlloc->SurfDesc.width == dstWidth
791 && pSrcAlloc->SurfDesc.width == srcWidth
792 && pSrcAlloc->SurfDesc.width == pDstAlloc->SurfDesc.width)
793 {
794 Assert(!pDstRect->left);
795 Assert(!pSrcRect->left);
796 uint32_t cbDstOff = vboxWddmCalcOffXYrd(0 /* x */, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
797 uint32_t cbSrcOff = vboxWddmCalcOffXYrd(0 /* x */, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
798 uint32_t cbSize = vboxWddmCalcSize(pDstAlloc->SurfDesc.pitch, dstHeight, pDstAlloc->SurfDesc.format);
799 memcpy(pvDstSurf + cbDstOff, pvSrcSurf + cbSrcOff, cbSize);
800 }
801 else
802 {
803 uint32_t cbDstLine = vboxWddmCalcRowSize(pDstRect->left, pDstRect->right, pDstAlloc->SurfDesc.format);
804 uint32_t offDstStart = vboxWddmCalcOffXYrd(pDstRect->left, pDstRect->top, pDstAlloc->SurfDesc.pitch, pDstAlloc->SurfDesc.format);
805 Assert(cbDstLine <= pDstAlloc->SurfDesc.pitch);
806 uint32_t cbDstSkip = pDstAlloc->SurfDesc.pitch;
807 uint8_t * pvDstStart = pvDstSurf + offDstStart;
808
809 uint32_t cbSrcLine = vboxWddmCalcRowSize(pSrcRect->left, pSrcRect->right, pSrcAlloc->SurfDesc.format);
810 uint32_t offSrcStart = vboxWddmCalcOffXYrd(pSrcRect->left, pSrcRect->top, pSrcAlloc->SurfDesc.pitch, pSrcAlloc->SurfDesc.format);
811 Assert(cbSrcLine <= pSrcAlloc->SurfDesc.pitch);
812 uint32_t cbSrcSkip = pSrcAlloc->SurfDesc.pitch;
813 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
814
815 uint32_t cRows = vboxWddmCalcNumRows(pDstRect->top, pDstRect->bottom, pDstAlloc->SurfDesc.format);
816
817 Assert(cbDstLine == cbSrcLine);
818
819 for (uint32_t i = 0; i < cRows; ++i)
820 {
821 memcpy(pvDstStart, pvSrcStart, cbDstLine);
822 pvDstStart += cbDstSkip;
823 pvSrcStart += cbSrcSkip;
824 }
825 }
826 return STATUS_SUCCESS;
827}
828
829/*
830 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
831 */
832static NTSTATUS vboxVdmaGgDmaBlt(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_BLT pBlt)
833{
834 /* we do not support stretching for now */
835 Assert(pBlt->SrcRect.right - pBlt->SrcRect.left == pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left);
836 Assert(pBlt->SrcRect.bottom - pBlt->SrcRect.top == pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top);
837 if (pBlt->SrcRect.right - pBlt->SrcRect.left != pBlt->DstRects.ContextRect.right - pBlt->DstRects.ContextRect.left)
838 return STATUS_INVALID_PARAMETER;
839 if (pBlt->SrcRect.bottom - pBlt->SrcRect.top != pBlt->DstRects.ContextRect.bottom - pBlt->DstRects.ContextRect.top)
840 return STATUS_INVALID_PARAMETER;
841 Assert(pBlt->DstRects.UpdateRects.cRects);
842
843 NTSTATUS Status = STATUS_SUCCESS;
844
845 if (pBlt->DstRects.UpdateRects.cRects)
846 {
847 for (uint32_t i = 0; i < pBlt->DstRects.UpdateRects.cRects; ++i)
848 {
849 RECT SrcRect;
850 vboxWddmRectTranslated(&SrcRect, &pBlt->DstRects.UpdateRects.aRects[i], -pBlt->DstRects.ContextRect.left, -pBlt->DstRects.ContextRect.top);
851
852 Status = vboxVdmaGgDmaBltPerform(pDevExt, &pBlt->SrcAlloc.pAlloc->AllocData, &SrcRect,
853 &pBlt->DstAlloc.pAlloc->AllocData, &pBlt->DstRects.UpdateRects.aRects[i]);
854 Assert(Status == STATUS_SUCCESS);
855 if (Status != STATUS_SUCCESS)
856 return Status;
857 }
858 }
859 else
860 {
861 Status = vboxVdmaGgDmaBltPerform(pDevExt, &pBlt->SrcAlloc.pAlloc->AllocData, &pBlt->SrcRect,
862 &pBlt->DstAlloc.pAlloc->AllocData, &pBlt->DstRects.ContextRect);
863 Assert(Status == STATUS_SUCCESS);
864 if (Status != STATUS_SUCCESS)
865 return Status;
866 }
867
868 return Status;
869}
870
871#ifdef VBOX_WITH_CROGL
872typedef struct VBOXVDMA_CRRXGENERICSYNC
873{
874 int rc;
875 KEVENT Event;
876} VBOXVDMA_CRRXGENERICSYNC, *PVBOXVDMA_CRRXGENERICSYNC;
877
878static DECLCALLBACK(void) vboxVdmaCrRxGenericSyncCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvRx, uint32_t cbRx, void *pvCtx)
879{
880 PVBOXMP_VDMACR_WRITEREADCOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)pvCtx;
881 PVBOXVDMA_CRRXGENERICSYNC pData = (PVBOXVDMA_CRRXGENERICSYNC)pvCompletionData->pvContext;
882 if (RT_SUCCESS(rc))
883 {
884 rc = VBoxMpCrCmdRxHandler((CRMessageHeader*)pvRx, cbRx);
885 if (!RT_SUCCESS(rc))
886 {
887 WARN(("VBoxMpCrCmdRxHandler failed %d", rc));
888 }
889 }
890 else
891 {
892 WARN(("rx failure %d", rc));
893 }
894
895 pData->rc = rc;
896
897 KeSetEvent(&pData->Event, 0, FALSE);
898
899 vboxVdmaCrSubmitWriteReadAsyncGenericCompletion(pCon, pvCtx);
900}
901
902NTSTATUS vboxVdmaCrRxGenericSync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID)
903{
904 VBOXVDMA_CRRXGENERICSYNC Data;
905 Data.rc = VERR_NOT_SUPPORTED;
906 KeInitializeEvent(&Data.Event, SynchronizationEvent, FALSE);
907 NTSTATUS Status = vboxVdmaCrSubmitWriteReadAsync(pDevExt, pCrPacker, u32CrConClientID, vboxVdmaCrRxGenericSyncCompletion, &Data);
908 if (!NT_SUCCESS(Status))
909 {
910 WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status));
911 return Status;
912 }
913
914 Status = KeWaitForSingleObject(&Data.Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
915 if (!NT_SUCCESS(Status))
916 {
917 WARN(("KeWaitForSingleObject failed Status 0x%x", Status));
918 return Status;
919 }
920
921 return STATUS_SUCCESS;
922}
923
924typedef struct VBOXMP_CRHGSMIMGR
925{
926 VBOXMP_CRPACKER CrPacker;
927 void *pvCommandBuffer;
928} VBOXMP_CRHGSMIMGR;
929
930DECLINLINE(CRPackContext*) vboxVdmaCrHmGetPackContext(VBOXMP_CRHGSMIMGR *pMgr)
931{
932 return &pMgr->CrPacker.CrPacker;
933}
934
935NTSTATUS vboxVdmaCrHmCreate(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRHGSMIMGR *pMgr, uint32_t cbCommandBuffer, uint32_t cCommands)
936{
937 pMgr->pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer);
938 if (!pMgr->pvCommandBuffer)
939 {
940 WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!"));
941 return VERR_OUT_OF_RESOURCES;
942 }
943
944 VBoxMpCrPackerInit(&pMgr->CrPacker);
945
946 VBoxMpCrPackerTxBufferInit(&pMgr->CrPacker, pMgr->pvCommandBuffer, cbCommandBuffer, cCommands);
947
948 return STATUS_SUCCESS;
949}
950
951NTSTATUS vboxVdmaCrHmSubmitWrSync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRHGSMIMGR *pMgr, uint32_t u32CrConClientID)
952{
953 NTSTATUS Status = vboxVdmaCrRxGenericSync(pDevExt, &pMgr->CrPacker, u32CrConClientID);
954 if (!NT_SUCCESS(Status))
955 {
956 WARN(("vboxVdmaCrRxGenericSync failed Status 0x%x", Status));
957 VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pMgr->pvCommandBuffer);
958 return Status;
959 }
960
961 return STATUS_SUCCESS;
962}
963#if 0
964NTSTATUS vboxVdmaCrCmdGetChromiumParametervCR(PVBOXMP_DEVEXT pDevExt, uint32_t u32CrConClientID, GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid * values)
965{
966 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_GETCHROMIUMPARAMETERVCR;
967 uint32_t cCommands = 1;
968
969 VBOXMP_CRHGSMIMGR Mgr;
970 NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands);
971 if (!NT_SUCCESS(Status))
972 {
973 WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status));
974 return Status;
975 }
976
977 int dummy = 1;
978
979 crPackGetChromiumParametervCR(vboxVdmaCrHmGetPackContext(&Mgr), target, index, type, count, values, &dummy);
980
981 Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID);
982 if (!NT_SUCCESS(Status))
983 {
984 WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status));
985 return Status;
986 }
987
988 return STATUS_SUCCESS;
989}
990
991static NTSTATUS vboxVdmaCrCmdCreateContext(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32CtxID)
992{
993 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_CREATECONTEXT;
994 uint32_t cCommands = 1;
995
996 VBOXMP_CRHGSMIMGR Mgr;
997 NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands);
998 if (!NT_SUCCESS(Status))
999 {
1000 WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status));
1001 return Status;
1002 }
1003
1004 int dummy = 1;
1005
1006 crPackCreateContext(&CrPacker.CrPacker, "", visualBits, 0, &pi32CtxID, &dummy);
1007
1008 Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID);
1009 if (!NT_SUCCESS(Status))
1010 {
1011 WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status));
1012 return Status;
1013 }
1014
1015 return STATUS_SUCCESS;
1016}
1017
1018static NTSTATUS vboxVdmaCrCmdWindowCreate(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32WinID)
1019{
1020 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_WINDOWCREATE;
1021 uint32_t cCommands = 1;
1022
1023 VBOXMP_CRHGSMIMGR Mgr;
1024 NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands);
1025 if (!NT_SUCCESS(Status))
1026 {
1027 WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status));
1028 return Status;
1029 }
1030
1031 int dummy = 1;
1032
1033 crPackWindowCreate(&CrPacker.CrPacker, "", visualBits, 0, &pi32CtxID, &dummy);
1034
1035 Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID);
1036 if (!NT_SUCCESS(Status))
1037 {
1038 WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status));
1039 return Status;
1040 }
1041
1042 return STATUS_SUCCESS;
1043}
1044
1045static NTSTATUS vboxVdmaCrCtlGetDefaultCtxId(PVBOXMP_DEVEXT pDevExt, int32_t *pi32CtxID)
1046{
1047 if (!pDevExt->i32CrConDefaultCtxID)
1048 {
1049 if (!pDevExt->f3DEnabled)
1050 {
1051 WARN(("3D disabled, should not be here!"));
1052 return STATUS_UNSUCCESSFUL;
1053 }
1054
1055 uint32_t u32ClienID;
1056 NTSTATUS Status = vboxVdmaCrCtlGetDefaultClientId(pDevExt, &u32ClienID);
1057 if (!NT_SUCCESS(Status))
1058 {
1059 WARN(("vboxVdmaCrCtlGetDefaultClientId failed, Status %#x", Status));
1060 return Status;
1061 }
1062
1063 Status = vboxVdmaCrCmdWindowCreate(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32WinID)
1064
1065 VBOXMP_CRPACKER CrPacker;
1066 VBoxMpCrPackerInit(&CrPacker);
1067
1068 int rc = VBoxMpCrCtlConConnect(pDevExt, &pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDevExt->u32CrConDefaultClientID);
1069 if (!RT_SUCCESS(rc))
1070 {
1071 WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc));
1072 return STATUS_UNSUCCESSFUL;
1073 }
1074 }
1075
1076 *pi32CtxID = pDevExt->i32CrConDefaultCtxID;
1077 return STATUS_SUCCESS;
1078}
1079#endif
1080
1081static NTSTATUS vboxVdmaTexPresentSubmit(PVBOXMP_DEVEXT pDevExt,
1082 VBOXMP_CRPACKER *pCrPacker,
1083 uint32_t u32CrConClientID,
1084 uint32_t hostID,
1085 uint32_t cfg,
1086 int32_t posX,
1087 int32_t posY,
1088 uint32_t cRects,
1089 const RTRECT*paRects)
1090{
1091 Assert(pDevExt->fTexPresentEnabled);
1092
1093 uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_VBOXTEXPRESENT(cRects);
1094 uint32_t cCommands = 1;
1095 void *pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer);
1096 if (!pvCommandBuffer)
1097 {
1098 WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!"));
1099 return VERR_OUT_OF_RESOURCES;
1100 }
1101
1102 VBoxMpCrPackerTxBufferInit(pCrPacker, pvCommandBuffer, cbCommandBuffer, cCommands);
1103
1104 crPackVBoxTexPresent(&pCrPacker->CrPacker, hostID, cfg, posX, posY, cRects, (int32_t*)paRects);
1105
1106 NTSTATUS Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCrPacker, u32CrConClientID);
1107 if (!NT_SUCCESS(Status))
1108 {
1109 WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status));
1110 VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer);
1111 }
1112
1113 return Status;
1114}
1115
1116static NTSTATUS vboxVdmaCrCtlGetDefaultClientId(PVBOXMP_DEVEXT pDevExt, uint32_t *pu32ClienID)
1117{
1118 if (!pDevExt->u32CrConDefaultClientID)
1119 {
1120 if (!pDevExt->f3DEnabled)
1121 {
1122 WARN(("3D disabled, should not be here!"));
1123 return STATUS_UNSUCCESSFUL;
1124 }
1125
1126 int rc = VBoxMpCrCtlConConnect(pDevExt, &pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDevExt->u32CrConDefaultClientID);
1127 if (!RT_SUCCESS(rc))
1128 {
1129 WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc));
1130 return STATUS_UNSUCCESSFUL;
1131 }
1132 }
1133
1134 *pu32ClienID = pDevExt->u32CrConDefaultClientID;
1135 return STATUS_SUCCESS;
1136}
1137
1138static NTSTATUS vboxVdmaProcessVReg(PVBOXMP_DEVEXT pDevExt,
1139 VBOXMP_CRPACKER *pCrPacker,
1140 uint32_t u32CrConClientID,
1141 const VBOXWDDM_ALLOCATION *pSrcAlloc,
1142 const VBOXWDDM_ALLOCATION *pDstAlloc,
1143 const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects)
1144{
1145 D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId = pDstAlloc->AllocData.SurfDesc.VidPnSourceId;
1146 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[srcId];
1147 NTSTATUS Status = STATUS_SUCCESS;
1148
1149 if (pDevExt->fTexPresentEnabled)
1150 {
1151 /* we care only about screen regions */
1152 if (pDstAlloc != pSource->pPrimaryAllocation)
1153 {
1154 WARN(("non-primary allocation passed to vboxWddmSubmitBltCmd!"));
1155 return STATUS_NOT_SUPPORTED;
1156 }
1157
1158 uint32_t hostID = pSrcAlloc->AllocData.hostID;
1159 int rc;
1160 if (hostID)
1161 {
1162// Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D);
1163 int32_t posX = pDstRects->ContextRect.left - pSrcRect->left;
1164 int32_t posY = pDstRects->ContextRect.top - pSrcRect->top;
1165
1166 Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, posX, posY, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects);
1167 if (NT_SUCCESS(Status))
1168 {
1169 rc = VBoxVrListRectsSubst(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, NULL);
1170 if (RT_SUCCESS(rc))
1171 pSource->fHas3DVrs = TRUE;
1172 else
1173 WARN(("VBoxVrListRectsSubst failed rc %d, ignoring..", rc));
1174 }
1175 else
1176 WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status));
1177 }
1178 else if (pSource->pPrimaryAllocation == pDstAlloc)
1179 {
1180 bool fChanged = false;
1181 Assert(pSource->pPrimaryAllocation->bVisible);
1182 rc = VBoxVrListRectsAdd(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, &fChanged);
1183 if (RT_SUCCESS(rc))
1184 {
1185 if (fChanged)
1186 {
1187 Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, 0, 0, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects);
1188 if (NT_SUCCESS(Status))
1189 {
1190 if (pSource->fHas3DVrs)
1191 {
1192 if (VBoxVrListRectsCount(&pSource->VrList) == 1)
1193 {
1194 RTRECT Rect;
1195 VBoxVrListRectsGet(&pSource->VrList, 1, &Rect);
1196 if (Rect.xLeft == 0
1197 && Rect.yTop == 0
1198 && Rect.xRight == pDstAlloc->AllocData.SurfDesc.width
1199 && Rect.yBottom == pDstAlloc->AllocData.SurfDesc.height)
1200 {
1201 pSource->fHas3DVrs = FALSE;
1202 }
1203 }
1204 }
1205 }
1206 else
1207 WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status));
1208 }
1209 }
1210 else
1211 WARN(("VBoxVrListRectsAdd failed rc %d, ignoring..", rc));
1212 }
1213 else
1214 {
1215 WARN(("unexpected"));
1216 Status = STATUS_INVALID_PARAMETER;
1217 }
1218 }
1219 else
1220 {
1221 PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc);
1222
1223 if (pSwapchain)
1224 {
1225 Assert(pSrcAlloc->AllocData.SurfDesc.width == pSwapchain->width);
1226 Assert(pSrcAlloc->AllocData.SurfDesc.height == pSwapchain->height);
1227 }
1228
1229 Status = vboxVdmaProcessVRegCmdLegacy(pDevExt, pCrPacker, u32CrConClientID, pSource, pSwapchain, pSrcRect, pDstRects);
1230 if (!NT_SUCCESS(Status))
1231 WARN(("vboxVdmaProcessVRegCmdLegacy failed Status 0x%x", Status));
1232
1233 if (pSwapchain)
1234 vboxWddmSwapchainRelease(pSwapchain);
1235 }
1236
1237 return Status;
1238}
1239
1240NTSTATUS vboxVdmaTexPresentSetAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pRealFbAlloc)
1241{
1242 VBOXMP_CRPACKER CrPacker;
1243 VBoxMpCrPackerInit(&CrPacker);
1244 uint32_t u32CrConClientID;
1245
1246 NTSTATUS Status = vboxVdmaCrCtlGetDefaultClientId(pDevExt, &u32CrConClientID);
1247 if (!NT_SUCCESS(Status))
1248 {
1249 WARN(("vboxVdmaCrCtlGetDefaultClientId failed Status 0x%x", Status));
1250 return Status;
1251 }
1252
1253 RECT Rect;
1254 Rect.left = 0;
1255 Rect.top = 0;
1256 Rect.right = pRealFbAlloc->AllocData.SurfDesc.width;
1257 Rect.bottom = pRealFbAlloc->AllocData.SurfDesc.height;
1258
1259 VBOXVDMAPIPE_RECTS RectInfo;
1260 RectInfo.ContextRect = Rect;
1261 RectInfo.UpdateRects.cRects = 1;
1262 RectInfo.UpdateRects.aRects[0] = Rect;
1263
1264 return vboxVdmaProcessVReg(pDevExt, &CrPacker, u32CrConClientID,
1265 pRealFbAlloc, pRealFbAlloc,
1266 &Rect, &RectInfo);
1267}
1268
1269static NTSTATUS vboxVdmaProcessVRegCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext,
1270 const VBOXWDDM_DMA_ALLOCINFO *pSrcAllocInfo,
1271 const VBOXWDDM_DMA_ALLOCINFO *pDstAllocInfo,
1272 const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects)
1273{
1274 return vboxVdmaProcessVReg(pDevExt, &pContext->CrPacker, pContext->u32CrConClientID,
1275 pSrcAllocInfo->pAlloc, pDstAllocInfo->pAlloc,
1276 pSrcRect, pDstRects);
1277}
1278
1279static void vboxVdmaBltDirtyRectsUpdate(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, uint32_t cRects, const RECT *paRects)
1280{
1281 if (!cRects)
1282 {
1283 WARN(("vboxVdmaBltDirtyRectsUpdate: no rects specified"));
1284 return;
1285 }
1286
1287 RECT rect;
1288 rect = paRects[0];
1289 for (UINT i = 1; i < cRects; ++i)
1290 {
1291 vboxWddmRectUnited(&rect, &rect, &paRects[i]);
1292 }
1293
1294 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
1295 if (!cUnlockedVBVADisabled)
1296 {
1297 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &rect);
1298 }
1299 else
1300 {
1301 VBOXVBVA_OP_WITHLOCK_ATDPC(ReportDirtyRect, pDevExt, pSource, &rect);
1302 }
1303}
1304#endif
1305
1306NTSTATUS vboxVdmaProcessBltCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_BLT *pBlt)
1307{
1308 NTSTATUS Status = STATUS_SUCCESS;
1309 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
1310 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
1311 BOOLEAN fRenderFromSharedDisabled = pDevExt->fRenderToShadowDisabled;
1312 BOOLEAN fVRAMUpdated = FALSE;
1313#ifdef VBOX_WITH_CROGL
1314 if (!pDstAlloc->AllocData.hostID && !pSrcAlloc->AllocData.hostID)
1315#endif
1316 {
1317 /* the allocations contain a real data in VRAM, do blitting */
1318 vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt);
1319 fVRAMUpdated = TRUE;
1320 }
1321
1322#ifdef VBOX_WITH_CROGL
1323 if (VBOXWDDM_IS_REAL_FB_ALLOCATION(pDevExt, pDstAlloc)
1324 && pDstAlloc->bVisible)
1325 {
1326 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId];
1327 Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
1328 Assert(pSource->pPrimaryAllocation == pDstAlloc);
1329
1330
1331 if (fVRAMUpdated)
1332 vboxVdmaBltDirtyRectsUpdate(pDevExt, pSource, pBlt->Blt.DstRects.UpdateRects.cRects, pBlt->Blt.DstRects.UpdateRects.aRects);
1333
1334 if (pSrcAlloc->AllocData.hostID || (pDevExt->fTexPresentEnabled ? pSource->fHas3DVrs : !!pDevExt->cContexts3D))
1335 {
1336 Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pBlt->Blt.SrcAlloc, &pBlt->Blt.DstAlloc, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects);
1337 if (!NT_SUCCESS(Status))
1338 WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status));
1339 }
1340 }
1341#endif
1342 return Status;
1343}
1344
1345NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip)
1346{
1347 NTSTATUS Status = STATUS_SUCCESS;
1348 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
1349 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
1350 vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
1351#ifdef VBOX_WITH_CROGL
1352 if (pAlloc->AllocData.hostID)
1353 {
1354 RECT SrcRect;
1355 VBOXVDMAPIPE_RECTS Rects;
1356 SrcRect.left = 0;
1357 SrcRect.top = 0;
1358 SrcRect.right = pAlloc->AllocData.SurfDesc.width;
1359 SrcRect.bottom = pAlloc->AllocData.SurfDesc.height;
1360 Rects.ContextRect.left = 0;
1361 Rects.ContextRect.top = 0;
1362 Rects.ContextRect.right = pAlloc->AllocData.SurfDesc.width;
1363 Rects.ContextRect.bottom = pAlloc->AllocData.SurfDesc.height;
1364 Rects.UpdateRects.cRects = 1;
1365 Rects.UpdateRects.aRects[0] = Rects.ContextRect;
1366
1367 Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pFlip->Flip.Alloc, &pFlip->Flip.Alloc, &SrcRect, &Rects);
1368 if (!NT_SUCCESS(Status))
1369 WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status));
1370 }
1371 else
1372#endif
1373 {
1374 WARN(("unexpected flip request"));
1375 }
1376
1377 return Status;
1378}
1379
1380NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF)
1381{
1382 NTSTATUS Status = STATUS_SUCCESS;
1383 PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
1384#ifdef VBOX_WITH_CROGL
1385 if (!pAlloc->AllocData.hostID)
1386#endif
1387 {
1388 Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill);
1389 if (!NT_SUCCESS(Status))
1390 WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status));
1391 }
1392#ifdef VBOX_WITH_CROGL
1393 else
1394 WARN(("unexpected clrfill request"));
1395#endif
1396
1397 return Status;
1398}
1399
1400
1401#ifdef VBOX_WITH_VDMA
1402/*
1403 * This is currently used by VDMA. It is invisible for Vdma API clients since
1404 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1405 * transport for DMA commands submission
1406 */
1407
1408#ifdef VBOXVDMA_WITH_VBVA
1409static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1410{
1411 int rc;
1412 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1413 {
1414 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1415 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1416 }
1417 else
1418 {
1419 AssertBreakpoint();
1420 rc = VERR_INVALID_STATE;
1421 }
1422 return rc;
1423}
1424#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1425#else
1426static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1427{
1428 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1429 return VINF_SUCCESS;
1430}
1431#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1432#endif
1433
1434static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1435{
1436 int rc = VINF_SUCCESS;
1437
1438 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1439 if (pCmd)
1440 {
1441 pCmd->enmCtl = enmCtl;
1442 pCmd->u32Offset = pInfo->CmdHeap.Heap.area.offBase;
1443 pCmd->i32Result = VERR_NOT_SUPPORTED;
1444
1445 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1446 Assert(pHdr);
1447 if (pHdr)
1448 {
1449 do
1450 {
1451 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1452 Assert(offCmd != HGSMIOFFSET_VOID);
1453 if (offCmd != HGSMIOFFSET_VOID)
1454 {
1455 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1456 AssertRC(rc);
1457 if (RT_SUCCESS(rc))
1458 {
1459 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1460 AssertRC(rc);
1461 if (RT_SUCCESS(rc))
1462 {
1463 rc = pCmd->i32Result;
1464 AssertRC(rc);
1465 }
1466 break;
1467 }
1468 }
1469 else
1470 rc = VERR_INVALID_PARAMETER;
1471 /* fail to submit, cancel it */
1472 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1473 } while (0);
1474 }
1475
1476 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1477 }
1478 else
1479 {
1480 LOGREL(("HGSMIHeapAlloc failed"));
1481 rc = VERR_OUT_OF_RESOURCES;
1482 }
1483
1484 return rc;
1485}
1486#endif
1487
1488static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb)
1489{
1490 NOREF(pvEnv);
1491 return RTMemAlloc(cb);
1492}
1493
1494static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv)
1495{
1496 NOREF(pvEnv);
1497 RTMemFree(pv);
1498}
1499
1500static HGSMIENV g_hgsmiEnvVdma =
1501{
1502 NULL,
1503 hgsmiEnvAlloc,
1504 hgsmiEnvFree
1505};
1506
1507/* create a DMACommand buffer */
1508int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1509#ifdef VBOX_WITH_VDMA
1510 , ULONG offBuffer, ULONG cbBuffer
1511#endif
1512 )
1513{
1514 int rc;
1515 pInfo->fEnabled = FALSE;
1516
1517#ifdef VBOX_WITH_VDMA
1518 Assert((offBuffer & 0xfff) == 0);
1519 Assert((cbBuffer & 0xfff) == 0);
1520 Assert(offBuffer);
1521 Assert(cbBuffer);
1522
1523 if((offBuffer & 0xfff)
1524 || (cbBuffer & 0xfff)
1525 || !offBuffer
1526 || !cbBuffer)
1527 {
1528 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1529 return VERR_INVALID_PARAMETER;
1530 }
1531 PVOID pvBuffer;
1532
1533 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1534 &pvBuffer,
1535 offBuffer,
1536 cbBuffer);
1537 Assert(RT_SUCCESS(rc));
1538 if (RT_SUCCESS(rc))
1539 {
1540 /* Setup a HGSMI heap within the adapter information area. */
1541 rc = VBoxSHGSMIInit(&pInfo->CmdHeap,
1542 HGSMI_HEAP_TYPE_MA,
1543 pvBuffer,
1544 cbBuffer,
1545 offBuffer,
1546 &g_hgsmiEnvVdma);
1547 Assert(RT_SUCCESS(rc));
1548 if(RT_SUCCESS(rc))
1549#endif
1550 {
1551 return VINF_SUCCESS;
1552 }
1553#ifdef VBOX_WITH_VDMA
1554 else
1555 LOGREL(("HGSMIHeapSetup failed rc = 0x%x", rc));
1556
1557 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), &pvBuffer);
1558 }
1559 else
1560 LOGREL(("VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
1561#endif
1562 return rc;
1563}
1564
1565int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1566{
1567 Assert(pInfo->fEnabled);
1568 if (!pInfo->fEnabled)
1569 return VINF_ALREADY_INITIALIZED;
1570
1571 /* ensure nothing else is submitted */
1572 pInfo->fEnabled = FALSE;
1573#ifdef VBOX_WITH_VDMA
1574 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1575 AssertRC(rc);
1576 return rc;
1577#else
1578 return VINF_SUCCESS;
1579#endif
1580}
1581
1582int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1583{
1584 Assert(!pInfo->fEnabled);
1585 if (pInfo->fEnabled)
1586 return VINF_ALREADY_INITIALIZED;
1587#ifdef VBOX_WITH_VDMA
1588 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1589 Assert(RT_SUCCESS(rc));
1590 if (RT_SUCCESS(rc))
1591 pInfo->fEnabled = TRUE;
1592
1593 return rc;
1594#else
1595 return VINF_SUCCESS;
1596#endif
1597}
1598
1599#ifdef VBOX_WITH_VDMA
1600int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1601{
1602 Assert(pInfo->fEnabled);
1603 if (!pInfo->fEnabled)
1604 return VINF_ALREADY_INITIALIZED;
1605
1606 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1607 Assert(RT_SUCCESS(rc));
1608
1609 return rc;
1610}
1611#endif
1612
1613int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1614{
1615 int rc = VINF_SUCCESS;
1616 Assert(!pInfo->fEnabled);
1617 if (pInfo->fEnabled)
1618 rc = vboxVdmaDisable (pDevExt, pInfo);
1619#ifdef VBOX_WITH_VDMA
1620 VBoxSHGSMITerm(&pInfo->CmdHeap);
1621 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base);
1622#endif
1623 return rc;
1624}
1625
1626#ifdef VBOX_WITH_VDMA
1627void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1628{
1629 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1630}
1631
1632PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1633{
1634 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1635 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1636 Assert(pDr);
1637 if (pDr)
1638 memset (pDr, 0, cbDr);
1639 else
1640 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1641
1642 return pDr;
1643}
1644
1645static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext)
1646{
1647 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1648 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1649
1650 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1651}
1652
1653static DECLCALLBACK(PFNVBOXSHGSMICMDCOMPLETION) vboxVdmaCBufDrCompletionIrq(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext, void **ppvCompletion)
1654{
1655 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1656 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1657 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1658
1659 DXGK_INTERRUPT_TYPE enmComplType;
1660
1661 if (RT_SUCCESS(pDr->rc))
1662 {
1663 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1664 }
1665 else if (pDr->rc == VERR_INTERRUPTED)
1666 {
1667 Assert(0);
1668 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1669 }
1670 else
1671 {
1672 Assert(0);
1673 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1674 }
1675
1676 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1677 {
1678 pDevExt->bNotifyDxDpc = TRUE;
1679 }
1680
1681 /* inform SHGSMI we DO NOT want to be called at DPC later */
1682 return NULL;
1683// *ppvCompletion = pvContext;
1684}
1685
1686int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1687{
1688 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1689 Assert(pHdr);
1690 int rc = VERR_GENERAL_FAILURE;
1691 if (pHdr)
1692 {
1693 do
1694 {
1695 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1696 Assert(offCmd != HGSMIOFFSET_VOID);
1697 if (offCmd != HGSMIOFFSET_VOID)
1698 {
1699 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1700 AssertRC(rc);
1701 if (RT_SUCCESS(rc))
1702 {
1703 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1704 AssertRC(rc);
1705 break;
1706 }
1707 }
1708 else
1709 rc = VERR_INVALID_PARAMETER;
1710 /* fail to submit, cancel it */
1711 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1712 } while (0);
1713 }
1714 else
1715 rc = VERR_INVALID_PARAMETER;
1716 return rc;
1717}
1718
1719int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1720{
1721 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1722 Assert(pHdr);
1723 int rc = VERR_GENERAL_FAILURE;
1724 if (pHdr)
1725 {
1726 do
1727 {
1728 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1729 Assert(offCmd != HGSMIOFFSET_VOID);
1730 if (offCmd != HGSMIOFFSET_VOID)
1731 {
1732 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1733 AssertRC(rc);
1734 if (RT_SUCCESS(rc))
1735 {
1736 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1737 AssertRC(rc);
1738 break;
1739 }
1740 }
1741 else
1742 rc = VERR_INVALID_PARAMETER;
1743 /* fail to submit, cancel it */
1744 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1745 } while (0);
1746 }
1747 else
1748 rc = VERR_INVALID_PARAMETER;
1749 return rc;
1750}
1751#endif
1752
1753
1754/* ddi dma command queue */
1755
1756VOID vboxVdmaDdiCmdGetCompletedListIsr(PVBOXMP_DEVEXT pDevExt, LIST_ENTRY *pList)
1757{
1758 vboxVideoLeDetach(&pDevExt->DpcCmdQueue, pList);
1759}
1760
1761BOOLEAN vboxVdmaDdiCmdIsCompletedListEmptyIsr(PVBOXMP_DEVEXT pDevExt)
1762{
1763 return IsListEmpty(&pDevExt->DpcCmdQueue);
1764}
1765
1766DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
1767{
1768 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
1769 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1770}
1771
1772DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1773{
1774 vboxWddmMemFree(pCmd);
1775}
1776
1777static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1778{
1779 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
1780 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1781 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1782 switch (enmComplType)
1783 {
1784 case DXGK_INTERRUPT_DMA_COMPLETED:
1785 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1786 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
1787 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
1788 pNode->uLastCompletedFenceId = u32FenceId;
1789 break;
1790
1791 case DXGK_INTERRUPT_DMA_PREEMPTED:
1792 Assert(0);
1793 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1794 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
1795 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
1796 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
1797 break;
1798
1799 case DXGK_INTERRUPT_DMA_FAULTED:
1800 Assert(0);
1801 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1802 notify.DmaFaulted.FaultedFenceId = u32FenceId;
1803 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1804 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
1805 break;
1806
1807 default:
1808 Assert(0);
1809 break;
1810 }
1811
1812 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1813}
1814
1815static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1816{
1817 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
1818 switch (enmComplType)
1819 {
1820 case DXGK_INTERRUPT_DMA_COMPLETED:
1821 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1822 break;
1823 default:
1824 AssertFailed();
1825 break;
1826 }
1827}
1828
1829DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1830{
1831 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1832 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1833 RemoveEntryList(&pCmd->QueueEntry);
1834}
1835
1836DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1837{
1838 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1839 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1840 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1841}
1842
1843VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
1844{
1845 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
1846 {
1847 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
1848 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
1849 pQueue->cQueuedCmds = 0;
1850 InitializeListHead(&pQueue->CmdQueue);
1851 }
1852 InitializeListHead(&pDevExt->DpcCmdQueue);
1853}
1854
1855BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1856{
1857 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1858 {
1859 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1860 return FALSE;
1861 }
1862
1863 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1864 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1865 BOOLEAN bComplete = FALSE;
1866 Assert(!bQueued || pQueue->cQueuedCmds);
1867 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1868 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1869 if (bQueued)
1870 {
1871 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1872 {
1873 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1874 bComplete = TRUE;
1875 }
1876 }
1877 else if (IsListEmpty(&pQueue->CmdQueue))
1878 {
1879 bComplete = TRUE;
1880 }
1881 else
1882 {
1883 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1884 }
1885
1886 if (bComplete)
1887 {
1888 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
1889
1890 while (!IsListEmpty(&pQueue->CmdQueue))
1891 {
1892 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1893 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1894 {
1895 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1896 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
1897 }
1898 else
1899 break;
1900 }
1901 }
1902 else
1903 {
1904 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1905 pCmd->enmComplType = enmComplType;
1906 }
1907
1908 return bComplete;
1909}
1910
1911VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1912{
1913 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
1914 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
1915 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
1916 if (!bQueued)
1917 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1918}
1919
1920typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
1921{
1922 PVBOXMP_DEVEXT pDevExt;
1923 PVBOXVDMADDI_CMD pCmd;
1924 DXGK_INTERRUPT_TYPE enmComplType;
1925} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
1926
1927static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
1928{
1929 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
1930 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1931 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
1932 pDevExt->bNotifyDxDpc |= bNeedDpc;
1933
1934 if (bNeedDpc)
1935 {
1936 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1937 }
1938
1939 return bNeedDpc;
1940}
1941
1942NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1943{
1944 VBOXVDMADDI_CMD_COMPLETED_CB context;
1945 context.pDevExt = pDevExt;
1946 context.pCmd = pCmd;
1947 context.enmComplType = enmComplType;
1948 BOOLEAN bNeedDps;
1949 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1950 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1951 vboxVdmaDdiCmdCompletedCb,
1952 &context,
1953 0, /* IN ULONG MessageNumber */
1954 &bNeedDps);
1955 Assert(Status == STATUS_SUCCESS);
1956 return Status;
1957}
1958
1959typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
1960{
1961 PVBOXMP_DEVEXT pDevExt;
1962 PVBOXVDMADDI_CMD pCmd;
1963} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
1964
1965static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
1966{
1967 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
1968 vboxVdmaDdiCmdSubmittedIrq(pdc->pDevExt, pdc->pCmd);
1969
1970 return FALSE;
1971}
1972
1973NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1974{
1975 VBOXVDMADDI_CMD_SUBMITTED_CB context;
1976 context.pDevExt = pDevExt;
1977 context.pCmd = pCmd;
1978 BOOLEAN bRc;
1979 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1980 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1981 vboxVdmaDdiCmdSubmittedCb,
1982 &context,
1983 0, /* IN ULONG MessageNumber */
1984 &bRc);
1985 Assert(Status == STATUS_SUCCESS);
1986 return Status;
1987}
1988
1989typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
1990{
1991 PVBOXMP_DEVEXT pDevExt;
1992 UINT u32NodeOrdinal;
1993 uint32_t u32FenceId;
1994} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
1995
1996static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
1997{
1998 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
1999 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2000
2001 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
2002
2003 pDevExt->bNotifyDxDpc = TRUE;
2004 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
2005
2006 return TRUE;
2007}
2008
2009static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
2010{
2011 VBOXVDMADDI_CMD_COMPLETE_CB context;
2012 context.pDevExt = pDevExt;
2013 context.u32NodeOrdinal = u32NodeOrdinal;
2014 context.u32FenceId = u32FenceId;
2015 BOOLEAN bRet;
2016 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2017 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2018 vboxVdmaDdiCmdFenceCompleteCb,
2019 &context,
2020 0, /* IN ULONG MessageNumber */
2021 &bRet);
2022 Assert(Status == STATUS_SUCCESS);
2023 return Status;
2024}
2025
2026NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
2027{
2028 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
2029 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
2030
2031 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
2032 Assert(pCmd);
2033 if (pCmd)
2034 {
2035 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
2036 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
2037 Assert(Status == STATUS_SUCCESS);
2038 if (Status == STATUS_SUCCESS)
2039 return STATUS_SUCCESS;
2040 vboxWddmMemFree(pCmd);
2041 return Status;
2042 }
2043 return STATUS_NO_MEMORY;
2044}
2045
2046#ifdef VBOXWDDM_RENDER_FROM_SHADOW
2047NTSTATUS vboxVdmaHlpUpdatePrimary(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT* pRect)
2048{
2049 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
2050 Assert(pSource->pPrimaryAllocation);
2051 Assert(pSource->pShadowAllocation);
2052 if (!pSource->pPrimaryAllocation)
2053 return STATUS_INVALID_PARAMETER;
2054 if (!pSource->pShadowAllocation)
2055 return STATUS_INVALID_PARAMETER;
2056
2057 if (vboxWddmAddrFramOffset(&pSource->pPrimaryAllocation->AllocData.Addr) == VBOXVIDEOOFFSET_VOID)
2058 {
2059 WARN(("invalid primary"));
2060 return STATUS_INVALID_PARAMETER;
2061 }
2062 if (vboxWddmAddrFramOffset(&pSource->pShadowAllocation->AllocData.Addr) == VBOXVIDEOOFFSET_VOID)
2063 {
2064 WARN(("invalid secondary"));
2065 return STATUS_INVALID_PARAMETER;
2066 }
2067
2068 NTSTATUS Status = vboxVdmaGgDmaBltPerform(pDevExt, &pSource->pShadowAllocation->AllocData, pRect, &pSource->pPrimaryAllocation->AllocData, pRect);
2069 Assert(Status == STATUS_SUCCESS);
2070 return Status;
2071}
2072#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