VirtualBox

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

Last change on this file since 106505 was 106061, checked in by vboxsync, 8 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.6 KB
Line 
1/* $Id: VBoxMPVhwa.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "VBoxMPWddm.h"
29#include "VBoxMPVhwa.h"
30
31#include <iprt/semaphore.h>
32#include <iprt/asm.h>
33
34#define VBOXVHWA_PRIMARY_ALLOCATION(_pSrc) ((_pSrc)->pPrimaryAllocation)
35
36#define VBOXVHWA_COPY_RECT(a_pDst, a_pSrc) do { \
37 (a_pDst)->left = (a_pSrc)->left; \
38 (a_pDst)->top = (a_pSrc)->top; \
39 (a_pDst)->right = (a_pSrc)->right; \
40 (a_pDst)->bottom = (a_pSrc)->bottom; \
41 } while(0)
42
43
44DECLINLINE(void) vboxVhwaHdrInit(VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pHdr,
45 D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId, VBOXVHWACMD_TYPE enmCmd)
46{
47 memset((void *)pHdr, 0, sizeof(VBOXVHWACMD));
48 pHdr->iDisplay = srcId;
49 pHdr->rc = VERR_GENERAL_FAILURE;
50 pHdr->enmCmd = enmCmd;
51 pHdr->cRefs = 1;
52}
53
54DECLINLINE(void) vbvaVhwaCommandRelease(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
55{
56 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
57 Assert(cRefs < UINT32_MAX / 2);
58 if(!cRefs)
59 {
60 VBoxHGSMIBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pCmd);
61 }
62}
63
64DECLINLINE(void) vbvaVhwaCommandRetain(VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
65{
66 ASMAtomicIncU32(&pCmd->cRefs);
67}
68
69/* do not wait for completion */
70void vboxVhwaCommandSubmitAsynch(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd,
71 PFNVBOXVHWACMDCOMPLETION pfnCompletion, void *pContext)
72{
73 pCmd->GuestVBVAReserved1 = (uintptr_t)pfnCompletion;
74 pCmd->GuestVBVAReserved2 = (uintptr_t)pContext;
75 vbvaVhwaCommandRetain(pCmd);
76
77 VBoxHGSMIBufferSubmit(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pCmd);
78
79 uint32_t const fFlags = pCmd->Flags;
80 if( !(fFlags & VBOXVHWACMD_FLAG_HG_ASYNCH)
81 || ( (fFlags & VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION)
82 && (fFlags & VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED) ) )
83 {
84 /* the command is completed */
85 pfnCompletion(pDevExt, pCmd, pContext);
86 }
87
88 vbvaVhwaCommandRelease(pDevExt, pCmd);
89}
90
91/** @callback_method_impl{FNVBOXVHWACMDCOMPLETION} */
92static DECLCALLBACK(void)
93vboxVhwaCompletionSetEvent(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd, void *pvContext)
94{
95 RT_NOREF(pDevExt, pCmd);
96 RTSemEventSignal((RTSEMEVENT)pvContext);
97}
98
99void vboxVhwaCommandSubmitAsynchByEvent(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd, RTSEMEVENT hEvent)
100{
101 vboxVhwaCommandSubmitAsynch(pDevExt, pCmd, vboxVhwaCompletionSetEvent, hEvent);
102}
103
104void vboxVhwaCommandCheckCompletion(PVBOXMP_DEVEXT pDevExt)
105{
106 NTSTATUS Status = vboxWddmCallIsr(pDevExt);
107 AssertNtStatusSuccess(Status);
108}
109
110VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *vboxVhwaCommandCreate(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId,
111 VBOXVHWACMD_TYPE enmCmd, VBOXVHWACMD_LENGTH cbCmd)
112{
113 vboxVhwaCommandCheckCompletion(pDevExt);
114 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pHdr;
115 pHdr = (VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx,
116 cbCmd + VBOXVHWACMD_HEADSIZE(),
117 HGSMI_CH_VBVA,
118 VBVA_VHWA_CMD);
119 Assert(pHdr);
120 if (!pHdr)
121 LOGREL(("VBoxHGSMIBufferAlloc failed"));
122 else
123 vboxVhwaHdrInit(pHdr, srcId, enmCmd);
124
125 return pHdr;
126}
127
128void vboxVhwaCommandFree(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
129{
130 vbvaVhwaCommandRelease(pDevExt, pCmd);
131}
132
133int vboxVhwaCommandSubmit(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
134{
135 RTSEMEVENT hEvent;
136 int rc = RTSemEventCreate(&hEvent);
137 AssertRC(rc);
138 if (RT_SUCCESS(rc))
139 {
140 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ;
141 vboxVhwaCommandSubmitAsynchByEvent(pDevExt, pCmd, hEvent);
142 rc = RTSemEventWait(hEvent, RT_INDEFINITE_WAIT);
143 AssertRC(rc);
144 if (RT_SUCCESS(rc))
145 RTSemEventDestroy(hEvent);
146 }
147 return rc;
148}
149
150/** @callback_method_impl{FNVBOXVHWACMDCOMPLETION} */
151static DECLCALLBACK(void)
152vboxVhwaCompletionFreeCmd(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd, void *pvContext)
153{
154 RT_NOREF(pvContext);
155 vboxVhwaCommandFree(pDevExt, pCmd);
156}
157
158void vboxVhwaCompletionListProcess(PVBOXMP_DEVEXT pDevExt, VBOXVTLIST *pList)
159{
160 PVBOXVTLIST_ENTRY pNext, pCur;
161 for (pCur = pList->pFirst; pCur; pCur = pNext)
162 {
163 /* need to save next since the command may be released in a pfnCallback and thus its data might be invalid */
164 pNext = pCur->pNext;
165 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = VBOXVHWA_LISTENTRY2CMD(pCur);
166 PFNVBOXVHWACMDCOMPLETION pfnCallback = (PFNVBOXVHWACMDCOMPLETION)pCmd->GuestVBVAReserved1;
167 void *pvCallback = (void*)pCmd->GuestVBVAReserved2;
168 pfnCallback(pDevExt, pCmd, pvCallback);
169 }
170}
171
172
173void vboxVhwaCommandSubmitAsynchAndComplete(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd)
174{
175 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION;
176
177 vboxVhwaCommandSubmitAsynch(pDevExt, pCmd, vboxVhwaCompletionFreeCmd, NULL);
178}
179
180static void vboxVhwaFreeHostInfo1(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD_QUERYINFO1 RT_UNTRUSTED_VOLATILE_HOST *pInfo)
181{
182 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = VBOXVHWACMD_HEAD(pInfo);
183 vboxVhwaCommandFree(pDevExt, pCmd);
184}
185
186static void vboxVhwaFreeHostInfo2(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD_QUERYINFO2 RT_UNTRUSTED_VOLATILE_HOST *pInfo)
187{
188 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = VBOXVHWACMD_HEAD(pInfo);
189 vboxVhwaCommandFree(pDevExt, pCmd);
190}
191
192static VBOXVHWACMD_QUERYINFO1 RT_UNTRUSTED_VOLATILE_HOST *
193vboxVhwaQueryHostInfo1(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
194{
195 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, srcId, VBOXVHWACMD_TYPE_QUERY_INFO1,
196 sizeof(VBOXVHWACMD_QUERYINFO1));
197 AssertReturnStmt(pCmd, LOGREL(("vboxVhwaCommandCreate failed")), NULL);
198
199 VBOXVHWACMD_QUERYINFO1 RT_UNTRUSTED_VOLATILE_HOST *pInfo1 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
200 pInfo1->u.in.guestVersion.maj = VBOXVHWA_VERSION_MAJ;
201 pInfo1->u.in.guestVersion.min = VBOXVHWA_VERSION_MIN;
202 pInfo1->u.in.guestVersion.bld = VBOXVHWA_VERSION_BLD;
203 pInfo1->u.in.guestVersion.reserved = VBOXVHWA_VERSION_RSV;
204
205 int rc = vboxVhwaCommandSubmit(pDevExt, pCmd);
206 AssertRC(rc);
207 if (RT_SUCCESS(rc))
208 if (RT_SUCCESS(pCmd->rc))
209 return VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
210
211 vboxVhwaCommandFree(pDevExt, pCmd);
212 return NULL;
213}
214
215static VBOXVHWACMD_QUERYINFO2 RT_UNTRUSTED_VOLATILE_HOST *
216vboxVhwaQueryHostInfo2(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId, uint32_t numFourCC)
217{
218 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, srcId, VBOXVHWACMD_TYPE_QUERY_INFO2,
219 VBOXVHWAINFO2_SIZE(numFourCC));
220 AssertReturnStmt(pCmd, LOGREL(("vboxVhwaCommandCreate failed")), NULL);
221
222 VBOXVHWACMD_QUERYINFO2 RT_UNTRUSTED_VOLATILE_HOST *pInfo2 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO2);
223 pInfo2->numFourCC = numFourCC;
224
225 int rc = vboxVhwaCommandSubmit(pDevExt, pCmd);
226 AssertRC(rc);
227 if (RT_SUCCESS(rc))
228 {
229 AssertRC(pCmd->rc);
230 if(RT_SUCCESS(pCmd->rc))
231 if(pInfo2->numFourCC == numFourCC)
232 return pInfo2;
233 }
234
235 vboxVhwaCommandFree(pDevExt, pCmd);
236 return NULL;
237}
238
239int vboxVhwaEnable(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
240{
241 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, srcId, VBOXVHWACMD_TYPE_ENABLE, 0);
242 AssertReturnStmt(pCmd, LOGREL(("vboxVhwaCommandCreate failed")), VERR_GENERAL_FAILURE);
243
244 int rc = vboxVhwaCommandSubmit(pDevExt, pCmd);
245 AssertRC(rc);
246 if(RT_SUCCESS(rc))
247 {
248 AssertRC(pCmd->rc);
249 if(RT_SUCCESS(pCmd->rc))
250 rc = VINF_SUCCESS;
251 else
252 rc = pCmd->rc;
253 }
254
255 vboxVhwaCommandFree(pDevExt, pCmd);
256 return rc;
257}
258
259int vboxVhwaDisable(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
260{
261 vboxVhwaCommandCheckCompletion(pDevExt);
262
263 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, srcId, VBOXVHWACMD_TYPE_DISABLE, 0);
264 AssertReturnStmt(pCmd, LOGREL(("vboxVhwaCommandCreate failed")), VERR_GENERAL_FAILURE);
265
266 int rc = vboxVhwaCommandSubmit(pDevExt, pCmd);
267 AssertRC(rc);
268 if (RT_SUCCESS(rc))
269 {
270 if(RT_SUCCESS(pCmd->rc))
271 rc = VINF_SUCCESS;
272 else
273 rc = pCmd->rc;
274 }
275
276 vboxVhwaCommandFree(pDevExt, pCmd);
277 return rc;
278}
279
280DECLINLINE(VOID) vboxVhwaHlpOverlayListInit(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
281{
282 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
283 pSource->cOverlays = 0;
284 InitializeListHead(&pSource->OverlayList);
285 KeInitializeSpinLock(&pSource->OverlayListLock);
286}
287
288static void vboxVhwaInitSrc(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
289{
290 Assert(srcId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
291 VBOXVHWA_INFO *pSettings = &pDevExt->aSources[srcId].Vhwa.Settings;
292 memset (pSettings, 0, sizeof (VBOXVHWA_INFO));
293
294 vboxVhwaHlpOverlayListInit(pDevExt, srcId);
295
296 VBOXVHWACMD_QUERYINFO1 RT_UNTRUSTED_VOLATILE_HOST *pInfo1 = vboxVhwaQueryHostInfo1(pDevExt, srcId);
297 if (pInfo1)
298 {
299 if ((pInfo1->u.out.cfgFlags & VBOXVHWA_CFG_ENABLED)
300 && pInfo1->u.out.numOverlays)
301 {
302 if ((pInfo1->u.out.caps & VBOXVHWA_CAPS_OVERLAY)
303 && (pInfo1->u.out.caps & VBOXVHWA_CAPS_OVERLAYSTRETCH)
304 && (pInfo1->u.out.surfaceCaps & VBOXVHWA_SCAPS_OVERLAY)
305 && (pInfo1->u.out.surfaceCaps & VBOXVHWA_SCAPS_FLIP)
306 && (pInfo1->u.out.surfaceCaps & VBOXVHWA_SCAPS_LOCALVIDMEM)
307 && pInfo1->u.out.numOverlays)
308 {
309 pSettings->fFlags |= VBOXVHWA_F_ENABLED;
310
311 if (pInfo1->u.out.caps & VBOXVHWA_CAPS_COLORKEY)
312 {
313 if (pInfo1->u.out.colorKeyCaps & VBOXVHWA_CKEYCAPS_SRCOVERLAY)
314 {
315 pSettings->fFlags |= VBOXVHWA_F_CKEY_SRC;
316 /** @todo VBOXVHWA_CKEYCAPS_SRCOVERLAYONEACTIVE ? */
317 }
318
319 if (pInfo1->u.out.colorKeyCaps & VBOXVHWA_CKEYCAPS_DESTOVERLAY)
320 {
321 pSettings->fFlags |= VBOXVHWA_F_CKEY_DST;
322 /** @todo VBOXVHWA_CKEYCAPS_DESTOVERLAYONEACTIVE ? */
323 }
324 }
325
326 pSettings->cOverlaysSupported = pInfo1->u.out.numOverlays;
327
328 pSettings->cFormats = 0;
329
330 pSettings->aFormats[pSettings->cFormats] = D3DDDIFMT_X8R8G8B8;
331 ++pSettings->cFormats;
332
333 if (pInfo1->u.out.numFourCC
334 && (pInfo1->u.out.caps & VBOXVHWA_CAPS_OVERLAYFOURCC))
335 {
336 VBOXVHWACMD_QUERYINFO2 RT_UNTRUSTED_VOLATILE_HOST *pInfo2 =
337 vboxVhwaQueryHostInfo2(pDevExt, srcId, pInfo1->u.out.numFourCC);
338 if (pInfo2)
339 {
340 for (uint32_t i = 0; i < pInfo2->numFourCC; ++i)
341 {
342 pSettings->aFormats[pSettings->cFormats] = (D3DDDIFORMAT)pInfo2->FourCC[i];
343 ++pSettings->cFormats;
344 }
345 vboxVhwaFreeHostInfo2(pDevExt, pInfo2);
346 }
347 }
348 }
349 }
350 vboxVhwaFreeHostInfo1(pDevExt, pInfo1);
351 }
352}
353
354void vboxVhwaInit(PVBOXMP_DEVEXT pDevExt)
355{
356 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
357 {
358 vboxVhwaInitSrc(pDevExt, (D3DDDI_VIDEO_PRESENT_SOURCE_ID)i);
359 }
360}
361
362void vboxVhwaFree(PVBOXMP_DEVEXT pDevExt)
363{
364 /* we do not allocate/map anything, just issue a Disable command
365 * to ensure all pending commands are flushed */
366 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
367 {
368 vboxVhwaDisable(pDevExt, i);
369 }
370}
371
372static int vboxVhwaHlpTranslateFormat(VBOXVHWA_PIXELFORMAT RT_UNTRUSTED_VOLATILE_HOST *pFormat, D3DDDIFORMAT enmFormat)
373{
374 pFormat->Reserved = 0;
375 switch (enmFormat)
376 {
377 case D3DDDIFMT_A8R8G8B8:
378 case D3DDDIFMT_X8R8G8B8:
379 pFormat->flags = VBOXVHWA_PF_RGB;
380 pFormat->c.rgbBitCount = 32;
381 pFormat->m1.rgbRBitMask = 0xff0000;
382 pFormat->m2.rgbGBitMask = 0xff00;
383 pFormat->m3.rgbBBitMask = 0xff;
384 /* always zero for now */
385 pFormat->m4.rgbABitMask = 0;
386 return VINF_SUCCESS;
387 case D3DDDIFMT_R8G8B8:
388 pFormat->flags = VBOXVHWA_PF_RGB;
389 pFormat->c.rgbBitCount = 24;
390 pFormat->m1.rgbRBitMask = 0xff0000;
391 pFormat->m2.rgbGBitMask = 0xff00;
392 pFormat->m3.rgbBBitMask = 0xff;
393 /* always zero for now */
394 pFormat->m4.rgbABitMask = 0;
395 return VINF_SUCCESS;
396 case D3DDDIFMT_R5G6B5:
397 pFormat->flags = VBOXVHWA_PF_RGB;
398 pFormat->c.rgbBitCount = 16;
399 pFormat->m1.rgbRBitMask = 0xf800;
400 pFormat->m2.rgbGBitMask = 0x7e0;
401 pFormat->m3.rgbBBitMask = 0x1f;
402 /* always zero for now */
403 pFormat->m4.rgbABitMask = 0;
404 return VINF_SUCCESS;
405 case D3DDDIFMT_P8:
406 case D3DDDIFMT_A8:
407 case D3DDDIFMT_X1R5G5B5:
408 case D3DDDIFMT_A1R5G5B5:
409 case D3DDDIFMT_A4R4G4B4:
410 case D3DDDIFMT_R3G3B2:
411 case D3DDDIFMT_A8R3G3B2:
412 case D3DDDIFMT_X4R4G4B4:
413 case D3DDDIFMT_A2B10G10R10:
414 case D3DDDIFMT_A8B8G8R8:
415 case D3DDDIFMT_X8B8G8R8:
416 case D3DDDIFMT_G16R16:
417 case D3DDDIFMT_A2R10G10B10:
418 case D3DDDIFMT_A16B16G16R16:
419 case D3DDDIFMT_A8P8:
420 default:
421 {
422 uint32_t fourcc = vboxWddmFormatToFourcc(enmFormat);
423 Assert(fourcc);
424 if (fourcc)
425 {
426 pFormat->flags = VBOXVHWA_PF_FOURCC;
427 pFormat->fourCC = fourcc;
428 return VINF_SUCCESS;
429 }
430 return VERR_NOT_SUPPORTED;
431 }
432 }
433}
434
435int vboxVhwaHlpDestroySurface(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSurf,
436 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
437{
438 Assert(pSurf->hHostHandle);
439 if (!pSurf->hHostHandle)
440 return VERR_INVALID_STATE;
441
442 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, VidPnSourceId, VBOXVHWACMD_TYPE_SURF_DESTROY,
443 sizeof(VBOXVHWACMD_SURF_DESTROY));
444 Assert(pCmd);
445 if (pCmd)
446 {
447 VBOXVHWACMD_SURF_DESTROY RT_UNTRUSTED_VOLATILE_HOST *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_DESTROY);
448
449 memset((void *)pBody, 0, sizeof(VBOXVHWACMD_SURF_DESTROY));
450
451 pBody->u.in.hSurf = pSurf->hHostHandle;
452
453 /* we're not interested in completion, just send the command */
454 vboxVhwaCommandSubmitAsynchAndComplete(pDevExt, pCmd);
455
456 pSurf->hHostHandle = VBOXVHWA_SURFHANDLE_INVALID;
457
458 return VINF_SUCCESS;
459 }
460
461 return VERR_OUT_OF_RESOURCES;
462}
463
464int vboxVhwaHlpPopulateSurInfo(VBOXVHWA_SURFACEDESC RT_UNTRUSTED_VOLATILE_HOST *pInfo, PVBOXWDDM_ALLOCATION pSurf,
465 uint32_t fFlags, uint32_t cBackBuffers, uint32_t fSCaps,
466 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
467{
468 RT_NOREF(VidPnSourceId);
469 memset((void *)pInfo, 0, sizeof(VBOXVHWA_SURFACEDESC));
470
471#if 0
472 /**
473 * The following breaks 2D accelerated video playback because this method is called just after the surface was created
474 * and most its members are still 0.
475 *
476 * @todo: Not 100% sure this is the correct way. It looks like the SegmentId specifies where the memory
477 * for the surface is stored (VRAM vs. system memory) but because this method is only used
478 * to query some parameters (using VBOXVHWACMD_SURF_GETINFO) and this command doesn't access any surface memory
479 * on the host it should be safe.
480 */
481 if (pSurf->AllocData.Addr.SegmentId != 1)
482 {
483 WARN(("invalid segment id!"));
484 return VERR_INVALID_PARAMETER;
485 }
486#endif
487
488 pInfo->height = pSurf->AllocData.SurfDesc.height;
489 pInfo->width = pSurf->AllocData.SurfDesc.width;
490 pInfo->flags |= VBOXVHWA_SD_HEIGHT | VBOXVHWA_SD_WIDTH;
491 if (fFlags & VBOXVHWA_SD_PITCH)
492 {
493 pInfo->pitch = pSurf->AllocData.SurfDesc.pitch;
494 pInfo->flags |= VBOXVHWA_SD_PITCH;
495 pInfo->sizeX = pSurf->AllocData.SurfDesc.cbSize;
496 pInfo->sizeY = 1;
497 }
498
499 if (cBackBuffers)
500 {
501 pInfo->cBackBuffers = cBackBuffers;
502 pInfo->flags |= VBOXVHWA_SD_BACKBUFFERCOUNT;
503 }
504 else
505 pInfo->cBackBuffers = 0;
506 pInfo->Reserved = 0;
507 /** @todo color keys */
508// pInfo->DstOverlayCK;
509// pInfo->DstBltCK;
510// pInfo->SrcOverlayCK;
511// pInfo->SrcBltCK;
512 int rc = vboxVhwaHlpTranslateFormat(&pInfo->PixelFormat, pSurf->AllocData.SurfDesc.format);
513 AssertRC(rc);
514 if (RT_SUCCESS(rc))
515 {
516 pInfo->flags |= VBOXVHWA_SD_PIXELFORMAT;
517 pInfo->surfCaps = fSCaps;
518 pInfo->flags |= VBOXVHWA_SD_CAPS;
519 pInfo->offSurface = pSurf->AllocData.Addr.offVram;
520 }
521
522 return rc;
523}
524
525int vboxVhwaHlpCheckApplySurfInfo(PVBOXWDDM_ALLOCATION pSurf, VBOXVHWA_SURFACEDESC RT_UNTRUSTED_VOLATILE_HOST *pInfo,
526 uint32_t fFlags, bool bApplyHostHandle)
527{
528 int rc = VINF_SUCCESS;
529 if (!(fFlags & VBOXVHWA_SD_PITCH))
530 {
531 /* should be set by host */
532// Assert(pInfo->flags & VBOXVHWA_SD_PITCH);
533 pSurf->AllocData.SurfDesc.cbSize = pInfo->sizeX * pInfo->sizeY;
534 Assert(pSurf->AllocData.SurfDesc.cbSize);
535 pSurf->AllocData.SurfDesc.pitch = pInfo->pitch;
536 Assert(pSurf->AllocData.SurfDesc.pitch);
537 /** @todo make this properly */
538 pSurf->AllocData.SurfDesc.bpp = pSurf->AllocData.SurfDesc.pitch * 8 / pSurf->AllocData.SurfDesc.width;
539 Assert(pSurf->AllocData.SurfDesc.bpp);
540 }
541 else
542 {
543 Assert(pSurf->AllocData.SurfDesc.cbSize == pInfo->sizeX);
544 Assert(pInfo->sizeY == 1);
545 Assert(pInfo->pitch == pSurf->AllocData.SurfDesc.pitch);
546 if (pSurf->AllocData.SurfDesc.cbSize != pInfo->sizeX
547 || pInfo->sizeY != 1
548 || pInfo->pitch != pSurf->AllocData.SurfDesc.pitch)
549 {
550 rc = VERR_INVALID_PARAMETER;
551 }
552 }
553
554 if (bApplyHostHandle && RT_SUCCESS(rc))
555 {
556 pSurf->hHostHandle = pInfo->hSurf;
557 }
558
559 return rc;
560}
561
562int vboxVhwaHlpCreateSurface(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSurf,
563 uint32_t fFlags, uint32_t cBackBuffers, uint32_t fSCaps,
564 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
565{
566 /* the first thing we need is to post create primary */
567 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, VidPnSourceId, VBOXVHWACMD_TYPE_SURF_CREATE,
568 sizeof(VBOXVHWACMD_SURF_CREATE));
569 Assert(pCmd);
570 if (pCmd)
571 {
572 VBOXVHWACMD_SURF_CREATE RT_UNTRUSTED_VOLATILE_HOST *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_CREATE);
573 int rc = VINF_SUCCESS;
574
575 memset((void *)pBody, 0, sizeof(VBOXVHWACMD_SURF_CREATE));
576
577 rc = vboxVhwaHlpPopulateSurInfo(&pBody->SurfInfo, pSurf, fFlags, cBackBuffers, fSCaps, VidPnSourceId);
578 AssertRC(rc);
579 if (RT_SUCCESS(rc))
580 {
581 vboxVhwaCommandSubmit(pDevExt, pCmd);
582 Assert(pCmd->rc == VINF_SUCCESS);
583 if(pCmd->rc == VINF_SUCCESS)
584 rc = vboxVhwaHlpCheckApplySurfInfo(pSurf, &pBody->SurfInfo, fFlags, true);
585 else
586 rc = pCmd->rc;
587 }
588 vboxVhwaCommandFree(pDevExt, pCmd);
589 return rc;
590 }
591
592 return VERR_OUT_OF_RESOURCES;
593}
594
595int vboxVhwaHlpGetSurfInfoForSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSurf, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
596{
597 /* the first thing we need is to post create primary */
598 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pDevExt, VidPnSourceId, VBOXVHWACMD_TYPE_SURF_GETINFO,
599 sizeof(VBOXVHWACMD_SURF_GETINFO));
600 Assert(pCmd);
601 if (pCmd)
602 {
603 VBOXVHWACMD_SURF_GETINFO RT_UNTRUSTED_VOLATILE_HOST *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_GETINFO);
604 int rc = VINF_SUCCESS;
605
606 memset((void *)pBody, 0, sizeof(VBOXVHWACMD_SURF_GETINFO));
607
608 rc = vboxVhwaHlpPopulateSurInfo(&pBody->SurfInfo, pSurf, 0, 0,
609 VBOXVHWA_SCAPS_OVERLAY | VBOXVHWA_SCAPS_VIDEOMEMORY
610 | VBOXVHWA_SCAPS_LOCALVIDMEM | VBOXVHWA_SCAPS_COMPLEX,
611 VidPnSourceId);
612 AssertRC(rc);
613 if (RT_SUCCESS(rc))
614 {
615 vboxVhwaCommandSubmit(pDevExt, pCmd);
616 Assert(pCmd->rc == VINF_SUCCESS);
617 if(pCmd->rc == VINF_SUCCESS)
618 rc = vboxVhwaHlpCheckApplySurfInfo(pSurf, &pBody->SurfInfo, 0, true);
619 else
620 rc = pCmd->rc;
621 }
622 vboxVhwaCommandFree(pDevExt, pCmd);
623 return rc;
624 }
625
626 return VERR_OUT_OF_RESOURCES;
627}
628
629int vboxVhwaHlpGetSurfInfo(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pSurf)
630{
631 for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
632 {
633 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i];
634 if (pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED)
635 {
636 int rc = vboxVhwaHlpGetSurfInfoForSource(pDevExt, pSurf, i);
637 AssertRC(rc);
638 return rc;
639 }
640 }
641 AssertBreakpoint();
642 return VERR_NOT_SUPPORTED;
643}
644
645int vboxVhwaHlpDestroyPrimary(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
646{
647 PVBOXWDDM_ALLOCATION pFbSurf = VBOXVHWA_PRIMARY_ALLOCATION(pSource);
648
649 int rc = vboxVhwaHlpDestroySurface(pDevExt, pFbSurf, VidPnSourceId);
650 AssertRC(rc);
651 return rc;
652}
653
654int vboxVhwaHlpCreatePrimary(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
655{
656 PVBOXWDDM_ALLOCATION pFbSurf = VBOXVHWA_PRIMARY_ALLOCATION(pSource);
657 Assert(pSource->Vhwa.cOverlaysCreated == 1);
658 Assert(pFbSurf->hHostHandle == VBOXVHWA_SURFHANDLE_INVALID);
659 if (pFbSurf->hHostHandle != VBOXVHWA_SURFHANDLE_INVALID)
660 return VERR_INVALID_STATE;
661
662 int rc = vboxVhwaHlpCreateSurface(pDevExt, pFbSurf,
663 VBOXVHWA_SD_PITCH, 0, VBOXVHWA_SCAPS_PRIMARYSURFACE | VBOXVHWA_SCAPS_VIDEOMEMORY | VBOXVHWA_SCAPS_LOCALVIDMEM,
664 VidPnSourceId);
665 AssertRC(rc);
666 return rc;
667}
668
669int vboxVhwaHlpCheckInit(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
670{
671 Assert(VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
672 if (VidPnSourceId >= (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
673 return VERR_INVALID_PARAMETER;
674
675 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
676
677 Assert(!!(pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED));
678 if (!(pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED))
679 return VERR_NOT_SUPPORTED;
680
681 int rc = VINF_SUCCESS;
682 /** @todo need a better sync */
683 uint32_t cNew = ASMAtomicIncU32(&pSource->Vhwa.cOverlaysCreated);
684 if (cNew == 1)
685 {
686 rc = vboxVhwaEnable(pDevExt, VidPnSourceId);
687 AssertRC(rc);
688 if (RT_SUCCESS(rc))
689 {
690 rc = vboxVhwaHlpCreatePrimary(pDevExt, pSource, VidPnSourceId);
691 AssertRC(rc);
692 if (RT_FAILURE(rc))
693 {
694 int tmpRc = vboxVhwaDisable(pDevExt, VidPnSourceId);
695 AssertRC(tmpRc);
696 }
697 }
698 }
699 else
700 {
701 PVBOXWDDM_ALLOCATION pFbSurf = VBOXVHWA_PRIMARY_ALLOCATION(pSource);
702 Assert(pFbSurf->hHostHandle);
703 if (pFbSurf->hHostHandle)
704 rc = VINF_ALREADY_INITIALIZED;
705 else
706 rc = VERR_INVALID_STATE;
707 }
708
709 if (RT_FAILURE(rc))
710 ASMAtomicDecU32(&pSource->Vhwa.cOverlaysCreated);
711
712 return rc;
713}
714
715int vboxVhwaHlpCheckTerm(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
716{
717 Assert(VidPnSourceId < (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays);
718 if (VidPnSourceId >= (D3DDDI_VIDEO_PRESENT_SOURCE_ID)VBoxCommonFromDeviceExt(pDevExt)->cDisplays)
719 return VERR_INVALID_PARAMETER;
720
721 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
722
723 Assert(!!(pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED));
724
725 /** @todo need a better sync */
726 uint32_t cNew = ASMAtomicDecU32(&pSource->Vhwa.cOverlaysCreated);
727 int rc = VINF_SUCCESS;
728 if (!cNew)
729 {
730 rc = vboxVhwaHlpDestroyPrimary(pDevExt, pSource, VidPnSourceId);
731 AssertRC(rc);
732 }
733 else
734 {
735 Assert(cNew < UINT32_MAX / 2);
736 }
737
738 return rc;
739}
740
741int vboxVhwaHlpOverlayFlip(PVBOXWDDM_OVERLAY pOverlay, const DXGKARG_FLIPOVERLAY *pFlipInfo)
742{
743 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pFlipInfo->hSource;
744 Assert(pAlloc->hHostHandle);
745 Assert(pAlloc->pResource);
746 Assert(pAlloc->pResource == pOverlay->pResource);
747 Assert(pFlipInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_OVERLAYFLIP_INFO));
748 Assert(pFlipInfo->pPrivateDriverData);
749 PVBOXWDDM_SOURCE pSource = &pOverlay->pDevExt->aSources[pOverlay->VidPnSourceId];
750 Assert(!!(pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED));
751 PVBOXWDDM_ALLOCATION pFbSurf = VBOXVHWA_PRIMARY_ALLOCATION(pSource);
752 Assert(pFbSurf);
753 Assert(pFbSurf->hHostHandle);
754 Assert(pFbSurf->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID);
755 Assert(pOverlay->pCurentAlloc);
756 Assert(pOverlay->pCurentAlloc->pResource == pOverlay->pResource);
757 Assert(pOverlay->pCurentAlloc != pAlloc);
758 int rc = VINF_SUCCESS;
759
760 if (pFbSurf->AllocData.Addr.SegmentId != 1)
761 {
762 WARN(("invalid segment id on flip"));
763 return VERR_INVALID_PARAMETER;
764 }
765
766 if (pFlipInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_OVERLAYFLIP_INFO))
767 {
768 PVBOXWDDM_OVERLAYFLIP_INFO pOurInfo = (PVBOXWDDM_OVERLAYFLIP_INFO)pFlipInfo->pPrivateDriverData;
769
770 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST *pCmd = vboxVhwaCommandCreate(pOverlay->pDevExt, pOverlay->VidPnSourceId,
771 VBOXVHWACMD_TYPE_SURF_FLIP,
772 sizeof(VBOXVHWACMD_SURF_FLIP));
773 Assert(pCmd);
774 if (pCmd)
775 {
776 VBOXVHWACMD_SURF_FLIP RT_UNTRUSTED_VOLATILE_HOST *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_FLIP);
777
778 memset((void *)pBody, 0, sizeof(VBOXVHWACMD_SURF_FLIP));
779
780// pBody->TargGuestSurfInfo;
781// pBody->CurrGuestSurfInfo;
782 pBody->u.in.hTargSurf = pAlloc->hHostHandle;
783 pBody->u.in.offTargSurface = pFlipInfo->SrcPhysicalAddress.QuadPart;
784 pAlloc->AllocData.Addr.offVram = pFlipInfo->SrcPhysicalAddress.QuadPart;
785 pBody->u.in.hCurrSurf = pOverlay->pCurentAlloc->hHostHandle;
786 pBody->u.in.offCurrSurface = pOverlay->pCurentAlloc->AllocData.Addr.offVram;
787 if (pOurInfo->DirtyRegion.fFlags & VBOXWDDM_DIRTYREGION_F_VALID)
788 {
789 pBody->u.in.xUpdatedTargMemValid = 1;
790 if (pOurInfo->DirtyRegion.fFlags & VBOXWDDM_DIRTYREGION_F_RECT_VALID)
791 VBOXVHWA_COPY_RECT(&pBody->u.in.xUpdatedTargMemRect, &pOurInfo->DirtyRegion.Rect);
792 else
793 {
794 pBody->u.in.xUpdatedTargMemRect.right = pAlloc->AllocData.SurfDesc.width;
795 pBody->u.in.xUpdatedTargMemRect.bottom = pAlloc->AllocData.SurfDesc.height;
796 /* top & left are zero-inited with the above memset */
797 }
798 }
799
800 /* we're not interested in completion, just send the command */
801 vboxVhwaCommandSubmitAsynchAndComplete(pOverlay->pDevExt, pCmd);
802
803 pOverlay->pCurentAlloc = pAlloc;
804
805 rc = VINF_SUCCESS;
806 }
807 else
808 rc = VERR_OUT_OF_RESOURCES;
809 }
810 else
811 rc = VERR_INVALID_PARAMETER;
812
813 return rc;
814}
815
816AssertCompile(sizeof (RECT) == sizeof (VBOXVHWA_RECTL));
817AssertCompile(RT_SIZEOFMEMB(RECT, left) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, left));
818AssertCompile(RT_SIZEOFMEMB(RECT, right) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, right));
819AssertCompile(RT_SIZEOFMEMB(RECT, top) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, top));
820AssertCompile(RT_SIZEOFMEMB(RECT, bottom) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, bottom));
821AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(VBOXVHWA_RECTL, left));
822AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(VBOXVHWA_RECTL, right));
823AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(VBOXVHWA_RECTL, top));
824AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(VBOXVHWA_RECTL, bottom));
825
826static void vboxVhwaHlpOverlayDstRectSet(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_OVERLAY pOverlay, const RECT *pRect)
827{
828 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pOverlay->VidPnSourceId];
829 KIRQL OldIrql;
830 KeAcquireSpinLock(&pSource->OverlayListLock, &OldIrql);
831 pOverlay->DstRect = *pRect;
832 KeReleaseSpinLock(&pSource->OverlayListLock, OldIrql);
833}
834
835static void vboxVhwaHlpOverlayListAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_OVERLAY pOverlay)
836{
837 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pOverlay->VidPnSourceId];
838 KIRQL OldIrql;
839 KeAcquireSpinLock(&pSource->OverlayListLock, &OldIrql);
840 ASMAtomicIncU32(&pSource->cOverlays);
841 InsertHeadList(&pSource->OverlayList, &pOverlay->ListEntry);
842 KeReleaseSpinLock(&pSource->OverlayListLock, OldIrql);
843}
844
845static void vboxVhwaHlpOverlayListRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_OVERLAY pOverlay)
846{
847 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pOverlay->VidPnSourceId];
848 KIRQL OldIrql;
849 KeAcquireSpinLock(&pSource->OverlayListLock, &OldIrql);
850 ASMAtomicDecU32(&pSource->cOverlays);
851 RemoveEntryList(&pOverlay->ListEntry);
852 KeReleaseSpinLock(&pSource->OverlayListLock, OldIrql);
853}
854
855AssertCompile(sizeof (RECT) == sizeof (VBOXVHWA_RECTL));
856AssertCompile(RT_SIZEOFMEMB(RECT, left) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, left));
857AssertCompile(RT_SIZEOFMEMB(RECT, right) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, right));
858AssertCompile(RT_SIZEOFMEMB(RECT, top) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, top));
859AssertCompile(RT_SIZEOFMEMB(RECT, bottom) == RT_SIZEOFMEMB(VBOXVHWA_RECTL, bottom));
860AssertCompile(RT_OFFSETOF(RECT, left) == RT_OFFSETOF(VBOXVHWA_RECTL, left));
861AssertCompile(RT_OFFSETOF(RECT, right) == RT_OFFSETOF(VBOXVHWA_RECTL, right));
862AssertCompile(RT_OFFSETOF(RECT, top) == RT_OFFSETOF(VBOXVHWA_RECTL, top));
863AssertCompile(RT_OFFSETOF(RECT, bottom) == RT_OFFSETOF(VBOXVHWA_RECTL, bottom));
864
865int vboxVhwaHlpOverlayUpdate(PVBOXWDDM_OVERLAY pOverlay, const DXGK_OVERLAYINFO *pOverlayInfo, RECT * pDstUpdateRect)
866{
867 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pOverlayInfo->hAllocation;
868 Assert(pAlloc->hHostHandle);
869 Assert(pAlloc->pResource);
870 Assert(pAlloc->pResource == pOverlay->pResource);
871 Assert(pOverlayInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_OVERLAY_INFO));
872 Assert(pOverlayInfo->pPrivateDriverData);
873 PVBOXWDDM_SOURCE pSource = &pOverlay->pDevExt->aSources[pOverlay->VidPnSourceId];
874 Assert(!!(pSource->Vhwa.Settings.fFlags & VBOXVHWA_F_ENABLED));
875 PVBOXWDDM_ALLOCATION pFbSurf = VBOXVHWA_PRIMARY_ALLOCATION(pSource);
876 Assert(pFbSurf);
877 Assert(pFbSurf->hHostHandle);
878 Assert(pFbSurf->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID);
879 int rc = VINF_SUCCESS;
880
881 if (pFbSurf->AllocData.Addr.SegmentId != 1)
882 {
883 WARN(("invalid segment id on overlay update"));
884 return VERR_INVALID_PARAMETER;
885 }
886
887 if (pOverlayInfo->PrivateDriverDataSize == sizeof (VBOXWDDM_OVERLAY_INFO))
888 {
889 PVBOXWDDM_OVERLAY_INFO pOurInfo = (PVBOXWDDM_OVERLAY_INFO)pOverlayInfo->pPrivateDriverData;
890
891 VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HOST * pCmd = vboxVhwaCommandCreate(pOverlay->pDevExt, pOverlay->VidPnSourceId,
892 VBOXVHWACMD_TYPE_SURF_OVERLAY_UPDATE,
893 sizeof(VBOXVHWACMD_SURF_OVERLAY_UPDATE));
894 Assert(pCmd);
895 if (pCmd)
896 {
897 VBOXVHWACMD_SURF_OVERLAY_UPDATE RT_UNTRUSTED_VOLATILE_HOST *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_OVERLAY_UPDATE);
898
899 memset((void *)pBody, 0, sizeof(VBOXVHWACMD_SURF_OVERLAY_UPDATE));
900
901 pBody->u.in.hDstSurf = pFbSurf->hHostHandle;
902 pBody->u.in.offDstSurface = pFbSurf->AllocData.Addr.offVram;
903 VBOXVHWA_COPY_RECT(&pBody->u.in.dstRect, &pOverlayInfo->DstRect);
904
905 pBody->u.in.hSrcSurf = pAlloc->hHostHandle;
906 pBody->u.in.offSrcSurface = pOverlayInfo->PhysicalAddress.QuadPart;
907 pAlloc->AllocData.Addr.offVram = pOverlayInfo->PhysicalAddress.QuadPart;
908 VBOXVHWA_COPY_RECT(&pBody->u.in.srcRect, &pOverlayInfo->SrcRect);
909
910 pBody->u.in.flags |= VBOXVHWA_OVER_SHOW;
911 if (pOurInfo->OverlayDesc.fFlags & VBOXWDDM_OVERLAY_F_CKEY_DST)
912 {
913 pBody->u.in.flags |= VBOXVHWA_OVER_KEYDESTOVERRIDE /* ?? VBOXVHWA_OVER_KEYDEST */;
914 pBody->u.in.desc.DstCK.high = pOurInfo->OverlayDesc.DstColorKeyHigh;
915 pBody->u.in.desc.DstCK.low = pOurInfo->OverlayDesc.DstColorKeyLow;
916 }
917
918 if (pOurInfo->OverlayDesc.fFlags & VBOXWDDM_OVERLAY_F_CKEY_SRC)
919 {
920 pBody->u.in.flags |= VBOXVHWA_OVER_KEYSRCOVERRIDE /* ?? VBOXVHWA_OVER_KEYSRC */;
921 pBody->u.in.desc.SrcCK.high = pOurInfo->OverlayDesc.SrcColorKeyHigh;
922 pBody->u.in.desc.SrcCK.low = pOurInfo->OverlayDesc.SrcColorKeyLow;
923 }
924
925 if (pOurInfo->DirtyRegion.fFlags & VBOXWDDM_DIRTYREGION_F_VALID)
926 {
927 pBody->u.in.xFlags |= VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_SRCMEMRECT;
928 if (pOurInfo->DirtyRegion.fFlags & VBOXWDDM_DIRTYREGION_F_RECT_VALID)
929 VBOXVHWA_COPY_RECT(&pBody->u.in.xUpdatedSrcMemRect, &pOurInfo->DirtyRegion.Rect);
930 else
931 {
932 pBody->u.in.xUpdatedSrcMemRect.right = pAlloc->AllocData.SurfDesc.width;
933 pBody->u.in.xUpdatedSrcMemRect.bottom = pAlloc->AllocData.SurfDesc.height;
934 /* top & left are zero-inited with the above memset */
935 }
936 }
937
938 if (pDstUpdateRect)
939 {
940 pBody->u.in.xFlags |= VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_DSTMEMRECT;
941 VBOXVHWA_COPY_RECT(&pBody->u.in.xUpdatedDstMemRect, pDstUpdateRect);
942 }
943
944 /* we're not interested in completion, just send the command */
945 vboxVhwaCommandSubmitAsynchAndComplete(pOverlay->pDevExt, pCmd);
946
947 pOverlay->pCurentAlloc = pAlloc;
948
949 vboxVhwaHlpOverlayDstRectSet(pOverlay->pDevExt, pOverlay, &pOverlayInfo->DstRect);
950
951 rc = VINF_SUCCESS;
952 }
953 else
954 rc = VERR_OUT_OF_RESOURCES;
955 }
956 else
957 rc = VERR_INVALID_PARAMETER;
958
959 return rc;
960}
961
962int vboxVhwaHlpOverlayUpdate(PVBOXWDDM_OVERLAY pOverlay, const DXGK_OVERLAYINFO *pOverlayInfo)
963{
964 return vboxVhwaHlpOverlayUpdate(pOverlay, pOverlayInfo, NULL);
965}
966
967int vboxVhwaHlpOverlayDestroy(PVBOXWDDM_OVERLAY pOverlay)
968{
969 int rc = VINF_SUCCESS;
970
971 vboxVhwaHlpOverlayListRemove(pOverlay->pDevExt, pOverlay);
972
973 for (uint32_t i = 0; i < pOverlay->pResource->cAllocations; ++i)
974 {
975 PVBOXWDDM_ALLOCATION pCurAlloc = &pOverlay->pResource->aAllocations[i];
976 rc = vboxVhwaHlpDestroySurface(pOverlay->pDevExt, pCurAlloc, pOverlay->VidPnSourceId);
977 AssertRC(rc);
978 }
979
980 if (RT_SUCCESS(rc))
981 {
982 int tmpRc = vboxVhwaHlpCheckTerm(pOverlay->pDevExt, pOverlay->VidPnSourceId);
983 AssertRC(tmpRc);
984 }
985
986 return rc;
987}
988
989
990int vboxVhwaHlpOverlayCreate(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, DXGK_OVERLAYINFO *pOverlayInfo,
991 /* OUT */ PVBOXWDDM_OVERLAY pOverlay)
992{
993 int rc = vboxVhwaHlpCheckInit(pDevExt, VidPnSourceId);
994 AssertRC(rc);
995 if (RT_SUCCESS(rc))
996 {
997 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pOverlayInfo->hAllocation;
998 PVBOXWDDM_RESOURCE pRc = pAlloc->pResource;
999 Assert(pRc);
1000 for (uint32_t i = 0; i < pRc->cAllocations; ++i)
1001 {
1002 PVBOXWDDM_ALLOCATION pCurAlloc = &pRc->aAllocations[i];
1003 rc = vboxVhwaHlpCreateSurface(pDevExt, pCurAlloc,
1004 0, pRc->cAllocations - 1, VBOXVHWA_SCAPS_OVERLAY | VBOXVHWA_SCAPS_VIDEOMEMORY | VBOXVHWA_SCAPS_LOCALVIDMEM | VBOXVHWA_SCAPS_COMPLEX,
1005 VidPnSourceId);
1006 AssertRC(rc);
1007 if (!RT_SUCCESS(rc))
1008 {
1009 int tmpRc;
1010 for (uint32_t j = 0; j < i; ++j)
1011 {
1012 PVBOXWDDM_ALLOCATION pDestroyAlloc = &pRc->aAllocations[j];
1013 tmpRc = vboxVhwaHlpDestroySurface(pDevExt, pDestroyAlloc, VidPnSourceId);
1014 AssertRC(tmpRc);
1015 }
1016 break;
1017 }
1018 }
1019
1020 if (RT_SUCCESS(rc))
1021 {
1022 pOverlay->pDevExt = pDevExt;
1023 pOverlay->pResource = pRc;
1024 pOverlay->VidPnSourceId = VidPnSourceId;
1025
1026 vboxVhwaHlpOverlayListAdd(pDevExt, pOverlay);
1027
1028 RECT DstRect;
1029 vboxVhwaHlpOverlayDstRectGet(pDevExt, pOverlay, &DstRect);
1030
1031 rc = vboxVhwaHlpOverlayUpdate(pOverlay, pOverlayInfo, DstRect.right ? &DstRect : NULL);
1032 if (!RT_SUCCESS(rc))
1033 {
1034 int tmpRc = vboxVhwaHlpOverlayDestroy(pOverlay);
1035 AssertRC(tmpRc);
1036 }
1037 }
1038
1039 if (RT_FAILURE(rc))
1040 {
1041 int tmpRc = vboxVhwaHlpCheckTerm(pDevExt, VidPnSourceId);
1042 AssertRC(tmpRc);
1043 AssertRC(rc);
1044 }
1045 }
1046
1047 return rc;
1048}
1049
1050BOOLEAN vboxVhwaHlpOverlayListIsEmpty(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
1051{
1052 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1053 return !ASMAtomicReadU32(&pSource->cOverlays);
1054}
1055
1056#define VBOXWDDM_OVERLAY_FROM_ENTRY(_pEntry) ((PVBOXWDDM_OVERLAY)(((uint8_t*)(_pEntry)) - RT_UOFFSETOF(VBOXWDDM_OVERLAY, ListEntry)))
1057
1058void vboxVhwaHlpOverlayDstRectUnion(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, RECT *pRect)
1059{
1060 if (vboxVhwaHlpOverlayListIsEmpty(pDevExt, VidPnSourceId))
1061 {
1062 memset(pRect, 0, sizeof (*pRect));
1063 return;
1064 }
1065
1066 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
1067 KIRQL OldIrql;
1068 KeAcquireSpinLock(&pSource->OverlayListLock, &OldIrql);
1069 if (pSource->cOverlays)
1070 {
1071 PVBOXWDDM_OVERLAY pOverlay = VBOXWDDM_OVERLAY_FROM_ENTRY(pSource->OverlayList.Flink);
1072 *pRect = pOverlay->DstRect;
1073 while (pOverlay->ListEntry.Flink != &pSource->OverlayList)
1074 {
1075 pOverlay = VBOXWDDM_OVERLAY_FROM_ENTRY(pOverlay->ListEntry.Flink);
1076 vboxWddmRectUnite(pRect, &pOverlay->DstRect);
1077 }
1078 }
1079 KeReleaseSpinLock(&pSource->OverlayListLock, OldIrql);
1080}
1081
1082void vboxVhwaHlpOverlayDstRectGet(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_OVERLAY pOverlay, RECT *pRect)
1083{
1084 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pOverlay->VidPnSourceId];
1085 KIRQL OldIrql;
1086 KeAcquireSpinLock(&pSource->OverlayListLock, &OldIrql);
1087 *pRect = pOverlay->DstRect;
1088 KeReleaseSpinLock(&pSource->OverlayListLock, OldIrql);
1089}
Note: See TracBrowser for help on using the repository browser.

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