VirtualBox

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

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

*: scm --update-copyright-year

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