VirtualBox

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

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

(C) 2016

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette