VirtualBox

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

Last change on this file since 63057 was 63057, checked in by vboxsync, 8 years ago

GA/NT/Graphics: warnings

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