VirtualBox

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

Last change on this file since 51361 was 51361, checked in by vboxsync, 11 years ago

wddm/crOpenGL: misc bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.5 KB
Line 
1/* $Id: VBoxMPMisc.cpp 51361 2014-05-22 21:29:44Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011-2013 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 <VBox/Hardware/VBoxVideoVBE.h>
21#include <stdio.h>
22
23/* simple handle -> value table API */
24NTSTATUS vboxWddmHTableCreate(PVBOXWDDM_HTABLE pTbl, uint32_t cSize)
25{
26 memset(pTbl, 0, sizeof (*pTbl));
27 pTbl->paData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cSize);
28 if (pTbl->paData)
29 {
30 pTbl->cSize = cSize;
31 return STATUS_SUCCESS;
32 }
33 return STATUS_NO_MEMORY;
34}
35
36VOID vboxWddmHTableDestroy(PVBOXWDDM_HTABLE pTbl)
37{
38 if (!pTbl->paData)
39 return;
40
41 vboxWddmMemFree(pTbl->paData);
42}
43
44DECLINLINE(VBOXWDDM_HANDLE) vboxWddmHTableIndex2Handle(uint32_t iIndex)
45{
46 return iIndex+1;
47}
48
49DECLINLINE(uint32_t) vboxWddmHTableHandle2Index(VBOXWDDM_HANDLE hHandle)
50{
51 return hHandle-1;
52}
53
54NTSTATUS vboxWddmHTableRealloc(PVBOXWDDM_HTABLE pTbl, uint32_t cNewSize)
55{
56 Assert(cNewSize > pTbl->cSize);
57 if (cNewSize > pTbl->cSize)
58 {
59 PVOID *pvNewData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cNewSize);
60 if (!pvNewData)
61 {
62 WARN(("vboxWddmMemAllocZero failed for size (%d)", sizeof (pTbl->paData[0]) * cNewSize));
63 return STATUS_NO_MEMORY;
64 }
65 memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize);
66 vboxWddmMemFree(pTbl->paData);
67 pTbl->iNext2Search = pTbl->cSize;
68 pTbl->cSize = cNewSize;
69 pTbl->paData = pvNewData;
70 return STATUS_SUCCESS;
71 }
72 else if (cNewSize >= pTbl->cData)
73 {
74 AssertFailed();
75 return STATUS_NOT_IMPLEMENTED;
76 }
77 return STATUS_INVALID_PARAMETER;
78
79}
80VBOXWDDM_HANDLE vboxWddmHTablePut(PVBOXWDDM_HTABLE pTbl, PVOID pvData)
81{
82 if (pTbl->cSize == pTbl->cData)
83 {
84 NTSTATUS Status = vboxWddmHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4));
85 Assert(Status == STATUS_SUCCESS);
86 if (Status != STATUS_SUCCESS)
87 return VBOXWDDM_HANDLE_INVALID;
88 }
89 for (UINT i = pTbl->iNext2Search; ; ++i, i %= pTbl->cSize)
90 {
91 Assert(i < pTbl->cSize);
92 if (!pTbl->paData[i])
93 {
94 pTbl->paData[i] = pvData;
95 ++pTbl->cData;
96 Assert(pTbl->cData <= pTbl->cSize);
97 ++pTbl->iNext2Search;
98 pTbl->iNext2Search %= pTbl->cSize;
99 return vboxWddmHTableIndex2Handle(i);
100 }
101 }
102 Assert(0);
103 return VBOXWDDM_HANDLE_INVALID;
104}
105
106PVOID vboxWddmHTableRemove(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
107{
108 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
109 Assert(iIndex < pTbl->cSize);
110 if (iIndex < pTbl->cSize)
111 {
112 PVOID pvData = pTbl->paData[iIndex];
113 pTbl->paData[iIndex] = NULL;
114 --pTbl->cData;
115 Assert(pTbl->cData <= pTbl->cSize);
116 pTbl->iNext2Search = iIndex;
117 return pvData;
118 }
119 return NULL;
120}
121
122PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
123{
124 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
125 Assert(iIndex < pTbl->cSize);
126 if (iIndex < pTbl->cSize)
127 return pTbl->paData[iIndex];
128 return NULL;
129}
130
131VOID vboxWddmHTableIterInit(PVBOXWDDM_HTABLE pTbl, PVBOXWDDM_HTABLE_ITERATOR pIter)
132{
133 pIter->pTbl = pTbl;
134 pIter->iCur = ~0UL;
135 pIter->cLeft = pTbl->cData;
136}
137
138BOOL vboxWddmHTableIterHasNext(PVBOXWDDM_HTABLE_ITERATOR pIter)
139{
140 return pIter->cLeft;
141}
142
143
144PVOID vboxWddmHTableIterNext(PVBOXWDDM_HTABLE_ITERATOR pIter, VBOXWDDM_HANDLE *phHandle)
145{
146 if (vboxWddmHTableIterHasNext(pIter))
147 {
148 for (uint32_t i = pIter->iCur+1; i < pIter->pTbl->cSize ; ++i)
149 {
150 if (pIter->pTbl->paData[i])
151 {
152 pIter->iCur = i;
153 --pIter->cLeft;
154 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(i);
155 Assert(hHandle);
156 if (phHandle)
157 *phHandle = hHandle;
158 return pIter->pTbl->paData[i];
159 }
160 }
161 }
162
163 Assert(!vboxWddmHTableIterHasNext(pIter));
164 if (phHandle)
165 *phHandle = VBOXWDDM_HANDLE_INVALID;
166 return NULL;
167}
168
169
170PVOID vboxWddmHTableIterRemoveCur(PVBOXWDDM_HTABLE_ITERATOR pIter)
171{
172 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(pIter->iCur);
173 Assert(hHandle);
174 if (hHandle)
175 {
176 PVOID pRet = vboxWddmHTableRemove(pIter->pTbl, hHandle);
177 Assert(pRet);
178 return pRet;
179 }
180 return NULL;
181}
182#ifdef VBOX_WITH_CROGL
183PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate(UINT w, UINT h)
184{
185 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmMemAllocZero(sizeof (VBOXWDDM_SWAPCHAIN));
186 Assert(pSwapchain);
187 if (pSwapchain)
188 {
189 InitializeListHead(&pSwapchain->AllocList);
190 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_INITIALIZED;
191 pSwapchain->cRefs = 1;
192 /* init to some invalid value so that the pos get submitted */
193 pSwapchain->Pos.x = pSwapchain->Pos.y = VBOXWDDM_INVALID_COORD;
194 pSwapchain->width = w;
195 pSwapchain->height = h;
196 VBoxVrListInit(&pSwapchain->VisibleRegions);
197 }
198 return pSwapchain;
199}
200
201DECLINLINE(BOOLEAN) vboxWddmSwapchainRetainLocked(PVBOXWDDM_SWAPCHAIN pSwapchain)
202{
203 if (pSwapchain->enmState == VBOXWDDM_OBJSTATE_TYPE_INITIALIZED)
204 {
205 ASMAtomicIncU32(&pSwapchain->cRefs);
206 return TRUE;
207 }
208 return FALSE;
209}
210
211BOOLEAN vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
212{
213 KIRQL OldIrql;
214 BOOLEAN bRc;
215 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
216 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
217 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
218 return bRc;
219}
220
221VOID vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain)
222{
223 const uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs);
224 Assert(cRefs < UINT32_MAX/2);
225 if (!cRefs)
226 {
227 VBoxVrListClear(&pSwapchain->VisibleRegions);
228 vboxWddmMemFree(pSwapchain);
229 }
230}
231
232PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAllocData(PVBOXMP_DEVEXT pDevExt, const struct VBOXWDDM_ALLOC_DATA *pAllocData)
233{
234 KIRQL OldIrql;
235 PVBOXWDDM_SWAPCHAIN pSwapchain;
236 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
237 pSwapchain = pAllocData->pSwapchain;
238 if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain))
239 pSwapchain = NULL;
240 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
241 return pSwapchain;
242}
243
244PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOCATION *pAlloc)
245{
246 return vboxWddmSwapchainRetainByAllocData(pDevExt, &pAlloc->AllocData);
247}
248
249VOID vboxWddmSwapchainAllocRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
250{
251 KIRQL OldIrql;
252 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
253 Assert(pAlloc->AllocData.pSwapchain == pSwapchain);
254 pAlloc->AllocData.pSwapchain = NULL;
255 RemoveEntryList(&pAlloc->SwapchainEntry);
256 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
257 vboxWddmSwapchainRelease(pSwapchain);
258}
259
260BOOLEAN vboxWddmSwapchainAllocAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
261{
262 KIRQL OldIrql;
263 BOOLEAN bRc;
264 Assert(!pAlloc->AllocData.pSwapchain);
265 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
266 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
267 if (bRc)
268 {
269 if (pAlloc->AllocData.pSwapchain)
270 {
271 RemoveEntryList(&pAlloc->SwapchainEntry);
272 }
273 InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry);
274 pAlloc->AllocData.pSwapchain = pSwapchain;
275 }
276 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
277 return bRc;
278}
279
280#define VBOXSCENTRY_2_ALLOC(_pE) ((PVBOXWDDM_ALLOCATION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, SwapchainEntry)))
281
282static VOID vboxWddmSwapchainAllocRemoveAllInternal(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, BOOLEAN bOnDestroy)
283{
284 KIRQL OldIrql;
285 UINT cRemoved = 0;
286 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
287 PLIST_ENTRY pEntry = pSwapchain->AllocList.Flink;
288 do
289 {
290 if (pEntry != &pSwapchain->AllocList)
291 {
292 PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry);
293 pEntry = pEntry->Flink;
294 Assert(pAlloc->AllocData.pSwapchain == pSwapchain);
295 pAlloc->AllocData.pSwapchain = NULL;
296 RemoveEntryList(&pAlloc->SwapchainEntry);
297 ++cRemoved;
298 }
299 else
300 break;
301 } while (1);
302
303 if (bOnDestroy)
304 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_TERMINATED;
305 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
306
307 for (UINT i = 0; i < cRemoved; ++i)
308 vboxWddmSwapchainRelease(pSwapchain);
309}
310
311VOID vboxWddmSwapchainAllocRemoveAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
312{
313 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, FALSE);
314}
315
316VOID vboxWddmSwapchainDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
317{
318 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE);
319
320 vboxWddmSwapchainRelease(pSwapchain);
321}
322
323static BOOLEAN vboxWddmSwapchainCtxAddLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
324{
325 if (vboxWddmSwapchainRetain(pDevExt, pSwapchain))
326 {
327 Assert(!pSwapchain->hSwapchainKm);
328 Assert(!pSwapchain->pContext);
329 pSwapchain->pContext = pContext;
330 pSwapchain->hSwapchainKm = vboxWddmHTablePut(&pContext->Swapchains, pSwapchain);
331 InsertHeadList(&pDevExt->SwapchainList3D, &pSwapchain->DevExtListEntry);
332 return TRUE;
333 }
334 return FALSE;
335}
336
337static VOID vboxWddmSwapchainCtxRemoveLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
338{
339 Assert(pSwapchain->hSwapchainKm);
340 Assert(pSwapchain->pContext);
341 void * pTst = vboxWddmHTableRemove(&pContext->Swapchains, pSwapchain->hSwapchainKm);
342 Assert(pTst == pSwapchain);
343 RemoveEntryList(&pSwapchain->DevExtListEntry);
344 pSwapchain->hSwapchainKm = NULL;
345 VBoxVrListClear(&pSwapchain->VisibleRegions);
346 vboxWddmSwapchainRelease(pSwapchain);
347}
348
349/* adds the given swapchain to the context's swapchain list
350 * @return true on success */
351BOOLEAN vboxWddmSwapchainCtxAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
352{
353 BOOLEAN bRc;
354 VBOXWDDM_CTXLOCK_DATA
355 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
356 bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
357 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
358 return bRc;
359}
360
361/* removes the given swapchain from the context's swapchain list
362 * */
363VOID vboxWddmSwapchainCtxRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
364{
365 VBOXWDDM_CTXLOCK_DATA
366 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
367 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
368 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
369}
370
371/* destroys all swapchains for the given context
372 * */
373VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
374{
375 VBOXWDDM_HTABLE_ITERATOR Iter;
376 VBOXWDDM_CTXLOCK_DATA
377 do
378 {
379 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
380 vboxWddmHTableIterInit(&pContext->Swapchains, &Iter);
381 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL);
382 if (!pSwapchain)
383 break;
384
385 /* yes, we can call remove locked even when using iterator */
386 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
387
388 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
389 /* we must not do vboxWddmSwapchainDestroy inside a context mutex */
390 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
391 /* start from the very beginning, we will quit the loop when no swapchains left */
392 } while (1);
393
394 /* no swapchains left, we exiteed the while loop via the "break", and we still owning the mutex */
395 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
396}
397
398/* process the swapchain info passed from user-mode display driver & synchronizes the driver state with it */
399NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize)
400{
401 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
402 {
403 WARN(("invalid cbSize1 %d", cbSize));
404 return STATUS_INVALID_PARAMETER;
405 }
406
407 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
408 {
409 return STATUS_INVALID_PARAMETER;
410 WARN(("invalid cbSize2 %d", cbSize));
411 }
412
413 if (!pSwapchainInfo->SwapchainInfo.winHostID)
414 {
415 WARN(("Zero winHostID specified!"));
416 return STATUS_INVALID_PARAMETER;
417 }
418
419 if (!pContext)
420 {
421 WARN(("vboxWddmSwapchainCtxEscape: no context specified"));
422 return STATUS_INVALID_PARAMETER;
423 }
424
425 PVBOXWDDM_SWAPCHAIN pSwapchain = NULL;
426 PVBOXWDDM_ALLOCATION *apAlloc = NULL;
427 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
428 NTSTATUS Status = STATUS_SUCCESS;
429 VBOXWDDM_CTXLOCK_DATA
430
431 do {
432 if (pSwapchainInfo->SwapchainInfo.cAllocs)
433 {
434 /* ensure we do not overflow the 32bit buffer size value */
435 if (VBOXWDDM_ARRAY_MAXELEMENTSU32(VBOXWDDM_ALLOCATION) < pSwapchainInfo->SwapchainInfo.cAllocs)
436 {
437 WARN(("number of allocations passed in too big (%d), max is (%d)", pSwapchainInfo->SwapchainInfo.cAllocs, VBOXWDDM_ARRAY_MAXELEMENTSU32(VBOXWDDM_ALLOCATION)));
438 Status = STATUS_INVALID_PARAMETER;
439 break;
440 }
441
442 apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
443 Assert(apAlloc);
444 if (!apAlloc)
445 {
446 Status = STATUS_NO_MEMORY;
447 break;
448 }
449 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
450 {
451 DXGKARGCB_GETHANDLEDATA GhData;
452 GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
453 GhData.Type = DXGK_HANDLE_ALLOCATION;
454 GhData.Flags.Value = 0;
455 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
456 Assert(pAlloc);
457 if (!pAlloc)
458 {
459 Status = STATUS_INVALID_PARAMETER;
460 break;
461 }
462 apAlloc[i] = pAlloc;
463 }
464
465 if (!NT_SUCCESS(Status))
466 break;
467 }
468
469 if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
470 {
471 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
472 pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
473 Assert(pSwapchain);
474 if (!pSwapchain)
475 {
476 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
477 Status = STATUS_INVALID_PARAMETER;
478 break;
479 }
480 Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
481 Assert(pSwapchain->pContext == pContext);
482 if (pSwapchain->pContext != pContext)
483 {
484 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
485 Status = STATUS_INVALID_PARAMETER;
486 break;
487 }
488 }
489 else if (pSwapchainInfo->SwapchainInfo.cAllocs)
490 {
491 pSwapchain = vboxWddmSwapchainCreate(apAlloc[0]->AllocData.SurfDesc.width, apAlloc[0]->AllocData.SurfDesc.height);
492 if (!pSwapchain)
493 {
494 Status = STATUS_NO_MEMORY;
495 break;
496 }
497
498 VBOXWDDM_CTXLOCK_LOCK(pDevExt);
499 BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
500 Assert(bRc);
501 }
502 else
503 {
504 Status = STATUS_INVALID_PARAMETER;
505 break;
506 }
507
508 /* do not zero up the view rect since it may still be valid */
509// memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
510 /* @todo: do we really need to zero this up here ? */
511 VBoxVrListClear(&pSwapchain->VisibleRegions);
512
513 vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);
514
515 if (pSwapchainInfo->SwapchainInfo.cAllocs)
516 {
517 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
518 {
519 vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
520 }
521 pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
522 if (pSwapchain->winHostID != pSwapchainInfo->SwapchainInfo.winHostID)
523 {
524 pSwapchain->fExposed = FALSE;
525 pSwapchain->winHostID = pSwapchainInfo->SwapchainInfo.winHostID;
526 }
527 }
528 else
529 {
530 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
531 }
532
533 VBOXWDDM_CTXLOCK_UNLOCK(pDevExt);
534
535 if (pSwapchainInfo->SwapchainInfo.cAllocs)
536 {
537 Assert(pSwapchain->pContext);
538 Assert(pSwapchain->hSwapchainKm);
539 pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
540 }
541 else
542 {
543 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
544 pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
545 }
546
547 Assert(Status == STATUS_SUCCESS);
548 } while (0);
549
550 /* cleanup */
551 if (apAlloc)
552 vboxWddmMemFree(apAlloc);
553
554 return Status;
555}
556
557NTSTATUS vboxWddmSwapchainCtxInit(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
558{
559 NTSTATUS Status = vboxWddmHTableCreate(&pContext->Swapchains, 4);
560 if (!NT_SUCCESS(Status))
561 {
562 WARN(("vboxWddmHTableCreate failes, Status (x%x)", Status));
563 return Status;
564 }
565
566 return STATUS_SUCCESS;
567}
568
569VOID vboxWddmSwapchainCtxTerm(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
570{
571 vboxWddmSwapchainCtxDestroyAll(pDevExt, pContext);
572 vboxWddmHTableDestroy(&pContext->Swapchains);
573}
574#endif
575NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
576{
577 WCHAR fallBackBuf[2];
578 PWCHAR pSuffix;
579 bool bFallback = false;
580
581 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
582 {
583 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
584 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
585 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
586 }
587 else
588 {
589 pSuffix = fallBackBuf;
590 cbBuf = sizeof (fallBackBuf);
591 bFallback = true;
592 }
593
594 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
595 DevicePropertyDriverKeyName,
596 cbBuf,
597 pSuffix,
598 &cbBuf);
599 if (Status == STATUS_SUCCESS && bFallback)
600 Status = STATUS_BUFFER_TOO_SMALL;
601 if (Status == STATUS_BUFFER_TOO_SMALL)
602 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
603
604 return Status;
605}
606
607NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
608 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
609{
610 NTSTATUS Status = STATUS_SUCCESS;
611 PWCHAR pSuffix;
612 bool bFallback = false;
613 const WCHAR* pKeyPrefix;
614 UINT cbKeyPrefix;
615 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
616 Assert(pVGuid);
617 if (!pVGuid)
618 return STATUS_UNSUCCESSFUL;
619
620 vboxWinVersion_t ver = VBoxQueryWinVersion();
621 if (ver == WINVISTA)
622 {
623 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
624 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
625 }
626 else
627 {
628 Assert(ver == WIN7 || ver == WIN8 || ver == WIN81);
629 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
630 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
631 }
632
633 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
634 if (cbBuf >= cbResult)
635 {
636 wcscpy(pBuf, pKeyPrefix);
637 pSuffix = pBuf + (cbKeyPrefix-2)/2;
638 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
639 pSuffix += pVGuid->Length/2;
640 pSuffix[0] = L'\\';
641 pSuffix += 1;
642 swprintf(pSuffix, L"%04d", VidPnSourceId);
643 }
644 else
645 {
646 Status = STATUS_BUFFER_TOO_SMALL;
647 }
648
649 *pcbResult = cbResult;
650
651 return Status;
652}
653
654NTSTATUS vboxWddmRegQueryVideoGuidString(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
655{
656 BOOLEAN fNewMethodSucceeded = FALSE;
657 HANDLE hKey = NULL;
658 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DEVICE, GENERIC_READ, &hKey);
659 if (NT_SUCCESS(Status))
660 {
661 struct
662 {
663 KEY_VALUE_PARTIAL_INFORMATION Info;
664 UCHAR Buf[1024]; /* should be enough */
665 } KeyData;
666 ULONG cbResult;
667 UNICODE_STRING RtlStr;
668 RtlInitUnicodeString(&RtlStr, L"VideoID");
669 Status = ZwQueryValueKey(hKey,
670 &RtlStr,
671 KeyValuePartialInformation,
672 &KeyData.Info,
673 sizeof(KeyData),
674 &cbResult);
675 if (NT_SUCCESS(Status))
676 {
677 if (KeyData.Info.Type == REG_SZ)
678 {
679 fNewMethodSucceeded = TRUE;
680 *pcbResult = KeyData.Info.DataLength + 2;
681 if (cbBuf >= KeyData.Info.DataLength)
682 {
683 memcpy(pBuf, KeyData.Info.Data, KeyData.Info.DataLength + 2);
684 Status = STATUS_SUCCESS;
685 }
686 else
687 Status = STATUS_BUFFER_TOO_SMALL;
688 }
689 }
690 else
691 {
692 WARN(("ZwQueryValueKey failed, Status 0x%x", Status));
693 }
694
695 NTSTATUS tmpStatus = ZwClose(hKey);
696 Assert(tmpStatus == STATUS_SUCCESS);
697 }
698 else
699 {
700 WARN(("IoOpenDeviceRegistryKey failed Status 0x%x", Status));
701 }
702
703 if (fNewMethodSucceeded)
704 return Status;
705 else
706 WARN(("failed to acquire the VideoID, falling back to the old impl"));
707
708 Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
709 Assert(Status == STATUS_SUCCESS);
710 if (Status == STATUS_SUCCESS)
711 {
712 struct
713 {
714 KEY_BASIC_INFORMATION Name;
715 WCHAR Buf[256];
716 } Buf;
717 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
718 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
719 ULONG ResultLength;
720 BOOL bFound = FALSE;
721 for (ULONG i = 0; !bFound; ++i)
722 {
723 RtlZeroMemory(&Buf, sizeof (Buf));
724 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
725 Assert(Status == STATUS_SUCCESS);
726 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
727 if (Status != STATUS_SUCCESS)
728 break;
729
730 HANDLE hSubKey;
731 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
732 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
733 pSubBuf += Buf.Name.NameLength/2;
734 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
735 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
736 Assert(Status == STATUS_SUCCESS);
737 if (Status == STATUS_SUCCESS)
738 {
739 struct
740 {
741 KEY_VALUE_PARTIAL_INFORMATION Info;
742 UCHAR Buf[sizeof (VBOX_WDDM_DRIVERNAME)]; /* should be enough */
743 } KeyData;
744 ULONG cbResult;
745 UNICODE_STRING RtlStr;
746 RtlInitUnicodeString(&RtlStr, L"Service");
747 Status = ZwQueryValueKey(hSubKey,
748 &RtlStr,
749 KeyValuePartialInformation,
750 &KeyData.Info,
751 sizeof(KeyData),
752 &cbResult);
753 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
754 if (Status == STATUS_SUCCESS)
755 {
756 if (KeyData.Info.Type == REG_SZ)
757 {
758 if (KeyData.Info.DataLength == sizeof (VBOX_WDDM_DRIVERNAME))
759 {
760 if (!wcscmp(VBOX_WDDM_DRIVERNAME, (PWCHAR)KeyData.Info.Data))
761 {
762 bFound = TRUE;
763 *pcbResult = Buf.Name.NameLength + 2;
764 if (cbBuf >= Buf.Name.NameLength + 2)
765 {
766 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
767 }
768 else
769 {
770 Status = STATUS_BUFFER_TOO_SMALL;
771 }
772 }
773 }
774 }
775 }
776
777 NTSTATUS tmpStatus = ZwClose(hSubKey);
778 Assert(tmpStatus == STATUS_SUCCESS);
779 }
780 else
781 break;
782 }
783 NTSTATUS tmpStatus = ZwClose(hKey);
784 Assert(tmpStatus == STATUS_SUCCESS);
785 }
786
787 return Status;
788}
789
790NTSTATUS vboxWddmRegOpenKeyEx(OUT PHANDLE phKey, IN HANDLE hRootKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
791{
792 OBJECT_ATTRIBUTES ObjAttr;
793 UNICODE_STRING RtlStr;
794
795 RtlInitUnicodeString(&RtlStr, pName);
796 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hRootKey, NULL);
797
798 return ZwOpenKey(phKey, fAccess, &ObjAttr);
799}
800
801NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
802{
803 return vboxWddmRegOpenKeyEx(phKey, NULL, pName, fAccess);
804}
805
806NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey)
807{
808 WCHAR Buf[512];
809 ULONG cbBuf = sizeof(Buf);
810 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDeviceExtension, VidPnSourceId, cbBuf, Buf, &cbBuf);
811 Assert(Status == STATUS_SUCCESS);
812 if (Status == STATUS_SUCCESS)
813 {
814 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
815 Assert(Status == STATUS_SUCCESS);
816 if(Status == STATUS_SUCCESS)
817 return STATUS_SUCCESS;
818 }
819
820 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
821 * basically needed to make as less modifications to the current XPDM code as possible */
822 *phKey = NULL;
823
824 return Status;
825}
826
827NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
828{
829 DWORD dwVal;
830 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
831 Assert(Status == STATUS_SUCCESS);
832 if (Status == STATUS_SUCCESS)
833 {
834 *pResult = (int)dwVal;
835 }
836
837 return Status;
838}
839
840NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
841{
842 DWORD dwVal;
843 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
844 Assert(Status == STATUS_SUCCESS);
845 if (Status == STATUS_SUCCESS)
846 {
847 *pResult = (int)dwVal;
848 }
849
850 return Status;
851}
852
853NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
854{
855 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
856 HANDLE hKey;
857 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDeviceExtension, VidPnSourceId, &hKey);
858 Assert(Status == STATUS_SUCCESS);
859 if (Status == STATUS_SUCCESS)
860 {
861 int x, y;
862 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
863 Assert(Status == STATUS_SUCCESS);
864 if (Status == STATUS_SUCCESS)
865 {
866 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
867 Assert(Status == STATUS_SUCCESS);
868 if (Status == STATUS_SUCCESS)
869 {
870 pPos->x = x;
871 pPos->y = y;
872 }
873 }
874 NTSTATUS tmpStatus = ZwClose(hKey);
875 Assert(tmpStatus == STATUS_SUCCESS);
876 }
877
878 return Status;
879}
880
881NTSTATUS vboxWddmRegDrvFlagsSet(PVBOXMP_DEVEXT pDevExt, DWORD fVal)
882{
883 HANDLE hKey = NULL;
884 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
885 if (!NT_SUCCESS(Status))
886 {
887 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
888 return Status;
889 }
890
891 Status = vboxWddmRegSetValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, fVal);
892 if (!NT_SUCCESS(Status))
893 WARN(("vboxWddmRegSetValueDword failed, Status = 0x%x", Status));
894
895 NTSTATUS tmpStatus = ZwClose(hKey);
896 Assert(tmpStatus == STATUS_SUCCESS);
897
898 return Status;
899}
900
901DWORD vboxWddmRegDrvFlagsGet(PVBOXMP_DEVEXT pDevExt, DWORD fDefault)
902{
903 HANDLE hKey = NULL;
904 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey);
905 if (!NT_SUCCESS(Status))
906 {
907 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
908 return fDefault;
909 }
910
911 DWORD dwVal = 0;
912 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal);
913 if (!NT_SUCCESS(Status))
914 {
915 WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
916 dwVal = fDefault;
917 }
918
919 NTSTATUS tmpStatus = ZwClose(hKey);
920 Assert(tmpStatus == STATUS_SUCCESS);
921
922 return dwVal;
923}
924
925NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
926{
927 struct
928 {
929 KEY_VALUE_PARTIAL_INFORMATION Info;
930 UCHAR Buf[32]; /* should be enough */
931 } Buf;
932 ULONG cbBuf;
933 UNICODE_STRING RtlStr;
934 RtlInitUnicodeString(&RtlStr, pName);
935 NTSTATUS Status = ZwQueryValueKey(hKey,
936 &RtlStr,
937 KeyValuePartialInformation,
938 &Buf.Info,
939 sizeof(Buf),
940 &cbBuf);
941 if (Status == STATUS_SUCCESS)
942 {
943 if (Buf.Info.Type == REG_DWORD)
944 {
945 Assert(Buf.Info.DataLength == 4);
946 *pDword = *((PULONG)Buf.Info.Data);
947 return STATUS_SUCCESS;
948 }
949 }
950
951 return STATUS_INVALID_PARAMETER;
952}
953
954NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, IN DWORD val)
955{
956 UNICODE_STRING RtlStr;
957 RtlInitUnicodeString(&RtlStr, pName);
958 return ZwSetValueKey(hKey, &RtlStr,
959 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
960 REG_DWORD,
961 &val,
962 sizeof(val));
963}
964
965UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt)
966{
967 if (pDevExt->VideoGuid.Buffer)
968 return &pDevExt->VideoGuid;
969
970 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
971 WCHAR VideoGuidBuf[512];
972 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
973 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(pDevExt ,cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
974 Assert(Status == STATUS_SUCCESS);
975 if (Status == STATUS_SUCCESS)
976 {
977 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
978 Assert(pBuf);
979 if (pBuf)
980 {
981 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
982 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
983 return &pDevExt->VideoGuid;
984 }
985 }
986
987 return NULL;
988}
989
990VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt)
991{
992 if (pDevExt->VideoGuid.Buffer)
993 {
994 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
995 pDevExt->VideoGuid.Buffer = NULL;
996 }
997}
998
999/* mm */
1000
1001NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
1002{
1003 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
1004 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
1005 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
1006 if (!pBuf)
1007 {
1008 Assert(0);
1009 return STATUS_NO_MEMORY;
1010 }
1011 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
1012 pMm->cPages = cPages;
1013 pMm->cAllocs = 0;
1014 pMm->pBuffer = pBuf;
1015 return STATUS_SUCCESS;
1016}
1017
1018ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
1019{
1020 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
1021 if (iPage == 0xFFFFFFFF)
1022 {
1023 Assert(0);
1024 return VBOXWDDM_MM_VOID;
1025 }
1026
1027 ++pMm->cAllocs;
1028 return iPage;
1029}
1030
1031VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
1032{
1033 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
1034 RtlClearBits(&pMm->BitMap, iPage, cPages);
1035 --pMm->cAllocs;
1036 Assert(pMm->cAllocs < UINT32_MAX);
1037}
1038
1039NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
1040{
1041 Assert(!pMm->cAllocs);
1042 vboxWddmMemFree(pMm->pBuffer);
1043 pMm->pBuffer = NULL;
1044 return STATUS_SUCCESS;
1045}
1046
1047
1048
1049typedef struct VBOXVIDEOCM_ALLOC
1050{
1051 VBOXWDDM_HANDLE hGlobalHandle;
1052 uint32_t offData;
1053 uint32_t cbData;
1054} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
1055
1056typedef struct VBOXVIDEOCM_ALLOC_REF
1057{
1058 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
1059 VBOXWDDM_HANDLE hSessionHandle;
1060 PVBOXVIDEOCM_ALLOC pAlloc;
1061 PKEVENT pSynchEvent;
1062 VBOXUHGSMI_BUFFER_TYPE_FLAGS fUhgsmiType;
1063 volatile uint32_t cRefs;
1064 PVOID pvUm;
1065 MDL Mdl;
1066} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
1067
1068
1069NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
1070{
1071 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1072 UINT cbSize = pAlloc->cbData;
1073 UINT cPages = BYTES_TO_PAGES(cbSize);
1074 ExAcquireFastMutex(&pMgr->Mutex);
1075 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
1076 if (iPage != VBOXWDDM_MM_VOID)
1077 {
1078 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
1079 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
1080 pAlloc->offData = offData;
1081 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
1082 ExReleaseFastMutex(&pMgr->Mutex);
1083 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
1084 return STATUS_SUCCESS;
1085
1086 Assert(0);
1087 Status = STATUS_NO_MEMORY;
1088 vboxMmFree(&pMgr->Mm, iPage, cPages);
1089 }
1090 else
1091 {
1092 Assert(0);
1093 ExReleaseFastMutex(&pMgr->Mutex);
1094 Status = STATUS_INSUFFICIENT_RESOURCES;
1095 }
1096 return Status;
1097}
1098
1099VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
1100{
1101 UINT cbSize = pAlloc->cbData;
1102 UINT cPages = BYTES_TO_PAGES(cbSize);
1103 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
1104 ExAcquireFastMutex(&pMgr->Mutex);
1105 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
1106 vboxMmFree(&pMgr->Mm, iPage, cPages);
1107 ExReleaseFastMutex(&pMgr->Mutex);
1108}
1109
1110
1111NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
1112{
1113 NTSTATUS Status = STATUS_SUCCESS;
1114 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
1115 if (pAlloc)
1116 {
1117 pAlloc->cbData = cbSize;
1118 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
1119 if (Status == STATUS_SUCCESS)
1120 {
1121 *ppAlloc = pAlloc;
1122 return STATUS_SUCCESS;
1123 }
1124
1125 Assert(0);
1126 vboxWddmMemFree(pAlloc);
1127 }
1128 else
1129 {
1130 Assert(0);
1131 Status = STATUS_NO_MEMORY;
1132 }
1133
1134 return Status;
1135}
1136
1137VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
1138{
1139 vboxVideoCmAllocDealloc(pMgr, pAlloc);
1140 vboxWddmMemFree(pAlloc);
1141}
1142
1143NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1144{
1145 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1146 NTSTATUS Status = STATUS_SUCCESS;
1147 PKEVENT pSynchEvent = NULL;
1148
1149 if (pUmAlloc->hSynch)
1150 {
1151 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
1152 (PVOID*)&pSynchEvent,
1153 NULL);
1154 Assert(Status == STATUS_SUCCESS);
1155 Assert(pSynchEvent);
1156 }
1157
1158 if (Status == STATUS_SUCCESS)
1159 {
1160 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
1161 SIZE_T cbLength = pAlloc->cbData;
1162
1163 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero(sizeof (*pAllocRef) + sizeof (PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
1164 if (pAllocRef)
1165 {
1166 pAllocRef->cRefs = 1;
1167 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
1168 __try
1169 {
1170 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
1171 }
1172 __except(EXCEPTION_EXECUTE_HANDLER)
1173 {
1174 Assert(0);
1175 Status = STATUS_UNSUCCESSFUL;
1176 }
1177
1178 if (Status == STATUS_SUCCESS)
1179 {
1180 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
1181 NULL, /* PVOID BaseAddress */
1182 FALSE, /* ULONG BugCheckOnFailure */
1183 NormalPagePriority);
1184 if (pvUm)
1185 {
1186 pAllocRef->pvUm = pvUm;
1187 pAllocRef->pContext = pContext;
1188 pAllocRef->pAlloc = pAlloc;
1189 pAllocRef->fUhgsmiType = pUmAlloc->fUhgsmiType;
1190 pAllocRef->pSynchEvent = pSynchEvent;
1191 ExAcquireFastMutex(&pContext->Mutex);
1192 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
1193 ExReleaseFastMutex(&pContext->Mutex);
1194 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
1195 {
1196 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
1197 pUmAlloc->cbData = pAlloc->cbData;
1198 pUmAlloc->pvData = (uint64_t)pvUm;
1199 return STATUS_SUCCESS;
1200 }
1201
1202 MmUnmapLockedPages(pvUm, &pAllocRef->Mdl);
1203 }
1204 else
1205 {
1206 Assert(0);
1207 Status = STATUS_INSUFFICIENT_RESOURCES;
1208 }
1209
1210 MmUnlockPages(&pAllocRef->Mdl);
1211 }
1212
1213 vboxWddmMemFree(pAllocRef);
1214 }
1215 else
1216 {
1217 Assert(0);
1218 Status = STATUS_NO_MEMORY;
1219 }
1220
1221 if (pSynchEvent)
1222 ObDereferenceObject(pSynchEvent);
1223 }
1224 else
1225 {
1226 Assert(0);
1227 }
1228
1229
1230 return Status;
1231}
1232
1233NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle, PVBOXVIDEOCM_ALLOC *ppAlloc)
1234{
1235 NTSTATUS Status = STATUS_SUCCESS;
1236 ExAcquireFastMutex(&pContext->Mutex);
1237 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
1238 ExReleaseFastMutex(&pContext->Mutex);
1239 if (pAllocRef)
1240 {
1241 /* wait for the dereference, i.e. for all commands involving this allocation to complete */
1242 vboxWddmCounterU32Wait(&pAllocRef->cRefs, 1);
1243
1244 MmUnmapLockedPages(pAllocRef->pvUm, &pAllocRef->Mdl);
1245
1246 MmUnlockPages(&pAllocRef->Mdl);
1247 *ppAlloc = pAllocRef->pAlloc;
1248 if (pAllocRef->pSynchEvent)
1249 ObDereferenceObject(pAllocRef->pSynchEvent);
1250 vboxWddmMemFree(pAllocRef);
1251 }
1252 else
1253 {
1254 Assert(0);
1255 Status = STATUS_INVALID_PARAMETER;
1256 }
1257
1258 return Status;
1259}
1260
1261static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1262{
1263 ExAcquireFastMutex(&pContext->Mutex);
1264 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
1265 if (pAllocRef)
1266 ASMAtomicIncU32(&pAllocRef->cRefs);
1267 ExReleaseFastMutex(&pContext->Mutex);
1268 return pAllocRef;
1269}
1270
1271static VOID vboxVideoAMgrCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
1272{
1273 uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs);
1274 Assert(cRefs < UINT32_MAX/2);
1275 Assert(cRefs >= 1); /* we do not do cleanup-on-zero here, instead we wait for the cRefs to reach 1 in vboxVideoAMgrCtxAllocUnmap before unmapping */
1276}
1277
1278
1279
1280NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1281{
1282 PVBOXVIDEOCM_ALLOC pAlloc;
1283 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1284 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
1285 if (Status == STATUS_SUCCESS)
1286 {
1287 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
1288 if (Status == STATUS_SUCCESS)
1289 return STATUS_SUCCESS;
1290 else
1291 {
1292 Assert(0);
1293 }
1294 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1295 }
1296 else
1297 {
1298 Assert(0);
1299 }
1300 return Status;
1301}
1302
1303NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1304{
1305 PVBOXVIDEOCM_ALLOC pAlloc;
1306 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1307 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
1308 if (Status == STATUS_SUCCESS)
1309 {
1310 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1311 }
1312 else
1313 {
1314 Assert(0);
1315 }
1316 return Status;
1317}
1318
1319#ifdef VBOX_WITH_CRHGSMI
1320static DECLCALLBACK(VOID) vboxVideoAMgrAllocSubmitCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1321{
1322 /* we should be called from our DPC routine */
1323 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1324
1325 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvContext;
1326 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1327 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1328 UINT cBufs = pBody->cBuffers;
1329 for (UINT i = 0; i < cBufs; ++i)
1330 {
1331 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1332 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd->u64GuestData;
1333 if (!pBufCmd->u32GuestData)
1334 {
1335 /* signal completion */
1336 if (pRef->pSynchEvent)
1337 KeSetEvent(pRef->pSynchEvent, 3, FALSE);
1338 }
1339
1340 vboxVideoAMgrCtxAllocRefRelease(pRef);
1341 }
1342
1343 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1344}
1345
1346/* submits a set of chromium uhgsmi buffers to host for processing */
1347NTSTATUS vboxVideoAMgrCtxAllocSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_CONTEXT pContext, UINT cBuffers, VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *paBuffers)
1348{
1349 /* ensure we do not overflow the 32bit buffer size value */
1350 if (VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXVDMACMD_CHROMIUM_CMD, aBuffers) < cBuffers)
1351 {
1352 WARN(("number of buffers passed too big (%d), max is (%d)", cBuffers, VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXVDMACMD_CHROMIUM_CMD, aBuffers)));
1353 return STATUS_INVALID_PARAMETER;
1354 }
1355
1356 NTSTATUS Status = STATUS_SUCCESS;
1357 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers]));
1358
1359 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd);
1360 if (pDr)
1361 {
1362 // vboxVdmaCBufDrCreate zero initializes the pDr
1363 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
1364 pDr->cbBuf = cbCmd;
1365 pDr->rc = VERR_NOT_IMPLEMENTED;
1366
1367 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1368 pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD;
1369 pHdr->u32CmdSpecific = 0;
1370 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1371 pBody->cBuffers = cBuffers;
1372 for (UINT i = 0; i < cBuffers; ++i)
1373 {
1374 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1375 VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *pBufInfo = &paBuffers[i];
1376 PVBOXVIDEOCM_ALLOC_REF pRef = vboxVideoAMgrCtxAllocRefAcquire(pContext, pBufInfo->hAlloc);
1377 if (pRef)
1378 {
1379#ifdef DEBUG_misha
1380 Assert(pRef->cRefs == 2);
1381#endif
1382 pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData;
1383 pBufCmd->cbBuffer = pBufInfo->Info.cbData;
1384 pBufCmd->u32GuestData = 0;
1385 pBufCmd->u64GuestData = (uint64_t)pRef;
1386 }
1387 else
1388 {
1389 WARN(("vboxVideoAMgrCtxAllocRefAcquire failed for hAlloc(0x%x)\n", pBufInfo->hAlloc));
1390 /* release all previously acquired aloc references */
1391 for (UINT j = 0; j < i; ++j)
1392 {
1393 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmdJ = &pBody->aBuffers[j];
1394 PVBOXVIDEOCM_ALLOC_REF pRefJ = (PVBOXVIDEOCM_ALLOC_REF)pBufCmdJ;
1395 vboxVideoAMgrCtxAllocRefRelease(pRefJ);
1396 }
1397 Status = STATUS_INVALID_PARAMETER;
1398 break;
1399 }
1400 }
1401
1402 if (Status == STATUS_SUCCESS)
1403 {
1404 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
1405 vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxVideoAMgrAllocSubmitCompletion, pDr);
1406 /* mark command as submitted & invisible for the dx runtime since dx did not originate it */
1407 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
1408 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1409 if (RT_SUCCESS(rc))
1410 {
1411 return STATUS_SUCCESS;
1412 }
1413
1414 WARN(("vboxVdmaCBufDrSubmit failed with rc (%d)\n", rc));
1415
1416 /* failure branch */
1417 /* release all previously acquired aloc references */
1418 for (UINT i = 0; i < cBuffers; ++i)
1419 {
1420 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1421 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd;
1422 vboxVideoAMgrCtxAllocRefRelease(pRef);
1423 }
1424 }
1425
1426 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1427 }
1428 else
1429 {
1430 Assert(0);
1431 /* @todo: try flushing.. */
1432 LOGREL(("vboxVdmaCBufDrCreate returned NULL"));
1433 Status = STATUS_INSUFFICIENT_RESOURCES;
1434 }
1435
1436 return Status;
1437}
1438#endif
1439
1440NTSTATUS vboxVideoAMgrCreate(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
1441{
1442 Assert(!(offData & (PAGE_SIZE -1)));
1443 Assert(!(cbData & (PAGE_SIZE -1)));
1444 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
1445 cbData &= (~(PAGE_SIZE -1));
1446 Assert(cbData);
1447 if (!cbData)
1448 return STATUS_INVALID_PARAMETER;
1449
1450 ExInitializeFastMutex(&pMgr->Mutex);
1451 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
1452 Assert(Status == STATUS_SUCCESS);
1453 if (Status == STATUS_SUCCESS)
1454 {
1455 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
1456 Assert(Status == STATUS_SUCCESS);
1457 if (Status == STATUS_SUCCESS)
1458 {
1459 PHYSICAL_ADDRESS PhysicalAddress = {0};
1460 PhysicalAddress.QuadPart = VBoxCommonFromDeviceExt(pDevExt)->phVRAM.QuadPart + offData;
1461 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
1462 Assert(pMgr->pvData);
1463 if (pMgr->pvData)
1464 {
1465 pMgr->offData = offData;
1466 pMgr->cbData = cbData;
1467 return STATUS_SUCCESS;
1468 }
1469 else
1470 {
1471 Status = STATUS_UNSUCCESSFUL;
1472 }
1473 vboxMmTerm(&pMgr->Mm);
1474 }
1475 vboxWddmHTableDestroy(&pMgr->AllocTable);
1476 }
1477
1478 return Status;
1479}
1480
1481NTSTATUS vboxVideoAMgrDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1482{
1483 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1484 vboxMmTerm(&pMgr->Mm);
1485 vboxWddmHTableDestroy(&pMgr->AllocTable);
1486 return STATUS_SUCCESS;
1487}
1488
1489NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1490{
1491 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1492 if (pMgr->pvData)
1493 {
1494 ExInitializeFastMutex(&pCtx->Mutex);
1495 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1496 Assert(Status == STATUS_SUCCESS);
1497 if (Status == STATUS_SUCCESS)
1498 {
1499 pCtx->pMgr = pMgr;
1500 return STATUS_SUCCESS;
1501 }
1502 }
1503 return Status;
1504}
1505
1506NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1507{
1508 if (!pCtx->pMgr)
1509 return STATUS_SUCCESS;
1510
1511 VBOXWDDM_HTABLE_ITERATOR Iter;
1512 NTSTATUS Status = STATUS_SUCCESS;
1513
1514 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1515 do
1516 {
1517 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1518 if (!pRef)
1519 break;
1520
1521 Assert(0);
1522
1523 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1524 Assert(Status == STATUS_SUCCESS);
1525 if (Status != STATUS_SUCCESS)
1526 break;
1527 // vboxWddmHTableIterRemoveCur(&Iter);
1528 } while (1);
1529
1530 if (Status == STATUS_SUCCESS)
1531 {
1532 vboxWddmHTableDestroy(&pCtx->AllocTable);
1533 }
1534
1535 return Status;
1536}
1537
1538
1539VOID vboxWddmSleep(uint32_t u32Val)
1540{
1541 LARGE_INTEGER Interval;
1542 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1543
1544 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1545}
1546
1547VOID vboxWddmCounterU32Wait(uint32_t volatile * pu32, uint32_t u32Val)
1548{
1549 LARGE_INTEGER Interval;
1550 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1551 uint32_t u32CurVal;
1552
1553 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1554
1555 while ((u32CurVal = ASMAtomicReadU32(pu32)) != u32Val)
1556 {
1557 Assert(u32CurVal >= u32Val);
1558 Assert(u32CurVal < UINT32_MAX/2);
1559
1560 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1561 }
1562}
1563
1564/* dump user-mode driver debug info */
1565static char g_aVBoxUmdD3DCAPS9[304];
1566static VBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS g_VBoxUmdD3DCAPS9Flags;
1567static BOOLEAN g_bVBoxUmdD3DCAPS9IsInited = FALSE;
1568
1569static void vboxUmdDumpDword(DWORD *pvData, DWORD cData)
1570{
1571 char aBuf[16*4];
1572 DWORD dw1, dw2, dw3, dw4;
1573 for (UINT i = 0; i < (cData & (~3)); i+=4)
1574 {
1575 dw1 = *pvData++;
1576 dw2 = *pvData++;
1577 dw3 = *pvData++;
1578 dw4 = *pvData++;
1579 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", dw1, dw2, dw3, dw4);
1580 LOGREL(("%s", aBuf));
1581 }
1582
1583 cData = cData % 4;
1584 switch (cData)
1585 {
1586 case 3:
1587 dw1 = *pvData++;
1588 dw2 = *pvData++;
1589 dw3 = *pvData++;
1590 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x\n", dw1, dw2, dw3);
1591 LOGREL(("%s", aBuf));
1592 break;
1593 case 2:
1594 dw1 = *pvData++;
1595 dw2 = *pvData++;
1596 sprintf(aBuf, "0x%08x, 0x%08x\n", dw1, dw2);
1597 LOGREL(("%s", aBuf));
1598 break;
1599 case 1:
1600 dw1 = *pvData++;
1601 sprintf(aBuf, "0x%8x\n", dw1);
1602 LOGREL(("%s", aBuf));
1603 break;
1604 default:
1605 break;
1606 }
1607}
1608
1609static void vboxUmdDumpD3DCAPS9(void *pvData, PVBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS pFlags)
1610{
1611 AssertCompile(!(sizeof (g_aVBoxUmdD3DCAPS9) % sizeof (DWORD)));
1612 LOGREL(("*****Start Dumping D3DCAPS9:*******"));
1613 LOGREL(("WoW64 flag(%d)", (UINT)pFlags->WoW64));
1614 vboxUmdDumpDword((DWORD*)pvData, sizeof (g_aVBoxUmdD3DCAPS9) / sizeof (DWORD));
1615 LOGREL(("*****End Dumping D3DCAPS9**********"));
1616}
1617
1618NTSTATUS vboxUmdDumpBuf(PVBOXDISPIFESCAPE_DBGDUMPBUF pBuf, uint32_t cbBuffer)
1619{
1620 if (cbBuffer < RT_OFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]))
1621 {
1622 WARN(("Buffer too small"));
1623 return STATUS_BUFFER_TOO_SMALL;
1624 }
1625
1626 NTSTATUS Status = STATUS_SUCCESS;
1627 uint32_t cbString = cbBuffer - RT_OFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]);
1628 switch (pBuf->enmType)
1629 {
1630 case VBOXDISPIFESCAPE_DBGDUMPBUF_TYPE_D3DCAPS9:
1631 {
1632 if (cbString != sizeof (g_aVBoxUmdD3DCAPS9))
1633 {
1634 WARN(("wrong caps size, expected %d, but was %d", sizeof (g_aVBoxUmdD3DCAPS9), cbString));
1635 Status = STATUS_INVALID_PARAMETER;
1636 break;
1637 }
1638
1639 if (g_bVBoxUmdD3DCAPS9IsInited)
1640 {
1641 if (!memcmp(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9)))
1642 break;
1643
1644 WARN(("caps do not match!"));
1645 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1646 break;
1647 }
1648
1649 memcpy(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9));
1650 g_VBoxUmdD3DCAPS9Flags = pBuf->Flags;
1651 g_bVBoxUmdD3DCAPS9IsInited = TRUE;
1652 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1653 }
1654 }
1655
1656 return Status;
1657}
1658
1659#if 0
1660VOID vboxShRcTreeInit(PVBOXMP_DEVEXT pDevExt)
1661{
1662 ExInitializeFastMutex(&pDevExt->ShRcTreeMutex);
1663 pDevExt->ShRcTree = NULL;
1664}
1665
1666VOID vboxShRcTreeTerm(PVBOXMP_DEVEXT pDevExt)
1667{
1668 Assert(!pDevExt->ShRcTree);
1669 pDevExt->ShRcTree = NULL;
1670}
1671
1672BOOLEAN vboxShRcTreePut(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1673{
1674 HANDLE hSharedRc = pAlloc->hSharedHandle;
1675 if (!hSharedRc)
1676 {
1677 WARN(("invalid call with zero shared handle!"));
1678 return FALSE;
1679 }
1680 pAlloc->ShRcTreeEntry.Key = (AVLPVKEY)hSharedRc;
1681 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1682 bool bRc = RTAvlPVInsert(&pDevExt->ShRcTree, &pAlloc->ShRcTreeEntry);
1683 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1684 Assert(bRc);
1685 return (BOOLEAN)bRc;
1686}
1687
1688#define PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(_p) ((PVBOXWDDM_ALLOCATION)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, ShRcTreeEntry)))
1689PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc)
1690{
1691 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1692 PAVLPVNODECORE pNode = RTAvlPVGet(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1693 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1694 if (!pNode)
1695 return NULL;
1696 PVBOXWDDM_ALLOCATION pAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1697 return pAlloc;
1698}
1699
1700BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1701{
1702 HANDLE hSharedRc = pAlloc->hSharedHandle;
1703 if (!hSharedRc)
1704 {
1705 WARN(("invalid call with zero shared handle!"));
1706 return FALSE;
1707 }
1708 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1709 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1710 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1711 if (!pNode)
1712 return NULL;
1713 PVBOXWDDM_ALLOCATION pRetAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1714 Assert(pRetAlloc == pAlloc);
1715 return !!pRetAlloc;
1716}
1717#endif
1718
1719NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr)
1720{
1721 HANDLE hKey;
1722 OBJECT_ATTRIBUTES ObjAttr;
1723
1724 InitializeObjectAttributes(&ObjAttr, pRegStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1725
1726 NTSTATUS Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjAttr);
1727 if (!NT_SUCCESS(Status))
1728 {
1729 WARN(("ZwOpenKey for settings key failed, Status 0x%x", Status));
1730 return Status;
1731 }
1732
1733 DWORD dwValue = 0;
1734 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_LOG_UM, &dwValue);
1735 if (NT_SUCCESS(Status))
1736 g_VBoxLogUm = dwValue;
1737
1738 ZwClose(hKey);
1739
1740 return Status;
1741}
1742
1743NTSTATUS vboxWddmThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
1744{
1745 NTSTATUS fStatus;
1746 HANDLE hThread;
1747 OBJECT_ATTRIBUTES fObjectAttributes;
1748
1749 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1750
1751 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
1752 NULL, NULL);
1753
1754 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
1755 &fObjectAttributes, NULL, NULL,
1756 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
1757 if (!NT_SUCCESS(fStatus))
1758 return fStatus;
1759
1760 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
1761 KernelMode, (PVOID*) ppThread, NULL);
1762 ZwClose(hThread);
1763 return STATUS_SUCCESS;
1764}
1765
1766#ifdef VBOX_VDMA_WITH_WATCHDOG
1767static int vboxWddmWdProgram(PVBOXMP_DEVEXT pDevExt, uint32_t cMillis)
1768{
1769 int rc = VINF_SUCCESS;
1770 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
1771 if (pCmd)
1772 {
1773 pCmd->enmCtl = VBOXVDMA_CTL_TYPE_WATCHDOG;
1774 pCmd->u32Offset = cMillis;
1775 pCmd->i32Result = VERR_NOT_SUPPORTED;
1776
1777 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1778 Assert(pHdr);
1779 if (pHdr)
1780 {
1781 do
1782 {
1783 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1784 Assert(offCmd != HGSMIOFFSET_VOID);
1785 if (offCmd != HGSMIOFFSET_VOID)
1786 {
1787 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offCmd);
1788 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1789 AssertRC(rc);
1790 if (RT_SUCCESS(rc))
1791 {
1792 rc = pCmd->i32Result;
1793 AssertRC(rc);
1794 }
1795 break;
1796 }
1797 else
1798 rc = VERR_INVALID_PARAMETER;
1799 /* fail to submit, cancel it */
1800 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
1801 } while (0);
1802 }
1803
1804 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
1805 }
1806 else
1807 {
1808 LOGREL(("HGSMIHeapAlloc failed"));
1809 rc = VERR_OUT_OF_RESOURCES;
1810 }
1811 return rc;
1812}
1813
1814static uint32_t g_VBoxWdTimeout = 4000;
1815/* if null g_VBoxWdTimeout / 2 is used */
1816static uint32_t g_VBoxWdTimerPeriod = 0;
1817
1818static VOID vboxWddmWdThread(PVOID pvUser)
1819{
1820 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvUser;
1821 BOOLEAN bExit = FALSE;
1822 int rc;
1823 while (1)
1824 {
1825 if (!bExit)
1826 {
1827 rc = vboxWddmWdProgram(pDevExt, g_VBoxWdTimeout /* ms */);
1828 AssertRC(rc);
1829 }
1830 else
1831 {
1832 rc = vboxWddmWdProgram(pDevExt, 0 /* to disable WatchDog */);
1833 AssertRC(rc);
1834 break;
1835 }
1836 LARGE_INTEGER Timeout;
1837 uint32_t timerTimeOut = g_VBoxWdTimerPeriod ? g_VBoxWdTimerPeriod : g_VBoxWdTimeout / 2;
1838 Timeout.QuadPart = 10000ULL * timerTimeOut /* ms */;
1839 NTSTATUS Status = KeWaitForSingleObject(&pDevExt->WdEvent, Executive, KernelMode, FALSE, &Timeout);
1840 if (Status != STATUS_TIMEOUT)
1841 bExit = TRUE;
1842 }
1843}
1844
1845NTSTATUS vboxWddmWdInit(PVBOXMP_DEVEXT pDevExt)
1846{
1847 KeInitializeEvent(&pDevExt->WdEvent, NotificationEvent, FALSE);
1848
1849 NTSTATUS Status = vboxWddmThreadCreate(&pDevExt->pWdThread, vboxWddmWdThread, pDevExt);
1850 if (!NT_SUCCESS(Status))
1851 {
1852 WARN(("vboxWddmThreadCreate failed, Status 0x%x", Status));
1853 pDevExt->pWdThread = NULL;
1854 }
1855 return Status;
1856}
1857
1858NTSTATUS vboxWddmWdTerm(PVBOXMP_DEVEXT pDevExt)
1859{
1860 if (!pDevExt->pWdThread)
1861 return STATUS_SUCCESS;
1862
1863 KeSetEvent(&pDevExt->WdEvent, 0, FALSE);
1864
1865 KeWaitForSingleObject(pDevExt->pWdThread, Executive, KernelMode, FALSE, NULL);
1866 ObDereferenceObject(pDevExt->pWdThread);
1867 pDevExt->pWdThread = NULL;
1868 return STATUS_SUCCESS;
1869}
1870#endif
1871
1872static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags)
1873{
1874 PHGSMIGUESTCOMMANDCONTEXT pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
1875 VBVASCANLINECFG *pCfg;
1876 int rc = VINF_SUCCESS;
1877
1878 /* Allocate the IO buffer. */
1879 pCfg = (VBVASCANLINECFG *)VBoxHGSMIBufferAlloc(pCtx,
1880 sizeof (VBVASCANLINECFG), HGSMI_CH_VBVA,
1881 VBVA_SCANLINE_CFG);
1882
1883 if (pCfg)
1884 {
1885 /* Prepare data to be sent to the host. */
1886 pCfg->rc = VERR_NOT_IMPLEMENTED;
1887 pCfg->fFlags = fFlags;
1888 rc = VBoxHGSMIBufferSubmit(pCtx, pCfg);
1889 if (RT_SUCCESS(rc))
1890 {
1891 AssertRC(pCfg->rc);
1892 rc = pCfg->rc;
1893 }
1894 /* Free the IO buffer. */
1895 VBoxHGSMIBufferFree(pCtx, pCfg);
1896 }
1897 else
1898 rc = VERR_NO_MEMORY;
1899 return rc;
1900}
1901
1902NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
1903{
1904 if (!pDevExt->bVSyncTimerEnabled == !fEnable)
1905 return STATUS_SUCCESS;
1906
1907 if (!fEnable)
1908 {
1909 KeCancelTimer(&pDevExt->VSyncTimer);
1910 }
1911 else
1912 {
1913 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1914
1915 LARGE_INTEGER DueTime;
1916 DueTime.QuadPart = -166666LL; /* 60 Hz */
1917 KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 16, &pDevExt->VSyncDpc);
1918 }
1919
1920 pDevExt->bVSyncTimerEnabled = !!fEnable;
1921
1922 return STATUS_SUCCESS;
1923}
1924
1925NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGetScanLine)
1926{
1927 Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pGetScanLine->VidPnTargetId);
1928 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[pGetScanLine->VidPnTargetId];
1929 Assert(pTarget->Size.cx);
1930 Assert(pTarget->Size.cy);
1931 if (pTarget->Size.cy)
1932 {
1933 uint32_t curScanLine;
1934 BOOL bVBlank;
1935 LARGE_INTEGER DevVSyncTime;
1936 DevVSyncTime.QuadPart = ASMAtomicReadU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart);
1937 LARGE_INTEGER VSyncTime;
1938 KeQuerySystemTime(&VSyncTime);
1939
1940 if (VSyncTime.QuadPart < DevVSyncTime.QuadPart)
1941 {
1942 WARN(("vsync time is less than the one stored in device"));
1943 curScanLine = 0;
1944 }
1945 else
1946 {
1947 VSyncTime.QuadPart = VSyncTime.QuadPart - DevVSyncTime.QuadPart;
1948 /* time is in 100ns, */
1949 curScanLine = (uint32_t)((pTarget->Size.cy * VSyncTime.QuadPart) / DevVSyncTime.QuadPart);
1950 if (pDevExt->bVSyncTimerEnabled)
1951 {
1952 if (curScanLine >= pTarget->Size.cy)
1953 curScanLine = 0;
1954 }
1955 else
1956 {
1957 curScanLine %= pTarget->Size.cy;
1958 }
1959 }
1960
1961 bVBlank = (!curScanLine || curScanLine > pTarget->Size.cy);
1962 pGetScanLine->ScanLine = curScanLine;
1963 pGetScanLine->InVerticalBlank = bVBlank;
1964 }
1965 else
1966 {
1967 pGetScanLine->InVerticalBlank = TRUE;
1968 pGetScanLine->ScanLine = 0;
1969 }
1970 return STATUS_SUCCESS;
1971}
1972
1973static BOOLEAN vboxWddmSlVSyncIrqCb(PVOID pvContext)
1974{
1975 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1976 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1977 BOOLEAN bNeedDpc = FALSE;
1978 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1979 {
1980 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1981 if (pTarget->fConnected)
1982 {
1983 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1984 notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC;
1985 notify.CrtcVsync.VidPnTargetId = i;
1986 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1987 bNeedDpc = TRUE;
1988 }
1989 }
1990
1991 if (bNeedDpc)
1992 {
1993 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1994 }
1995
1996 return FALSE;
1997}
1998
1999static VOID vboxWddmSlVSyncDpc(
2000 __in struct _KDPC *Dpc,
2001 __in_opt PVOID DeferredContext,
2002 __in_opt PVOID SystemArgument1,
2003 __in_opt PVOID SystemArgument2
2004)
2005{
2006 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext;
2007 Assert(!pDevExt->fVSyncInVBlank);
2008 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 1);
2009
2010 BOOLEAN bDummy;
2011 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
2012 pDevExt->u.primary.DxgkInterface.DeviceHandle,
2013 vboxWddmSlVSyncIrqCb,
2014 pDevExt,
2015 0, /* IN ULONG MessageNumber */
2016 &bDummy);
2017 if (!NT_SUCCESS(Status))
2018 WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status));
2019
2020 LARGE_INTEGER VSyncTime;
2021 KeQuerySystemTime(&VSyncTime);
2022 ASMAtomicWriteU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart, VSyncTime.QuadPart);
2023
2024 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 0);
2025}
2026
2027NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt)
2028{
2029 pDevExt->bVSyncTimerEnabled = FALSE;
2030 pDevExt->fVSyncInVBlank = 0;
2031 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
2032 KeInitializeTimer(&pDevExt->VSyncTimer);
2033 KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt);
2034 return STATUS_SUCCESS;
2035}
2036
2037NTSTATUS VBoxWddmSlTerm(PVBOXMP_DEVEXT pDevExt)
2038{
2039 KeCancelTimer(&pDevExt->VSyncTimer);
2040 return STATUS_SUCCESS;
2041}
2042
2043#ifdef VBOX_WDDM_WIN8
2044void vboxWddmDiInitDefault(DXGK_DISPLAY_INFORMATION *pInfo, PHYSICAL_ADDRESS PhAddr, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
2045{
2046 pInfo->Width = 1024;
2047 pInfo->Height = 768;
2048 pInfo->Pitch = pInfo->Width * 4;
2049 pInfo->ColorFormat = D3DDDIFMT_A8R8G8B8;
2050 pInfo->PhysicAddress = PhAddr;
2051 pInfo->TargetId = VidPnSourceId;
2052 pInfo->AcpiId = 0;
2053}
2054
2055void vboxWddmDiToAllocData(PVBOXMP_DEVEXT pDevExt, const DXGK_DISPLAY_INFORMATION *pInfo, PVBOXWDDM_ALLOC_DATA pAllocData)
2056{
2057 pAllocData->SurfDesc.width = pInfo->Width;
2058 pAllocData->SurfDesc.height = pInfo->Height;
2059 pAllocData->SurfDesc.format = pInfo->ColorFormat;
2060 pAllocData->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pInfo->ColorFormat);
2061 pAllocData->SurfDesc.pitch = pInfo->Pitch;
2062 pAllocData->SurfDesc.depth = 1;
2063 pAllocData->SurfDesc.slicePitch = pInfo->Pitch;
2064 pAllocData->SurfDesc.cbSize = pInfo->Pitch * pInfo->Height;
2065 pAllocData->SurfDesc.VidPnSourceId = pInfo->TargetId;
2066 pAllocData->SurfDesc.RefreshRate.Numerator = 60000;
2067 pAllocData->SurfDesc.RefreshRate.Denominator = 1000;
2068
2069 /* the address here is not a VRAM offset! so convert it to offset */
2070 vboxWddmAddrSetVram(&pAllocData->Addr, 1,
2071 vboxWddmVramAddrToOffset(pDevExt, pInfo->PhysicAddress));
2072}
2073
2074void vboxWddmDmAdjustDefaultVramLocations(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID ModifiedVidPnSourceId, VBOXWDDM_SOURCE *paSources)
2075{
2076 PVBOXWDDM_SOURCE pSource = &paSources[ModifiedVidPnSourceId];
2077 PHYSICAL_ADDRESS PhAddr;
2078 AssertRelease(pSource->AllocData.Addr.SegmentId);
2079 AssertRelease(pSource->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID);
2080 PhAddr.QuadPart = pSource->AllocData.Addr.offVram;
2081
2082 for (UINT i = ModifiedVidPnSourceId + 1; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
2083 {
2084 /* increaze the phaddr based on the previous source size info */
2085 PhAddr.QuadPart += pSource->AllocData.SurfDesc.cbSize;
2086 PhAddr.QuadPart = ROUND_TO_PAGES(PhAddr.QuadPart);
2087 pSource = &paSources[i];
2088 if (pSource->AllocData.Addr.offVram != PhAddr.QuadPart
2089 || pSource->AllocData.Addr.SegmentId != 1)
2090 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
2091 pSource->AllocData.Addr.SegmentId = 1;
2092 pSource->AllocData.Addr.offVram = PhAddr.QuadPart;
2093 }
2094}
2095#endif
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