VirtualBox

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

Last change on this file since 74477 was 74477, checked in by vboxsync, 7 years ago

WDDM: renamed VBOXVIDEO_HWTYPE_CROGL to VBOXVIDEO_HWTYPE_VBOX. bugref:8893

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

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