VirtualBox

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

Last change on this file since 63057 was 63057, checked in by vboxsync, 9 years ago

GA/NT/Graphics: warnings

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