VirtualBox

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

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

(C) 2016

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