VirtualBox

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

Last change on this file since 57801 was 55421, checked in by vboxsync, 10 years ago

HGSMI: cleanup, logging, comments, move legacy host heap support from common code to the host code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.9 KB
Line 
1/* $Id: VBoxMPVdma.cpp 55421 2015-04-24 12:00:21Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMPWddm.h"
20#include "common/VBoxMPCommon.h"
21#include "VBoxMPVdma.h"
22#include "VBoxMPVhwa.h"
23#include <iprt/asm.h>
24#include "VBoxMPCr.h"
25#include <iprt/mem.h>
26
27#ifdef VBOX_WITH_CROGL
28# include <packer.h>
29#endif
30
31static NTSTATUS vboxVdmaCrCtlGetDefaultClientId(PVBOXMP_DEVEXT pDevExt, uint32_t *pu32ClienID);
32
33NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe)
34{
35 KeInitializeSpinLock(&pPipe->SinchLock);
36 KeInitializeEvent(&pPipe->Event, SynchronizationEvent, FALSE);
37 InitializeListHead(&pPipe->CmdListHead);
38 pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
39 pPipe->bNeedNotify = true;
40 return STATUS_SUCCESS;
41}
42
43NTSTATUS vboxVdmaPipeSvrOpen(PVBOXVDMAPIPE pPipe)
44{
45 NTSTATUS Status = STATUS_SUCCESS;
46 KIRQL OldIrql;
47 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
48 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
49 switch (pPipe->enmState)
50 {
51 case VBOXVDMAPIPE_STATE_CREATED:
52 pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
53 pPipe->bNeedNotify = false;
54 break;
55 case VBOXVDMAPIPE_STATE_OPENNED:
56 pPipe->bNeedNotify = false;
57 break;
58 default:
59 AssertBreakpoint();
60 Status = STATUS_INVALID_PIPE_STATE;
61 break;
62 }
63
64 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
65 return Status;
66}
67
68NTSTATUS vboxVdmaPipeSvrClose(PVBOXVDMAPIPE pPipe)
69{
70 NTSTATUS Status = STATUS_SUCCESS;
71 KIRQL OldIrql;
72 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
73 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
74 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
75 switch (pPipe->enmState)
76 {
77 case VBOXVDMAPIPE_STATE_CLOSING:
78 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
79 break;
80 case VBOXVDMAPIPE_STATE_CLOSED:
81 break;
82 default:
83 AssertBreakpoint();
84 Status = STATUS_INVALID_PIPE_STATE;
85 break;
86 }
87
88 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
89 return Status;
90}
91
92NTSTATUS vboxVdmaPipeCltClose(PVBOXVDMAPIPE pPipe)
93{
94 NTSTATUS Status = STATUS_SUCCESS;
95 KIRQL OldIrql;
96 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
97 bool bNeedNotify = false;
98 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
99 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
100 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
101 switch (pPipe->enmState)
102 {
103 case VBOXVDMAPIPE_STATE_OPENNED:
104 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
105 bNeedNotify = pPipe->bNeedNotify;
106 pPipe->bNeedNotify = false;
107 break;
108 case VBOXVDMAPIPE_STATE_CREATED:
109 pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
110 pPipe->bNeedNotify = false;
111 break;
112 case VBOXVDMAPIPE_STATE_CLOSED:
113 break;
114 default:
115 AssertBreakpoint();
116 Status = STATUS_INVALID_PIPE_STATE;
117 break;
118 }
119
120 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
121
122 if (bNeedNotify)
123 {
124 KeSetEvent(&pPipe->Event, 0, FALSE);
125 }
126 return Status;
127}
128
129NTSTATUS vboxVdmaPipeDestruct(PVBOXVDMAPIPE pPipe)
130{
131 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
132 || pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
133 /* ensure the pipe is closed */
134 NTSTATUS Status = vboxVdmaPipeCltClose(pPipe);
135 Assert(Status == STATUS_SUCCESS);
136
137 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
138
139 return Status;
140}
141
142NTSTATUS vboxVdmaPipeSvrCmdGetList(PVBOXVDMAPIPE pPipe, PLIST_ENTRY pDetachHead)
143{
144 PLIST_ENTRY pEntry = NULL;
145 KIRQL OldIrql;
146 NTSTATUS Status = STATUS_SUCCESS;
147 VBOXVDMAPIPE_STATE enmState = VBOXVDMAPIPE_STATE_CLOSED;
148 do
149 {
150 bool bListEmpty = true;
151 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
152 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
153 || pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
154 Assert(pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED);
155 enmState = pPipe->enmState;
156 if (enmState >= VBOXVDMAPIPE_STATE_OPENNED)
157 {
158 vboxVideoLeDetach(&pPipe->CmdListHead, pDetachHead);
159 bListEmpty = !!(IsListEmpty(pDetachHead));
160 pPipe->bNeedNotify = bListEmpty;
161 }
162 else
163 {
164 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
165 Status = STATUS_INVALID_PIPE_STATE;
166 break;
167 }
168
169 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
170
171 if (!bListEmpty)
172 {
173 Assert(Status == STATUS_SUCCESS);
174 break;
175 }
176
177 if (enmState == VBOXVDMAPIPE_STATE_OPENNED)
178 {
179 Status = KeWaitForSingleObject(&pPipe->Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */);
180 Assert(Status == STATUS_SUCCESS);
181 if (Status != STATUS_SUCCESS)
182 break;
183 }
184 else
185 {
186 Assert(enmState == VBOXVDMAPIPE_STATE_CLOSING);
187 Status = STATUS_PIPE_CLOSING;
188 break;
189 }
190 } while (1);
191
192 return Status;
193}
194
195NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd)
196{
197 NTSTATUS Status = STATUS_SUCCESS;
198 KIRQL OldIrql;
199 bool bNeedNotify = false;
200
201 KeAcquireSpinLock(&pPipe->SinchLock, &OldIrql);
202
203 Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
204 if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
205 {
206 bNeedNotify = pPipe->bNeedNotify;
207 InsertHeadList(&pPipe->CmdListHead, &pCmd->ListEntry);
208 pPipe->bNeedNotify = false;
209 }
210 else
211 Status = STATUS_INVALID_PIPE_STATE;
212
213 KeReleaseSpinLock(&pPipe->SinchLock, OldIrql);
214
215 if (bNeedNotify)
216 {
217 KeSetEvent(&pPipe->Event, 0, FALSE);
218 }
219
220 return Status;
221}
222
223DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const VBOXWDDM_RECTS_INFO *pRects, PVBOXWDDM_RECTS_INFO pResult)
224{
225 uint32_t cRects = 0;
226 for (uint32_t i = 0; i < pRects->cRects; ++i)
227 {
228 if (vboxWddmRectIntersection(pArea, &pRects->aRects[i], &pResult->aRects[cRects]))
229 {
230 ++cRects;
231 }
232 }
233
234 pResult->cRects = cRects;
235}
236
237DECLINLINE(bool) vboxVdmaDirtyRectsHasIntersections(const RECT *paRects1, uint32_t cRects1, const RECT *paRects2, uint32_t cRects2)
238{
239 RECT tmpRect;
240 for (uint32_t i = 0; i < cRects1; ++i)
241 {
242 const RECT * pRect1 = &paRects1[i];
243 for (uint32_t j = 0; j < cRects2; ++j)
244 {
245 const RECT * pRect2 = &paRects2[j];
246 if (vboxWddmRectIntersection(pRect1, pRect2, &tmpRect))
247 return true;
248 }
249 }
250 return false;
251}
252
253DECLINLINE(bool) vboxVdmaDirtyRectsIsCover(const RECT *paRects, uint32_t cRects, const RECT *paRectsCovered, uint32_t cRectsCovered)
254{
255 for (uint32_t i = 0; i < cRectsCovered; ++i)
256 {
257 const RECT * pRectCovered = &paRectsCovered[i];
258 uint32_t j = 0;
259 for (; j < cRects; ++j)
260 {
261 const RECT * pRect = &paRects[j];
262 if (vboxWddmRectIsCoveres(pRect, pRectCovered))
263 break;
264 }
265 if (j == cRects)
266 return false;
267 }
268 return true;
269}
270#ifdef VBOX_WITH_CROGL
271NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain)
272{
273 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
274 uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(0);
275 PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal =
276 (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pSwapchain->pContext->CmContext, cbCmdInternal);
277 Assert(pCmdInternal);
278 if (pCmdInternal)
279 {
280 pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm;
281 pCmdInternal->Cmd.fFlags.Value = 0;
282 pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1;
283 pCmdInternal->Cmd.fFlags.bHide = 1;
284 pCmdInternal->Cmd.RectsInfo.cRects = 0;
285 vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
286 return STATUS_SUCCESS;
287 }
288 return STATUS_NO_MEMORY;
289}
290#endif
291static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y)
292{
293 vboxWddmRectTranslate(&pRects->ContextRect, x, y);
294
295 for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i)
296 {
297 vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y);
298 }
299}
300
301static VBOXVDMAPIPE_RECTS * vboxWddmBltPipeRectsDup(const VBOXVDMAPIPE_RECTS *pRects)
302{
303 const size_t cbDup = RT_OFFSETOF(VBOXVDMAPIPE_RECTS, UpdateRects.aRects[pRects->UpdateRects.cRects]);
304 VBOXVDMAPIPE_RECTS *pDup = (VBOXVDMAPIPE_RECTS*)vboxWddmMemAllocZero(cbDup);
305 if (!pDup)
306 {
307 WARN(("vboxWddmMemAllocZero failed"));
308 return NULL;
309 }
310 memcpy(pDup, pRects, cbDup);
311 return pDup;
312}
313#ifdef VBOX_WITH_CROGL
314typedef struct VBOXMP_VDMACR_WRITECOMPLETION
315{
316 void *pvBufferToFree;
317} VBOXMP_VDMACR_WRITECOMPLETION, *PVBOXMP_VDMACR_WRITECOMPLETION;
318
319static DECLCALLBACK(void) vboxVdmaCrWriteCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvCtx)
320{
321 PVBOXMP_VDMACR_WRITECOMPLETION pData = (PVBOXMP_VDMACR_WRITECOMPLETION)pvCtx;
322 void* pvBufferToFree = pData->pvBufferToFree;
323 if (pvBufferToFree)
324 VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree);
325
326 VBoxMpCrShgsmiTransportCmdTermWriteAsync(pCon, pvCtx);
327}
328
329typedef struct VBOXMP_VDMACR_WRITEREADCOMPLETION
330{
331 void *pvBufferToFree;
332 void *pvContext;
333} VBOXMP_VDMACR_WRITEREADCOMPLETION, *PVBOXMP_VDMACR_WRITEREADCOMPLETION;
334
335void vboxVdmaCrSubmitWriteReadAsyncGenericCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvCtx)
336{
337 PVBOXMP_VDMACR_WRITEREADCOMPLETION pData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)pvCtx;
338 void* pvBufferToFree = pData->pvBufferToFree;
339 if (pvBufferToFree)
340 VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree);
341
342 VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(pCon, pvCtx);
343}
344
345NTSTATUS vboxVdmaCrSubmitWriteReadAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID, PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion, void *pvCompletion)
346{
347 Assert(u32CrConClientID);
348 NTSTATUS Status = STATUS_SUCCESS;
349 uint32_t cbBuffer;
350 void * pvPackBuffer;
351 void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer);
352 if (pvBuffer)
353 {
354 PVBOXMP_VDMACR_WRITEREADCOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer,
355 pfnCompletion, sizeof (*pvCompletionData));
356 if (pvCompletionData)
357 {
358 pvCompletionData->pvBufferToFree = pvPackBuffer;
359 pvCompletionData->pvContext = pvCompletion;
360 int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
361 if (RT_SUCCESS(rc))
362 {
363 return STATUS_SUCCESS;
364 }
365 WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync failed, rc %d", rc));
366 Status = STATUS_UNSUCCESSFUL;
367 VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
368 }
369 else
370 {
371 WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync failed"));
372 Status = STATUS_INSUFFICIENT_RESOURCES;
373 }
374 }
375
376 return Status;
377}
378
379NTSTATUS vboxVdmaCrSubmitWriteAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID)
380{
381 Assert(u32CrConClientID);
382 NTSTATUS Status = STATUS_SUCCESS;
383 uint32_t cbBuffer;
384 void * pvPackBuffer;
385 void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer);
386 if (pvBuffer)
387 {
388 PVBOXMP_VDMACR_WRITECOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITECOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer,
389 vboxVdmaCrWriteCompletion, sizeof (*pvCompletionData));
390 if (pvCompletionData)
391 {
392 pvCompletionData->pvBufferToFree = pvPackBuffer;
393 int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
394 if (RT_SUCCESS(rc))
395 {
396 return STATUS_SUCCESS;
397 }
398 WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteAsync failed, rc %d", rc));
399 Status = STATUS_UNSUCCESSFUL;
400 VBoxMpCrShgsmiTransportCmdTermWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData);
401 }
402 else
403 {
404 WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteAsync failed"));
405 Status = STATUS_INSUFFICIENT_RESOURCES;
406 }
407 }
408
409 return Status;
410}
411
412static NTSTATUS vboxVdmaVRegGet(PVBOXWDDM_SWAPCHAIN pSwapchain, const RTRECT *pCtxRect, uint32_t *pcVRects, RTRECT **ppVRectsBuff, uint32_t *pcVRectsBuff)
413{
414 RTRECT *pVRectsBuff = *ppVRectsBuff;
415 uint32_t cVRectsBuff = *pcVRectsBuff;
416 uint32_t cVRects = VBoxVrListRectsCount(&pSwapchain->VisibleRegions);
417 if (cVRectsBuff < cVRects)
418 {
419 if (pVRectsBuff)
420 vboxWddmMemFree(pVRectsBuff);
421 pVRectsBuff = (RTRECT*)vboxWddmMemAlloc(cVRects * sizeof (pVRectsBuff[0]));
422 if (!pVRectsBuff)
423 {
424 WARN(("vboxWddmMemAlloc failed"));
425 *pcVRectsBuff = 0;
426 *ppVRectsBuff = NULL;
427 *pcVRects = NULL;
428 return STATUS_NO_MEMORY;
429 }
430
431 cVRectsBuff = cVRects;
432 *pcVRectsBuff = cVRectsBuff;
433 *ppVRectsBuff = pVRectsBuff;
434 }
435
436 int rc = VBoxVrListRectsGet(&pSwapchain->VisibleRegions, cVRects, pVRectsBuff);
437 AssertRC(rc);
438 if (pCtxRect->xLeft || pCtxRect->yTop)
439 {
440 for (UINT i = 0; i < cVRects; ++i)
441 {
442 VBoxRectTranslate(&pVRectsBuff[i], -pCtxRect->xLeft, -pCtxRect->yTop);
443 }
444 }
445
446 *pcVRects = cVRects;
447 return STATUS_SUCCESS;
448}
449
450
451/**
452 * @param pDevExt
453 */
454static NTSTATUS vboxVdmaProcessVRegCmdLegacy(PVBOXMP_DEVEXT pDevExt,
455 VBOXMP_CRPACKER *pCrPacker,
456 uint32_t u32CrConClientID,
457 PVBOXWDDM_SOURCE pSource,
458 PVBOXWDDM_SWAPCHAIN pSwapchain,
459 const RECT *pSrcRect,
460 const VBOXVDMAPIPE_RECTS *pContextRects)
461{
462 VBOXVDMAPIPE_RECTS *pRectsToFree = NULL;
463 POINT pos = pSource->VScreenPos;
464 if (pos.x || pos.y)
465 {
466 pRectsToFree = vboxWddmBltPipeRectsDup(pContextRects);
467 /* note: do NOT translate the src rect since it is used for screen pos calculation */
468 vboxWddmBltPipeRectsTranslate(pRectsToFree, pos.x, pos.y);
469 pContextRects = pRectsToFree;
470 }
471 const VBOXWDDM_RECTS_INFO *pRects = &pContextRects->UpdateRects;
472 NTSTATUS Status = STATUS_SUCCESS;
473 int rc;
474 bool fCurChanged = FALSE, fCurRectChanged = FALSE;
475 POINT CurPos;
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);
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 Assert(Status == STATUS_SUCCESS);
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 Assert(Status == STATUS_SUCCESS);
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 == pDstAllocData->SurfDesc.width
1262 && Rect.yBottom == 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 NTSTATUS Status = STATUS_SUCCESS;
1471 PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
1472#ifdef VBOX_WITH_CROGL
1473 if (!pAlloc->AllocData.hostID)
1474#endif
1475 {
1476 Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill);
1477 if (!NT_SUCCESS(Status))
1478 WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status));
1479 }
1480#ifdef VBOX_WITH_CROGL
1481 else
1482 WARN(("unexpected clrfill request"));
1483#endif
1484
1485 return Status;
1486}
1487
1488
1489#ifdef VBOX_WITH_VDMA
1490/*
1491 * This is currently used by VDMA. It is invisible for Vdma API clients since
1492 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1493 * transport for DMA commands submission
1494 */
1495
1496#ifdef VBOXVDMA_WITH_VBVA
1497static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1498{
1499 int rc;
1500 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1501 {
1502 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1503 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1504 }
1505 else
1506 {
1507 AssertBreakpoint();
1508 rc = VERR_INVALID_STATE;
1509 }
1510 return rc;
1511}
1512#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1513#else
1514static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1515{
1516 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1517 return VINF_SUCCESS;
1518}
1519#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1520#endif
1521
1522static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1523{
1524 int rc = VINF_SUCCESS;
1525
1526 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1527 if (pCmd)
1528 {
1529 pCmd->enmCtl = enmCtl;
1530 pCmd->u32Offset = pInfo->CmdHeap.Heap.area.offBase;
1531 pCmd->i32Result = VERR_NOT_SUPPORTED;
1532
1533 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1534 Assert(pHdr);
1535 if (pHdr)
1536 {
1537 do
1538 {
1539 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1540 Assert(offCmd != HGSMIOFFSET_VOID);
1541 if (offCmd != HGSMIOFFSET_VOID)
1542 {
1543 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1544 AssertRC(rc);
1545 if (RT_SUCCESS(rc))
1546 {
1547 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1548 AssertRC(rc);
1549 if (RT_SUCCESS(rc))
1550 {
1551 rc = pCmd->i32Result;
1552 AssertRC(rc);
1553 }
1554 break;
1555 }
1556 }
1557 else
1558 rc = VERR_INVALID_PARAMETER;
1559 /* fail to submit, cancel it */
1560 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1561 } while (0);
1562 }
1563
1564 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1565 }
1566 else
1567 {
1568 LOGREL(("HGSMIHeapAlloc failed"));
1569 rc = VERR_OUT_OF_RESOURCES;
1570 }
1571
1572 return rc;
1573}
1574#endif
1575
1576static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb)
1577{
1578 NOREF(pvEnv);
1579 return RTMemAlloc(cb);
1580}
1581
1582static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv)
1583{
1584 NOREF(pvEnv);
1585 RTMemFree(pv);
1586}
1587
1588static HGSMIENV g_hgsmiEnvVdma =
1589{
1590 NULL,
1591 hgsmiEnvAlloc,
1592 hgsmiEnvFree
1593};
1594
1595/* create a DMACommand buffer */
1596int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1597#ifdef VBOX_WITH_VDMA
1598 , ULONG offBuffer, ULONG cbBuffer
1599#endif
1600 )
1601{
1602 int rc;
1603 pInfo->fEnabled = FALSE;
1604
1605#ifdef VBOX_WITH_VDMA
1606 Assert((offBuffer & 0xfff) == 0);
1607 Assert((cbBuffer & 0xfff) == 0);
1608 Assert(offBuffer);
1609 Assert(cbBuffer);
1610
1611 if((offBuffer & 0xfff)
1612 || (cbBuffer & 0xfff)
1613 || !offBuffer
1614 || !cbBuffer)
1615 {
1616 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1617 return VERR_INVALID_PARAMETER;
1618 }
1619 PVOID pvBuffer;
1620
1621 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1622 &pvBuffer,
1623 offBuffer,
1624 cbBuffer);
1625 Assert(RT_SUCCESS(rc));
1626 if (RT_SUCCESS(rc))
1627 {
1628 /* Setup a HGSMI heap within the adapter information area. */
1629 rc = VBoxSHGSMIInit(&pInfo->CmdHeap,
1630 pvBuffer,
1631 cbBuffer,
1632 offBuffer,
1633 &g_hgsmiEnvVdma);
1634 Assert(RT_SUCCESS(rc));
1635 if(RT_SUCCESS(rc))
1636#endif
1637 {
1638 return VINF_SUCCESS;
1639 }
1640#ifdef VBOX_WITH_VDMA
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#endif
1649 return rc;
1650}
1651
1652int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1653{
1654 Assert(pInfo->fEnabled);
1655 if (!pInfo->fEnabled)
1656 return VINF_ALREADY_INITIALIZED;
1657
1658 /* ensure nothing else is submitted */
1659 pInfo->fEnabled = FALSE;
1660#ifdef VBOX_WITH_VDMA
1661 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1662 AssertRC(rc);
1663 return rc;
1664#else
1665 return VINF_SUCCESS;
1666#endif
1667}
1668
1669int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1670{
1671 Assert(!pInfo->fEnabled);
1672 if (pInfo->fEnabled)
1673 return VINF_ALREADY_INITIALIZED;
1674#ifdef VBOX_WITH_VDMA
1675 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1676 Assert(RT_SUCCESS(rc));
1677 if (RT_SUCCESS(rc))
1678 pInfo->fEnabled = TRUE;
1679
1680 return rc;
1681#else
1682 return VINF_SUCCESS;
1683#endif
1684}
1685
1686#ifdef VBOX_WITH_VDMA
1687int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1688{
1689 Assert(pInfo->fEnabled);
1690 if (!pInfo->fEnabled)
1691 return VINF_ALREADY_INITIALIZED;
1692
1693 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1694 Assert(RT_SUCCESS(rc));
1695
1696 return rc;
1697}
1698#endif
1699
1700int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1701{
1702 int rc = VINF_SUCCESS;
1703 Assert(!pInfo->fEnabled);
1704 if (pInfo->fEnabled)
1705 rc = vboxVdmaDisable (pDevExt, pInfo);
1706#ifdef VBOX_WITH_VDMA
1707 VBoxSHGSMITerm(&pInfo->CmdHeap);
1708 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base);
1709#endif
1710 return rc;
1711}
1712
1713#ifdef VBOX_WITH_VDMA
1714void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1715{
1716 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1717}
1718
1719PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1720{
1721 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1722 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1723 Assert(pDr);
1724 if (pDr)
1725 memset (pDr, 0, cbDr);
1726 else
1727 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1728
1729 return pDr;
1730}
1731
1732static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext)
1733{
1734 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1735 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1736
1737 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1738}
1739
1740static DECLCALLBACK(PFNVBOXSHGSMICMDCOMPLETION) vboxVdmaCBufDrCompletionIrq(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext, void **ppvCompletion)
1741{
1742 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1743 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1744 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1745
1746 DXGK_INTERRUPT_TYPE enmComplType;
1747
1748 if (RT_SUCCESS(pDr->rc))
1749 {
1750 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1751 }
1752 else if (pDr->rc == VERR_INTERRUPTED)
1753 {
1754 Assert(0);
1755 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1756 }
1757 else
1758 {
1759 Assert(0);
1760 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1761 }
1762
1763 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1764 {
1765 pDevExt->bNotifyDxDpc = TRUE;
1766 }
1767
1768 /* inform SHGSMI we DO NOT want to be called at DPC later */
1769 return NULL;
1770// *ppvCompletion = pvContext;
1771}
1772
1773int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1774{
1775 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1776 Assert(pHdr);
1777 int rc = VERR_GENERAL_FAILURE;
1778 if (pHdr)
1779 {
1780 do
1781 {
1782 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1783 Assert(offCmd != HGSMIOFFSET_VOID);
1784 if (offCmd != HGSMIOFFSET_VOID)
1785 {
1786 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1787 AssertRC(rc);
1788 if (RT_SUCCESS(rc))
1789 {
1790 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1791 AssertRC(rc);
1792 break;
1793 }
1794 }
1795 else
1796 rc = VERR_INVALID_PARAMETER;
1797 /* fail to submit, cancel it */
1798 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1799 } while (0);
1800 }
1801 else
1802 rc = VERR_INVALID_PARAMETER;
1803 return rc;
1804}
1805
1806int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1807{
1808 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1809 Assert(pHdr);
1810 int rc = VERR_GENERAL_FAILURE;
1811 if (pHdr)
1812 {
1813 do
1814 {
1815 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1816 Assert(offCmd != HGSMIOFFSET_VOID);
1817 if (offCmd != HGSMIOFFSET_VOID)
1818 {
1819 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1820 AssertRC(rc);
1821 if (RT_SUCCESS(rc))
1822 {
1823 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1824 AssertRC(rc);
1825 break;
1826 }
1827 }
1828 else
1829 rc = VERR_INVALID_PARAMETER;
1830 /* fail to submit, cancel it */
1831 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1832 } while (0);
1833 }
1834 else
1835 rc = VERR_INVALID_PARAMETER;
1836 return rc;
1837}
1838#endif
1839
1840
1841/* ddi dma command queue */
1842
1843VOID vboxVdmaDdiCmdGetCompletedListIsr(PVBOXMP_DEVEXT pDevExt, LIST_ENTRY *pList)
1844{
1845 vboxVideoLeDetach(&pDevExt->DpcCmdQueue, pList);
1846}
1847
1848BOOLEAN vboxVdmaDdiCmdIsCompletedListEmptyIsr(PVBOXMP_DEVEXT pDevExt)
1849{
1850 return IsListEmpty(&pDevExt->DpcCmdQueue);
1851}
1852
1853DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
1854{
1855 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
1856 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1857}
1858
1859DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1860{
1861 vboxWddmMemFree(pCmd);
1862}
1863
1864static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1865{
1866 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
1867 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1868 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1869 switch (enmComplType)
1870 {
1871 case DXGK_INTERRUPT_DMA_COMPLETED:
1872 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1873 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
1874 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
1875 pNode->uLastCompletedFenceId = u32FenceId;
1876 break;
1877
1878 case DXGK_INTERRUPT_DMA_PREEMPTED:
1879 Assert(0);
1880 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1881 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
1882 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
1883 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
1884 break;
1885
1886 case DXGK_INTERRUPT_DMA_FAULTED:
1887 Assert(0);
1888 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1889 notify.DmaFaulted.FaultedFenceId = u32FenceId;
1890 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1891 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
1892 break;
1893
1894 default:
1895 Assert(0);
1896 break;
1897 }
1898
1899 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1900}
1901
1902static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1903{
1904 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
1905 switch (enmComplType)
1906 {
1907 case DXGK_INTERRUPT_DMA_COMPLETED:
1908 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1909 break;
1910 default:
1911 AssertFailed();
1912 break;
1913 }
1914}
1915
1916DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1917{
1918 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1919 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1920 RemoveEntryList(&pCmd->QueueEntry);
1921}
1922
1923DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1924{
1925 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1926 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1927 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1928}
1929
1930VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
1931{
1932 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
1933 {
1934 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
1935 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
1936 pQueue->cQueuedCmds = 0;
1937 InitializeListHead(&pQueue->CmdQueue);
1938 }
1939 InitializeListHead(&pDevExt->DpcCmdQueue);
1940}
1941
1942BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1943{
1944 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1945 {
1946 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1947 return FALSE;
1948 }
1949
1950 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1951 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1952 BOOLEAN bComplete = FALSE;
1953 Assert(!bQueued || pQueue->cQueuedCmds);
1954 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1955 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1956 if (bQueued)
1957 {
1958 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1959 {
1960 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1961 bComplete = TRUE;
1962 }
1963 }
1964 else if (IsListEmpty(&pQueue->CmdQueue))
1965 {
1966 bComplete = TRUE;
1967 }
1968 else
1969 {
1970 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1971 }
1972
1973 if (bComplete)
1974 {
1975 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
1976
1977 while (!IsListEmpty(&pQueue->CmdQueue))
1978 {
1979 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1980 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1981 {
1982 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1983 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
1984 }
1985 else
1986 break;
1987 }
1988 }
1989 else
1990 {
1991 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1992 pCmd->enmComplType = enmComplType;
1993 }
1994
1995 return bComplete;
1996}
1997
1998VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1999{
2000 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
2001 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
2002 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
2003 if (!bQueued)
2004 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
2005}
2006
2007typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
2008{
2009 PVBOXMP_DEVEXT pDevExt;
2010 PVBOXVDMADDI_CMD pCmd;
2011 DXGK_INTERRUPT_TYPE enmComplType;
2012} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
2013
2014static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
2015{
2016 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
2017 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2018 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
2019 pDevExt->bNotifyDxDpc |= bNeedDpc;
2020
2021 if (bNeedDpc)
2022 {
2023 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
2024 }
2025
2026 return bNeedDpc;
2027}
2028
2029NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
2030{
2031 VBOXVDMADDI_CMD_COMPLETED_CB context;
2032 context.pDevExt = pDevExt;
2033 context.pCmd = pCmd;
2034 context.enmComplType = enmComplType;
2035 BOOLEAN bNeedDps;
2036 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2037 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2038 vboxVdmaDdiCmdCompletedCb,
2039 &context,
2040 0, /* IN ULONG MessageNumber */
2041 &bNeedDps);
2042 Assert(Status == STATUS_SUCCESS);
2043 return Status;
2044}
2045
2046typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
2047{
2048 PVBOXMP_DEVEXT pDevExt;
2049 PVBOXVDMADDI_CMD pCmd;
2050} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
2051
2052static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
2053{
2054 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
2055 vboxVdmaDdiCmdSubmittedIrq(pdc->pDevExt, pdc->pCmd);
2056
2057 return FALSE;
2058}
2059
2060NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
2061{
2062 VBOXVDMADDI_CMD_SUBMITTED_CB context;
2063 context.pDevExt = pDevExt;
2064 context.pCmd = pCmd;
2065 BOOLEAN bRc;
2066 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2067 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2068 vboxVdmaDdiCmdSubmittedCb,
2069 &context,
2070 0, /* IN ULONG MessageNumber */
2071 &bRc);
2072 Assert(Status == STATUS_SUCCESS);
2073 return Status;
2074}
2075
2076typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
2077{
2078 PVBOXMP_DEVEXT pDevExt;
2079 UINT u32NodeOrdinal;
2080 uint32_t u32FenceId;
2081} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
2082
2083static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
2084{
2085 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
2086 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
2087
2088 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
2089
2090 pDevExt->bNotifyDxDpc = TRUE;
2091 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
2092
2093 return TRUE;
2094}
2095
2096static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
2097{
2098 VBOXVDMADDI_CMD_COMPLETE_CB context;
2099 context.pDevExt = pDevExt;
2100 context.u32NodeOrdinal = u32NodeOrdinal;
2101 context.u32FenceId = u32FenceId;
2102 BOOLEAN bRet;
2103 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2104 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2105 vboxVdmaDdiCmdFenceCompleteCb,
2106 &context,
2107 0, /* IN ULONG MessageNumber */
2108 &bRet);
2109 Assert(Status == STATUS_SUCCESS);
2110 return Status;
2111}
2112
2113NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
2114{
2115 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
2116 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
2117
2118 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
2119 Assert(pCmd);
2120 if (pCmd)
2121 {
2122 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
2123 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
2124 Assert(Status == STATUS_SUCCESS);
2125 if (Status == STATUS_SUCCESS)
2126 return STATUS_SUCCESS;
2127 vboxWddmMemFree(pCmd);
2128 return Status;
2129 }
2130 return STATUS_NO_MEMORY;
2131}
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