VirtualBox

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

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