VirtualBox

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

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

wddm: more cleanup & generic way for handling 3D and 2D commands

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

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