VirtualBox

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

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

wddm: fix 3D disabled case

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.3 KB
Line 
1/* $Id: VBoxMPVdma.cpp 47070 2013-07-10 11:39:19Z 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 if (!pDevExt->f3DEnabled)
974 {
975 WARN(("3D disabled, should not be here!"));
976 return STATUS_UNSUCCESSFUL;
977 }
978
979 int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDevExt->u32CrConDefaultClientID);
980 if (!RT_SUCCESS(rc))
981 {
982 WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc));
983 return STATUS_UNSUCCESSFUL;
984 }
985 }
986
987 *pu32ClienID = pDevExt->u32CrConDefaultClientID;
988 return STATUS_SUCCESS;
989}
990
991static NTSTATUS vboxVdmaProcessVReg(PVBOXMP_DEVEXT pDevExt,
992 VBOXMP_CRPACKER *pCrPacker,
993 uint32_t u32CrConClientID,
994 const VBOXWDDM_ALLOC_DATA *pSrcAllocData,
995 const VBOXWDDM_ALLOC_DATA *pDstAllocData,
996 const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects)
997{
998 D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId = pDstAllocData->SurfDesc.VidPnSourceId;
999 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[srcId];
1000 NTSTATUS Status = STATUS_SUCCESS;
1001
1002 if (pDevExt->fTexPresentEnabled)
1003 {
1004 /* we care only about screen regions */
1005 if (pDstAllocData != &pSource->pPrimaryAllocation->AllocData)
1006 {
1007 WARN(("non-primary allocation passed to vboxWddmSubmitBltCmd!"));
1008 return STATUS_NOT_SUPPORTED;
1009 }
1010
1011 uint32_t hostID = pSrcAllocData->hostID;
1012 int rc;
1013 if (hostID)
1014 {
1015// Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D);
1016 int32_t posX = pDstRects->ContextRect.left - pSrcRect->left;
1017 int32_t posY = pDstRects->ContextRect.top - pSrcRect->top;
1018
1019 Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, posX, posY, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects);
1020 if (NT_SUCCESS(Status))
1021 {
1022 rc = VBoxVrListRectsSubst(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, NULL);
1023 if (RT_SUCCESS(rc))
1024 pSource->fHas3DVrs = TRUE;
1025 else
1026 WARN(("VBoxVrListRectsSubst failed rc %d, ignoring..", rc));
1027 }
1028 else
1029 WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status));
1030 }
1031 else if (&pSource->pPrimaryAllocation->AllocData == pDstAllocData)
1032 {
1033 bool fChanged = false;
1034 Assert(pSource->pPrimaryAllocation->bVisible);
1035 rc = VBoxVrListRectsAdd(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, &fChanged);
1036 if (RT_SUCCESS(rc))
1037 {
1038 if (fChanged)
1039 {
1040 Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, 0, 0, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects);
1041 if (NT_SUCCESS(Status))
1042 {
1043 if (pSource->fHas3DVrs)
1044 {
1045 if (VBoxVrListRectsCount(&pSource->VrList) == 1)
1046 {
1047 RTRECT Rect;
1048 VBoxVrListRectsGet(&pSource->VrList, 1, &Rect);
1049 if (Rect.xLeft == 0
1050 && Rect.yTop == 0
1051 && Rect.xRight == pDstAllocData->SurfDesc.width
1052 && Rect.yBottom == pDstAllocData->SurfDesc.height)
1053 {
1054 pSource->fHas3DVrs = FALSE;
1055 }
1056 }
1057 }
1058 }
1059 else
1060 WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status));
1061 }
1062 }
1063 else
1064 WARN(("VBoxVrListRectsAdd failed rc %d, ignoring..", rc));
1065 }
1066 else
1067 {
1068 WARN(("unexpected"));
1069 Status = STATUS_INVALID_PARAMETER;
1070 }
1071 }
1072 else
1073 {
1074 PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAllocData(pDevExt, pSrcAllocData);
1075
1076 if (pSwapchain)
1077 {
1078 Assert(pSrcAllocData->SurfDesc.width == pSwapchain->width);
1079 Assert(pSrcAllocData->SurfDesc.height == pSwapchain->height);
1080 }
1081
1082 Status = vboxVdmaProcessVRegCmdLegacy(pDevExt, pCrPacker, u32CrConClientID, pSource, pSwapchain, pSrcRect, pDstRects);
1083 if (!NT_SUCCESS(Status))
1084 WARN(("vboxVdmaProcessVRegCmdLegacy failed Status 0x%x", Status));
1085
1086 if (pSwapchain)
1087 vboxWddmSwapchainRelease(pSwapchain);
1088 }
1089
1090 return Status;
1091}
1092
1093NTSTATUS vboxVdmaTexPresentSetAlloc(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData)
1094{
1095 VBOXMP_CRPACKER CrPacker;
1096 VBoxMpCrPackerInit(&CrPacker);
1097 uint32_t u32CrConClientID;
1098
1099 NTSTATUS Status = vboxVdmaCrCtlGetDefaultClientId(pDevExt, &u32CrConClientID);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 WARN(("vboxVdmaCrCtlGetDefaultClientId failed Status 0x%x", Status));
1103 return Status;
1104 }
1105
1106 RECT Rect;
1107 Rect.left = 0;
1108 Rect.top = 0;
1109 Rect.right = pAllocData->SurfDesc.width;
1110 Rect.bottom = pAllocData->SurfDesc.height;
1111
1112 VBOXVDMAPIPE_RECTS RectInfo;
1113 RectInfo.ContextRect = Rect;
1114 RectInfo.UpdateRects.cRects = 1;
1115 RectInfo.UpdateRects.aRects[0] = Rect;
1116
1117 return vboxVdmaProcessVReg(pDevExt, &CrPacker, u32CrConClientID,
1118 pAllocData, pAllocData,
1119 &Rect, &RectInfo);
1120}
1121
1122static NTSTATUS vboxVdmaProcessVRegCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext,
1123 const VBOXWDDM_DMA_ALLOCINFO *pSrcAllocInfo,
1124 const VBOXWDDM_DMA_ALLOCINFO *pDstAllocInfo,
1125 const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects)
1126{
1127 return vboxVdmaProcessVReg(pDevExt, &pContext->CrPacker, pContext->u32CrConClientID,
1128 &pSrcAllocInfo->pAlloc->AllocData, &pDstAllocInfo->pAlloc->AllocData,
1129 pSrcRect, pDstRects);
1130}
1131
1132static void vboxVdmaBltDirtyRectsUpdate(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, uint32_t cRects, const RECT *paRects)
1133{
1134 if (!cRects)
1135 {
1136 WARN(("vboxVdmaBltDirtyRectsUpdate: no rects specified"));
1137 return;
1138 }
1139
1140 RECT rect;
1141 rect = paRects[0];
1142 for (UINT i = 1; i < cRects; ++i)
1143 {
1144 vboxWddmRectUnited(&rect, &rect, &paRects[i]);
1145 }
1146
1147 uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled);
1148 if (!cUnlockedVBVADisabled)
1149 {
1150 VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &rect);
1151 }
1152 else
1153 {
1154 VBOXVBVA_OP_WITHLOCK_ATDPC(ReportDirtyRect, pDevExt, pSource, &rect);
1155 }
1156}
1157
1158NTSTATUS vboxVdmaProcessBltCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_BLT *pBlt)
1159{
1160 NTSTATUS Status = STATUS_SUCCESS;
1161 PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc;
1162 PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc;
1163 BOOLEAN fRenderFromSharedDisabled = pDevExt->fRenderToShadowDisabled;
1164 BOOLEAN fVRAMUpdated = FALSE;
1165
1166 if (!pDstAlloc->AllocData.hostID && !pSrcAlloc->AllocData.hostID)
1167 {
1168 /* the allocations contain a real data in VRAM, do blitting */
1169 vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt);
1170 fVRAMUpdated = TRUE;
1171 }
1172
1173 if (VBOXWDDM_IS_REAL_FB_ALLOCATION(pDevExt, pDstAlloc)
1174 && pDstAlloc->bVisible)
1175 {
1176 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId];
1177 Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS);
1178 Assert(pSource->pPrimaryAllocation == pDstAlloc);
1179
1180
1181 if (fVRAMUpdated)
1182 vboxVdmaBltDirtyRectsUpdate(pDevExt, pSource, pBlt->Blt.DstRects.UpdateRects.cRects, pBlt->Blt.DstRects.UpdateRects.aRects);
1183
1184 if (pSrcAlloc->AllocData.hostID || pSource->fHas3DVrs)
1185 {
1186 Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pBlt->Blt.SrcAlloc, &pBlt->Blt.DstAlloc, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects);
1187 if (!NT_SUCCESS(Status))
1188 WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status));
1189 }
1190 }
1191
1192 return Status;
1193}
1194
1195NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip)
1196{
1197 NTSTATUS Status = STATUS_SUCCESS;
1198 PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc;
1199 VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId];
1200 vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId);
1201 if (pAlloc->AllocData.hostID)
1202 {
1203 RECT SrcRect;
1204 VBOXVDMAPIPE_RECTS Rects;
1205 SrcRect.left = 0;
1206 SrcRect.top = 0;
1207 SrcRect.right = pAlloc->AllocData.SurfDesc.width;
1208 SrcRect.bottom = pAlloc->AllocData.SurfDesc.height;
1209 Rects.ContextRect.left = 0;
1210 Rects.ContextRect.top = 0;
1211 Rects.ContextRect.right = pAlloc->AllocData.SurfDesc.width;
1212 Rects.ContextRect.bottom = pAlloc->AllocData.SurfDesc.height;
1213 Rects.UpdateRects.cRects = 1;
1214 Rects.UpdateRects.aRects[0] = Rects.ContextRect;
1215
1216 Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pFlip->Flip.Alloc, &pFlip->Flip.Alloc, &SrcRect, &Rects);
1217 if (!NT_SUCCESS(Status))
1218 WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status));
1219 }
1220 else
1221 WARN(("unexpected flip request"));
1222
1223 return Status;
1224}
1225
1226NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF)
1227{
1228 NTSTATUS Status = STATUS_SUCCESS;
1229 PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc;
1230
1231 if (!pAlloc->AllocData.hostID)
1232 {
1233 Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill);
1234 if (!NT_SUCCESS(Status))
1235 WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status));
1236 }
1237 else
1238 WARN(("unexpected clrfill request"));
1239
1240 return Status;
1241}
1242
1243
1244#ifdef VBOX_WITH_VDMA
1245/*
1246 * This is currently used by VDMA. It is invisible for Vdma API clients since
1247 * Vdma transport may change if we choose to use another (e.g. more light-weight)
1248 * transport for DMA commands submission
1249 */
1250
1251#ifdef VBOXVDMA_WITH_VBVA
1252static int vboxWddmVdmaSubmitVbva(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1253{
1254 int rc;
1255 if (vboxVbvaBufferBeginUpdate (pDevExt, &pDevExt->u.primary.Vbva))
1256 {
1257 rc = vboxVbvaReportCmdOffset(pDevExt, &pDevExt->u.primary.Vbva, offDr);
1258 vboxVbvaBufferEndUpdate (pDevExt, &pDevExt->u.primary.Vbva);
1259 }
1260 else
1261 {
1262 AssertBreakpoint();
1263 rc = VERR_INVALID_STATE;
1264 }
1265 return rc;
1266}
1267#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitVbva
1268#else
1269static int vboxWddmVdmaSubmitHgsmi(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, HGSMIOFFSET offDr)
1270{
1271 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offDr);
1272 return VINF_SUCCESS;
1273}
1274#define vboxWddmVdmaSubmit vboxWddmVdmaSubmitHgsmi
1275#endif
1276
1277static int vboxVdmaInformHost(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, VBOXVDMA_CTL_TYPE enmCtl)
1278{
1279 int rc = VINF_SUCCESS;
1280
1281 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1282 if (pCmd)
1283 {
1284 pCmd->enmCtl = enmCtl;
1285 pCmd->u32Offset = pInfo->CmdHeap.Heap.area.offBase;
1286 pCmd->i32Result = VERR_NOT_SUPPORTED;
1287
1288 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1289 Assert(pHdr);
1290 if (pHdr)
1291 {
1292 do
1293 {
1294 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1295 Assert(offCmd != HGSMIOFFSET_VOID);
1296 if (offCmd != HGSMIOFFSET_VOID)
1297 {
1298 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1299 AssertRC(rc);
1300 if (RT_SUCCESS(rc))
1301 {
1302 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1303 AssertRC(rc);
1304 if (RT_SUCCESS(rc))
1305 {
1306 rc = pCmd->i32Result;
1307 AssertRC(rc);
1308 }
1309 break;
1310 }
1311 }
1312 else
1313 rc = VERR_INVALID_PARAMETER;
1314 /* fail to submit, cancel it */
1315 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1316 } while (0);
1317 }
1318
1319 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1320 }
1321 else
1322 {
1323 LOGREL(("HGSMIHeapAlloc failed"));
1324 rc = VERR_OUT_OF_RESOURCES;
1325 }
1326
1327 return rc;
1328}
1329#endif
1330
1331/* create a DMACommand buffer */
1332int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo
1333#ifdef VBOX_WITH_VDMA
1334 , ULONG offBuffer, ULONG cbBuffer
1335#endif
1336 )
1337{
1338 int rc;
1339 pInfo->fEnabled = FALSE;
1340
1341#ifdef VBOX_WITH_VDMA
1342 Assert((offBuffer & 0xfff) == 0);
1343 Assert((cbBuffer & 0xfff) == 0);
1344 Assert(offBuffer);
1345 Assert(cbBuffer);
1346
1347 if((offBuffer & 0xfff)
1348 || (cbBuffer & 0xfff)
1349 || !offBuffer
1350 || !cbBuffer)
1351 {
1352 LOGREL(("invalid parameters: offBuffer(0x%x), cbBuffer(0x%x)", offBuffer, cbBuffer));
1353 return VERR_INVALID_PARAMETER;
1354 }
1355 PVOID pvBuffer;
1356
1357 rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt),
1358 &pvBuffer,
1359 offBuffer,
1360 cbBuffer);
1361 Assert(RT_SUCCESS(rc));
1362 if (RT_SUCCESS(rc))
1363 {
1364 /* Setup a HGSMI heap within the adapter information area. */
1365 rc = VBoxSHGSMIInit(&pInfo->CmdHeap,
1366 pvBuffer,
1367 cbBuffer,
1368 offBuffer,
1369 false /*fOffsetBased*/);
1370 Assert(RT_SUCCESS(rc));
1371 if(RT_SUCCESS(rc))
1372#endif
1373 {
1374 return VINF_SUCCESS;
1375 }
1376#ifdef VBOX_WITH_VDMA
1377 else
1378 LOGREL(("HGSMIHeapSetup failed rc = 0x%x", rc));
1379
1380 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), &pvBuffer);
1381 }
1382 else
1383 LOGREL(("VBoxMapAdapterMemory failed rc = 0x%x\n", rc));
1384#endif
1385 return rc;
1386}
1387
1388int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1389{
1390 Assert(pInfo->fEnabled);
1391 if (!pInfo->fEnabled)
1392 return VINF_ALREADY_INITIALIZED;
1393
1394 /* ensure nothing else is submitted */
1395 pInfo->fEnabled = FALSE;
1396#ifdef VBOX_WITH_VDMA
1397 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_DISABLE);
1398 AssertRC(rc);
1399 return rc;
1400#else
1401 return VINF_SUCCESS;
1402#endif
1403}
1404
1405int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1406{
1407 Assert(!pInfo->fEnabled);
1408 if (pInfo->fEnabled)
1409 return VINF_ALREADY_INITIALIZED;
1410#ifdef VBOX_WITH_VDMA
1411 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_ENABLE);
1412 Assert(RT_SUCCESS(rc));
1413 if (RT_SUCCESS(rc))
1414 pInfo->fEnabled = TRUE;
1415
1416 return rc;
1417#else
1418 return VINF_SUCCESS;
1419#endif
1420}
1421
1422#ifdef VBOX_WITH_VDMA
1423int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1424{
1425 Assert(pInfo->fEnabled);
1426 if (!pInfo->fEnabled)
1427 return VINF_ALREADY_INITIALIZED;
1428
1429 int rc = vboxVdmaInformHost (pDevExt, pInfo, VBOXVDMA_CTL_TYPE_FLUSH);
1430 Assert(RT_SUCCESS(rc));
1431
1432 return rc;
1433}
1434#endif
1435
1436int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo)
1437{
1438 int rc = VINF_SUCCESS;
1439 Assert(!pInfo->fEnabled);
1440 if (pInfo->fEnabled)
1441 rc = vboxVdmaDisable (pDevExt, pInfo);
1442#ifdef VBOX_WITH_VDMA
1443 VBoxSHGSMITerm(&pInfo->CmdHeap);
1444 VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base);
1445#endif
1446 return rc;
1447}
1448
1449#ifdef VBOX_WITH_VDMA
1450void vboxVdmaCBufDrFree (PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1451{
1452 VBoxSHGSMICommandFree (&pInfo->CmdHeap, pDr);
1453}
1454
1455PVBOXVDMACBUF_DR vboxVdmaCBufDrCreate (PVBOXVDMAINFO pInfo, uint32_t cbTrailingData)
1456{
1457 uint32_t cbDr = VBOXVDMACBUF_DR_SIZE(cbTrailingData);
1458 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)VBoxSHGSMICommandAlloc (&pInfo->CmdHeap, cbDr, HGSMI_CH_VBVA, VBVA_VDMA_CMD);
1459 Assert(pDr);
1460 if (pDr)
1461 memset (pDr, 0, cbDr);
1462 else
1463 LOGREL(("VBoxSHGSMICommandAlloc returned NULL"));
1464
1465 return pDr;
1466}
1467
1468static DECLCALLBACK(void) vboxVdmaCBufDrCompletion(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext)
1469{
1470 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1471 PVBOXVDMAINFO pInfo = &pDevExt->u.primary.Vdma;
1472
1473 vboxVdmaCBufDrFree (pInfo, (PVBOXVDMACBUF_DR)pvCmd);
1474}
1475
1476static DECLCALLBACK(void) vboxVdmaCBufDrCompletionIrq(PVBOXSHGSMI pHeap, void *pvCmd, void *pvContext,
1477 PFNVBOXSHGSMICMDCOMPLETION *ppfnCompletion, void **ppvCompletion)
1478{
1479 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1480 PVBOXVDMAINFO pVdma = &pDevExt->u.primary.Vdma;
1481 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvCmd;
1482
1483 DXGK_INTERRUPT_TYPE enmComplType;
1484
1485 if (RT_SUCCESS(pDr->rc))
1486 {
1487 enmComplType = DXGK_INTERRUPT_DMA_COMPLETED;
1488 }
1489 else if (pDr->rc == VERR_INTERRUPTED)
1490 {
1491 Assert(0);
1492 enmComplType = DXGK_INTERRUPT_DMA_PREEMPTED;
1493 }
1494 else
1495 {
1496 Assert(0);
1497 enmComplType = DXGK_INTERRUPT_DMA_FAULTED;
1498 }
1499
1500 if (vboxVdmaDdiCmdCompletedIrq(pDevExt, VBOXVDMADDI_CMD_FROM_BUF_DR(pDr), enmComplType))
1501 {
1502 pDevExt->bNotifyDxDpc = TRUE;
1503 }
1504
1505 /* inform SHGSMI we DO NOT want to be called at DPC later */
1506 *ppfnCompletion = NULL;
1507// *ppvCompletion = pvContext;
1508}
1509
1510int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1511{
1512 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq (&pInfo->CmdHeap, pDr, vboxVdmaCBufDrCompletionIrq, pDevExt, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE);
1513 Assert(pHdr);
1514 int rc = VERR_GENERAL_FAILURE;
1515 if (pHdr)
1516 {
1517 do
1518 {
1519 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1520 Assert(offCmd != HGSMIOFFSET_VOID);
1521 if (offCmd != HGSMIOFFSET_VOID)
1522 {
1523 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1524 AssertRC(rc);
1525 if (RT_SUCCESS(rc))
1526 {
1527 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1528 AssertRC(rc);
1529 break;
1530 }
1531 }
1532 else
1533 rc = VERR_INVALID_PARAMETER;
1534 /* fail to submit, cancel it */
1535 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1536 } while (0);
1537 }
1538 else
1539 rc = VERR_INVALID_PARAMETER;
1540 return rc;
1541}
1542
1543int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr)
1544{
1545 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynch (&pInfo->CmdHeap, pDr, NULL, NULL, VBOXSHGSMI_FLAG_GH_SYNCH);
1546 Assert(pHdr);
1547 int rc = VERR_GENERAL_FAILURE;
1548 if (pHdr)
1549 {
1550 do
1551 {
1552 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pInfo->CmdHeap, pHdr);
1553 Assert(offCmd != HGSMIOFFSET_VOID);
1554 if (offCmd != HGSMIOFFSET_VOID)
1555 {
1556 rc = vboxWddmVdmaSubmit(pDevExt, pInfo, offCmd);
1557 AssertRC(rc);
1558 if (RT_SUCCESS(rc))
1559 {
1560 VBoxSHGSMICommandDoneAsynch(&pInfo->CmdHeap, pHdr);
1561 AssertRC(rc);
1562 break;
1563 }
1564 }
1565 else
1566 rc = VERR_INVALID_PARAMETER;
1567 /* fail to submit, cancel it */
1568 VBoxSHGSMICommandCancelAsynch(&pInfo->CmdHeap, pHdr);
1569 } while (0);
1570 }
1571 else
1572 rc = VERR_INVALID_PARAMETER;
1573 return rc;
1574}
1575#endif
1576
1577
1578/* ddi dma command queue */
1579
1580VOID vboxVdmaDdiCmdGetCompletedListIsr(PVBOXMP_DEVEXT pDevExt, LIST_ENTRY *pList)
1581{
1582 vboxVideoLeDetach(&pDevExt->DpcCmdQueue, pList);
1583}
1584
1585BOOLEAN vboxVdmaDdiCmdIsCompletedListEmptyIsr(PVBOXMP_DEVEXT pDevExt)
1586{
1587 return IsListEmpty(&pDevExt->DpcCmdQueue);
1588}
1589
1590DECLINLINE(BOOLEAN) vboxVdmaDdiCmdCanComplete(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal)
1591{
1592 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[u32NodeOrdinal].CmdQueue;
1593 return ASMAtomicUoReadU32(&pQueue->cQueuedCmds) == 0;
1594}
1595
1596DECLCALLBACK(VOID) vboxVdmaDdiCmdCompletionCbFree(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1597{
1598 vboxWddmMemFree(pCmd);
1599}
1600
1601static VOID vboxVdmaDdiCmdNotifyCompletedIrq(PVBOXMP_DEVEXT pDevExt, UINT u32NodeOrdinal, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1602{
1603 PVBOXVDMADDI_NODE pNode = &pDevExt->aNodes[u32NodeOrdinal];
1604 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1605 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1606 switch (enmComplType)
1607 {
1608 case DXGK_INTERRUPT_DMA_COMPLETED:
1609 notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED;
1610 notify.DmaCompleted.SubmissionFenceId = u32FenceId;
1611 notify.DmaCompleted.NodeOrdinal = u32NodeOrdinal;
1612 pNode->uLastCompletedFenceId = u32FenceId;
1613 break;
1614
1615 case DXGK_INTERRUPT_DMA_PREEMPTED:
1616 Assert(0);
1617 notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED;
1618 notify.DmaPreempted.PreemptionFenceId = u32FenceId;
1619 notify.DmaPreempted.NodeOrdinal = u32NodeOrdinal;
1620 notify.DmaPreempted.LastCompletedFenceId = pNode->uLastCompletedFenceId;
1621 break;
1622
1623 case DXGK_INTERRUPT_DMA_FAULTED:
1624 Assert(0);
1625 notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED;
1626 notify.DmaFaulted.FaultedFenceId = u32FenceId;
1627 notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */
1628 notify.DmaFaulted.NodeOrdinal = u32NodeOrdinal;
1629 break;
1630
1631 default:
1632 Assert(0);
1633 break;
1634 }
1635
1636 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1637}
1638
1639static VOID vboxVdmaDdiCmdProcessCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1640{
1641 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pCmd->u32NodeOrdinal, pCmd->u32FenceId, enmComplType);
1642 switch (enmComplType)
1643 {
1644 case DXGK_INTERRUPT_DMA_COMPLETED:
1645 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1646 break;
1647 default:
1648 AssertFailed();
1649 break;
1650 }
1651}
1652
1653DECLINLINE(VOID) vboxVdmaDdiCmdDequeueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1654{
1655 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1656 ASMAtomicDecU32(&pQueue->cQueuedCmds);
1657 RemoveEntryList(&pCmd->QueueEntry);
1658}
1659
1660DECLINLINE(VOID) vboxVdmaDdiCmdEnqueueIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1661{
1662 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1663 ASMAtomicIncU32(&pQueue->cQueuedCmds);
1664 InsertTailList(&pQueue->CmdQueue, &pCmd->QueueEntry);
1665}
1666
1667VOID vboxVdmaDdiNodesInit(PVBOXMP_DEVEXT pDevExt)
1668{
1669 for (UINT i = 0; i < RT_ELEMENTS(pDevExt->aNodes); ++i)
1670 {
1671 pDevExt->aNodes[i].uLastCompletedFenceId = 0;
1672 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[i].CmdQueue;
1673 pQueue->cQueuedCmds = 0;
1674 InitializeListHead(&pQueue->CmdQueue);
1675 }
1676 InitializeListHead(&pDevExt->DpcCmdQueue);
1677}
1678
1679BOOLEAN vboxVdmaDdiCmdCompletedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1680{
1681 if (VBOXVDMADDI_STATE_NOT_DX_CMD == pCmd->enmState)
1682 {
1683 InsertTailList(&pDevExt->DpcCmdQueue, &pCmd->QueueEntry);
1684 return FALSE;
1685 }
1686
1687 PVBOXVDMADDI_CMD_QUEUE pQueue = &pDevExt->aNodes[pCmd->u32NodeOrdinal].CmdQueue;
1688 BOOLEAN bQueued = pCmd->enmState > VBOXVDMADDI_STATE_NOT_QUEUED;
1689 BOOLEAN bComplete = FALSE;
1690 Assert(!bQueued || pQueue->cQueuedCmds);
1691 Assert(!bQueued || !IsListEmpty(&pQueue->CmdQueue));
1692 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1693 if (bQueued)
1694 {
1695 if (pQueue->CmdQueue.Flink == &pCmd->QueueEntry)
1696 {
1697 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1698 bComplete = TRUE;
1699 }
1700 }
1701 else if (IsListEmpty(&pQueue->CmdQueue))
1702 {
1703 bComplete = TRUE;
1704 }
1705 else
1706 {
1707 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1708 }
1709
1710 if (bComplete)
1711 {
1712 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, enmComplType);
1713
1714 while (!IsListEmpty(&pQueue->CmdQueue))
1715 {
1716 pCmd = VBOXVDMADDI_CMD_FROM_ENTRY(pQueue->CmdQueue.Flink);
1717 if (pCmd->enmState == VBOXVDMADDI_STATE_COMPLETED)
1718 {
1719 vboxVdmaDdiCmdDequeueIrq(pDevExt, pCmd);
1720 vboxVdmaDdiCmdProcessCompletedIrq(pDevExt, pCmd, pCmd->enmComplType);
1721 }
1722 else
1723 break;
1724 }
1725 }
1726 else
1727 {
1728 pCmd->enmState = VBOXVDMADDI_STATE_COMPLETED;
1729 pCmd->enmComplType = enmComplType;
1730 }
1731
1732 return bComplete;
1733}
1734
1735VOID vboxVdmaDdiCmdSubmittedIrq(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1736{
1737 BOOLEAN bQueued = pCmd->enmState >= VBOXVDMADDI_STATE_PENDING;
1738 Assert(pCmd->enmState < VBOXVDMADDI_STATE_SUBMITTED);
1739 pCmd->enmState = VBOXVDMADDI_STATE_SUBMITTED;
1740 if (!bQueued)
1741 vboxVdmaDdiCmdEnqueueIrq(pDevExt, pCmd);
1742}
1743
1744typedef struct VBOXVDMADDI_CMD_COMPLETED_CB
1745{
1746 PVBOXMP_DEVEXT pDevExt;
1747 PVBOXVDMADDI_CMD pCmd;
1748 DXGK_INTERRUPT_TYPE enmComplType;
1749} VBOXVDMADDI_CMD_COMPLETED_CB, *PVBOXVDMADDI_CMD_COMPLETED_CB;
1750
1751static BOOLEAN vboxVdmaDdiCmdCompletedCb(PVOID Context)
1752{
1753 PVBOXVDMADDI_CMD_COMPLETED_CB pdc = (PVBOXVDMADDI_CMD_COMPLETED_CB)Context;
1754 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1755 BOOLEAN bNeedDpc = vboxVdmaDdiCmdCompletedIrq(pDevExt, pdc->pCmd, pdc->enmComplType);
1756 pDevExt->bNotifyDxDpc |= bNeedDpc;
1757
1758 if (bNeedDpc)
1759 {
1760 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1761 }
1762
1763 return bNeedDpc;
1764}
1765
1766NTSTATUS vboxVdmaDdiCmdCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, DXGK_INTERRUPT_TYPE enmComplType)
1767{
1768 VBOXVDMADDI_CMD_COMPLETED_CB context;
1769 context.pDevExt = pDevExt;
1770 context.pCmd = pCmd;
1771 context.enmComplType = enmComplType;
1772 BOOLEAN bNeedDps;
1773 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1774 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1775 vboxVdmaDdiCmdCompletedCb,
1776 &context,
1777 0, /* IN ULONG MessageNumber */
1778 &bNeedDps);
1779 Assert(Status == STATUS_SUCCESS);
1780 return Status;
1781}
1782
1783typedef struct VBOXVDMADDI_CMD_SUBMITTED_CB
1784{
1785 PVBOXMP_DEVEXT pDevExt;
1786 PVBOXVDMADDI_CMD pCmd;
1787} VBOXVDMADDI_CMD_SUBMITTED_CB, *PVBOXVDMADDI_CMD_SUBMITTED_CB;
1788
1789static BOOLEAN vboxVdmaDdiCmdSubmittedCb(PVOID Context)
1790{
1791 PVBOXVDMADDI_CMD_SUBMITTED_CB pdc = (PVBOXVDMADDI_CMD_SUBMITTED_CB)Context;
1792 vboxVdmaDdiCmdSubmittedIrq(pdc->pDevExt, pdc->pCmd);
1793
1794 return FALSE;
1795}
1796
1797NTSTATUS vboxVdmaDdiCmdSubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd)
1798{
1799 VBOXVDMADDI_CMD_SUBMITTED_CB context;
1800 context.pDevExt = pDevExt;
1801 context.pCmd = pCmd;
1802 BOOLEAN bRc;
1803 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1804 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1805 vboxVdmaDdiCmdSubmittedCb,
1806 &context,
1807 0, /* IN ULONG MessageNumber */
1808 &bRc);
1809 Assert(Status == STATUS_SUCCESS);
1810 return Status;
1811}
1812
1813typedef struct VBOXVDMADDI_CMD_COMPLETE_CB
1814{
1815 PVBOXMP_DEVEXT pDevExt;
1816 UINT u32NodeOrdinal;
1817 uint32_t u32FenceId;
1818} VBOXVDMADDI_CMD_COMPLETE_CB, *PVBOXVDMADDI_CMD_COMPLETE_CB;
1819
1820static BOOLEAN vboxVdmaDdiCmdFenceCompleteCb(PVOID Context)
1821{
1822 PVBOXVDMADDI_CMD_COMPLETE_CB pdc = (PVBOXVDMADDI_CMD_COMPLETE_CB)Context;
1823 PVBOXMP_DEVEXT pDevExt = pdc->pDevExt;
1824
1825 vboxVdmaDdiCmdNotifyCompletedIrq(pDevExt, pdc->u32NodeOrdinal, pdc->u32FenceId, DXGK_INTERRUPT_DMA_COMPLETED);
1826
1827 pDevExt->bNotifyDxDpc = TRUE;
1828 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1829
1830 return TRUE;
1831}
1832
1833static NTSTATUS vboxVdmaDdiCmdFenceNotifyComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId)
1834{
1835 VBOXVDMADDI_CMD_COMPLETE_CB context;
1836 context.pDevExt = pDevExt;
1837 context.u32NodeOrdinal = u32NodeOrdinal;
1838 context.u32FenceId = u32FenceId;
1839 BOOLEAN bRet;
1840 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1841 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1842 vboxVdmaDdiCmdFenceCompleteCb,
1843 &context,
1844 0, /* IN ULONG MessageNumber */
1845 &bRet);
1846 Assert(Status == STATUS_SUCCESS);
1847 return Status;
1848}
1849
1850NTSTATUS vboxVdmaDdiCmdFenceComplete(PVBOXMP_DEVEXT pDevExt, uint32_t u32NodeOrdinal, uint32_t u32FenceId, DXGK_INTERRUPT_TYPE enmComplType)
1851{
1852 if (vboxVdmaDdiCmdCanComplete(pDevExt, u32NodeOrdinal))
1853 return vboxVdmaDdiCmdFenceNotifyComplete(pDevExt, u32NodeOrdinal, u32FenceId);
1854
1855 PVBOXVDMADDI_CMD pCmd = (PVBOXVDMADDI_CMD)vboxWddmMemAlloc(sizeof (VBOXVDMADDI_CMD));
1856 Assert(pCmd);
1857 if (pCmd)
1858 {
1859 vboxVdmaDdiCmdInit(pCmd, u32NodeOrdinal, u32FenceId, vboxVdmaDdiCmdCompletionCbFree, NULL);
1860 NTSTATUS Status = vboxVdmaDdiCmdCompleted(pDevExt, pCmd, enmComplType);
1861 Assert(Status == STATUS_SUCCESS);
1862 if (Status == STATUS_SUCCESS)
1863 return STATUS_SUCCESS;
1864 vboxWddmMemFree(pCmd);
1865 return Status;
1866 }
1867 return STATUS_NO_MEMORY;
1868}
1869
1870#ifdef VBOXWDDM_RENDER_FROM_SHADOW
1871NTSTATUS vboxVdmaHlpUpdatePrimary(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT* pRect)
1872{
1873 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1874 Assert(pSource->pPrimaryAllocation);
1875 Assert(pSource->pShadowAllocation);
1876 if (!pSource->pPrimaryAllocation)
1877 return STATUS_INVALID_PARAMETER;
1878 if (!pSource->pShadowAllocation)
1879 return STATUS_INVALID_PARAMETER;
1880
1881 Assert(pSource->pPrimaryAllocation->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID);
1882 Assert(pSource->pShadowAllocation->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID);
1883 if (pSource->pPrimaryAllocation->AllocData.Addr.offVram == VBOXVIDEOOFFSET_VOID)
1884 return STATUS_INVALID_PARAMETER;
1885 if (pSource->pShadowAllocation->AllocData.Addr.offVram == VBOXVIDEOOFFSET_VOID)
1886 return STATUS_INVALID_PARAMETER;
1887
1888 NTSTATUS Status = vboxVdmaGgDmaBltPerform(pDevExt, &pSource->pShadowAllocation->AllocData, pRect, &pSource->pPrimaryAllocation->AllocData, pRect);
1889 Assert(Status == STATUS_SUCCESS);
1890 return Status;
1891}
1892#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