VirtualBox

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

Last change on this file since 69500 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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