VirtualBox

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

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

*: scm --update-copyright-year

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