VirtualBox

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

Last change on this file since 65381 was 65381, checked in by vboxsync, 8 years ago

bugref:8282: Additions/linux: submit DRM driver to the Linux kernel: move all graphics device-related header files to a separate sub-directory and add that to the include path where they are needed. The intention is too be able to remove the VBox/ include folder in the DRM driver package.

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