VirtualBox

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

Last change on this file since 38930 was 38930, checked in by vboxsync, 13 years ago

wddm/3d: more rendering fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.0 KB
Line 
1/* $Id: VBoxMPMisc.cpp 38930 2011-10-03 08:45:54Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011 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
183PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate()
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 }
193 return pSwapchain;
194}
195
196DECLINLINE(BOOLEAN) vboxWddmSwapchainRetainLocked(PVBOXWDDM_SWAPCHAIN pSwapchain)
197{
198 if (pSwapchain->enmState == VBOXWDDM_OBJSTATE_TYPE_INITIALIZED)
199 {
200 ASMAtomicIncU32(&pSwapchain->cRefs);
201 return TRUE;
202 }
203 return FALSE;
204}
205
206DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
207{
208 KIRQL OldIrql;
209 BOOLEAN bRc;
210 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
211 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
212 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
213 return bRc;
214}
215
216DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain)
217{
218 const uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs);
219 Assert(cRefs < UINT32_MAX/2);
220 if (!cRefs)
221 {
222 vboxWddmMemFree(pSwapchain);
223 }
224}
225
226PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
227{
228 KIRQL OldIrql;
229 PVBOXWDDM_SWAPCHAIN pSwapchain;
230 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
231 pSwapchain = pAlloc->pSwapchain;
232 if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain))
233 pSwapchain = NULL;
234 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
235 return pSwapchain;
236}
237
238VOID vboxWddmSwapchainAllocRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
239{
240 KIRQL OldIrql;
241 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
242 Assert(pAlloc->pSwapchain == pSwapchain);
243 pAlloc->pSwapchain = NULL;
244 RemoveEntryList(&pAlloc->SwapchainEntry);
245 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
246 vboxWddmSwapchainRelease(pSwapchain);
247}
248
249BOOLEAN vboxWddmSwapchainAllocAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
250{
251 KIRQL OldIrql;
252 BOOLEAN bRc;
253 Assert(!pAlloc->pSwapchain);
254 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
255 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
256 if (bRc)
257 {
258 if (pAlloc->pSwapchain)
259 {
260 RemoveEntryList(&pAlloc->SwapchainEntry);
261 }
262 InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry);
263 pAlloc->pSwapchain = pSwapchain;
264 }
265 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
266 return bRc;
267}
268
269#define VBOXSCENTRY_2_ALLOC(_pE) ((PVBOXWDDM_ALLOCATION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, SwapchainEntry)))
270
271static VOID vboxWddmSwapchainAllocRemoveAllInternal(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, BOOLEAN bOnDestroy)
272{
273 KIRQL OldIrql;
274 UINT cRemoved = 0;
275 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
276 PLIST_ENTRY pEntry = pSwapchain->AllocList.Flink;
277 do
278 {
279 if (pEntry != &pSwapchain->AllocList)
280 {
281 PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry);
282 pEntry = pEntry->Flink;
283 Assert(pAlloc->pSwapchain == pSwapchain);
284 pAlloc->pSwapchain = NULL;
285 RemoveEntryList(&pAlloc->SwapchainEntry);
286 ++cRemoved;
287 }
288 else
289 break;
290 } while (1);
291
292 if (bOnDestroy)
293 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_TERMINATED;
294 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
295
296 for (UINT i = 0; i < cRemoved; ++i)
297 vboxWddmSwapchainRelease(pSwapchain);
298}
299
300VOID vboxWddmSwapchainAllocRemoveAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
301{
302 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, FALSE);
303}
304
305VOID vboxWddmSwapchainDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
306{
307 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE);
308
309 Assert(pSwapchain->pContext);
310 if (pSwapchain->pContext)
311 {
312 NTSTATUS tmpStatus = vboxVdmaGgCmdCancel(pDevExt, pSwapchain->pContext, pSwapchain);
313 if (tmpStatus != STATUS_SUCCESS)
314 {
315 WARN(("vboxVdmaGgCmdCancel returned Status (0x%x)", tmpStatus));
316 }
317 }
318
319 vboxWddmSwapchainRelease(pSwapchain);
320}
321
322static BOOLEAN vboxWddmSwapchainCtxAddLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
323{
324 if (vboxWddmSwapchainRetain(pDevExt, pSwapchain))
325 {
326 Assert(!pSwapchain->hSwapchainKm);
327 Assert(!pSwapchain->pContext);
328 pSwapchain->pContext = pContext;
329 pSwapchain->hSwapchainKm = vboxWddmHTablePut(&pContext->Swapchains, pSwapchain);
330 InsertHeadList(&pDevExt->SwapchainList3D, &pSwapchain->DevExtListEntry);
331 return TRUE;
332 }
333 return FALSE;
334}
335
336static VOID vboxWddmSwapchainCtxRemoveLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
337{
338 Assert(pSwapchain->hSwapchainKm);
339 Assert(pSwapchain->pContext);
340 void * pTst = vboxWddmHTableRemove(&pContext->Swapchains, pSwapchain->hSwapchainKm);
341 Assert(pTst == pSwapchain);
342 RemoveEntryList(&pSwapchain->DevExtListEntry);
343 pSwapchain->hSwapchainKm = NULL;
344 if (pSwapchain->pLastReportedRects)
345 {
346 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
347 pSwapchain->pLastReportedRects = NULL;
348 }
349 vboxWddmSwapchainRelease(pSwapchain);
350}
351
352/* adds the given swapchain to the context's swapchain list
353 * @return true on success */
354BOOLEAN vboxWddmSwapchainCtxAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
355{
356 BOOLEAN bRc;
357 ExAcquireFastMutex(&pDevExt->ContextMutex);
358 bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
359 ExReleaseFastMutex(&pDevExt->ContextMutex);
360 return bRc;
361}
362
363/* removes the given swapchain from the context's swapchain list
364 * */
365VOID vboxWddmSwapchainCtxRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
366{
367 ExAcquireFastMutex(&pDevExt->ContextMutex);
368 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
369 ExReleaseFastMutex(&pDevExt->ContextMutex);
370}
371
372/* destroys all swapchains for the given context
373 * */
374VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
375{
376 VBOXWDDM_HTABLE_ITERATOR Iter;
377 do
378 {
379 ExAcquireFastMutex(&pDevExt->ContextMutex);
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 ExReleaseFastMutex(&pDevExt->ContextMutex);
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 ExReleaseFastMutex(&pDevExt->ContextMutex);
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 Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])));
402 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
403 return STATUS_INVALID_PARAMETER;
404 Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]));
405 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
406 return STATUS_INVALID_PARAMETER;
407
408 PVBOXWDDM_SWAPCHAIN pSwapchain = NULL;
409 PVBOXWDDM_ALLOCATION *apAlloc = NULL;
410 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
411 NTSTATUS Status = STATUS_SUCCESS;
412
413 do {
414 if (pSwapchainInfo->SwapchainInfo.cAllocs)
415 {
416 apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
417 Assert(apAlloc);
418 if (!apAlloc)
419 {
420 Status = STATUS_NO_MEMORY;
421 break;
422 }
423 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
424 {
425 DXGKARGCB_GETHANDLEDATA GhData;
426 GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
427 GhData.Type = DXGK_HANDLE_ALLOCATION;
428 GhData.Flags.Value = 0;
429 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
430 Assert(pAlloc);
431 if (!pAlloc)
432 {
433 Status = STATUS_INVALID_PARAMETER;
434 break;
435 }
436 apAlloc[i] = pAlloc;
437 }
438
439 if (!NT_SUCCESS(Status))
440 break;
441 }
442
443 if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
444 {
445 ExAcquireFastMutex(&pDevExt->ContextMutex);
446 pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
447 Assert(pSwapchain);
448 if (!pSwapchain)
449 {
450 ExReleaseFastMutex(&pDevExt->ContextMutex);
451 Status = STATUS_INVALID_PARAMETER;
452 break;
453 }
454 Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
455 Assert(pSwapchain->pContext == pContext);
456 if (pSwapchain->pContext != pContext)
457 {
458 ExReleaseFastMutex(&pDevExt->ContextMutex);
459 Status = STATUS_INVALID_PARAMETER;
460 break;
461 }
462 }
463 else if (pSwapchainInfo->SwapchainInfo.cAllocs)
464 {
465 pSwapchain = vboxWddmSwapchainCreate();
466 if (!pSwapchain)
467 {
468 Status = STATUS_NO_MEMORY;
469 break;
470 }
471
472 ExAcquireFastMutex(&pDevExt->ContextMutex);
473 BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
474 Assert(bRc);
475 }
476 else
477 {
478 Status = STATUS_INVALID_PARAMETER;
479 break;
480 }
481
482 /* do not zero up the view rect since it may still be valid */
483// memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
484 if (pSwapchain->pLastReportedRects)
485 {
486 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
487 pSwapchain->pLastReportedRects = NULL;
488 }
489
490 vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);
491
492 if (pSwapchainInfo->SwapchainInfo.cAllocs)
493 {
494 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
495 {
496 vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
497 }
498 pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
499 }
500 else
501 {
502 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
503 }
504
505 ExReleaseFastMutex(&pDevExt->ContextMutex);
506
507 if (pSwapchainInfo->SwapchainInfo.cAllocs)
508 {
509 Assert(pSwapchain->pContext);
510 Assert(pSwapchain->hSwapchainKm);
511 pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
512 }
513 else
514 {
515 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
516 pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
517 }
518
519 Assert(Status == STATUS_SUCCESS);
520 } while (0);
521
522 /* cleanup */
523 if (apAlloc)
524 vboxWddmMemFree(apAlloc);
525
526 return Status;
527}
528
529NTSTATUS vboxWddmSwapchainCtxInit(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
530{
531 NTSTATUS Status = vboxWddmHTableCreate(&pContext->Swapchains, 4);
532 if (!NT_SUCCESS(Status))
533 {
534 WARN(("vboxWddmHTableCreate failes, Status (x%x)", Status));
535 return Status;
536 }
537
538 return STATUS_SUCCESS;
539}
540
541VOID vboxWddmSwapchainCtxTerm(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
542{
543 vboxWddmSwapchainCtxDestroyAll(pDevExt, pContext);
544 vboxWddmHTableDestroy(&pContext->Swapchains);
545}
546
547#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
548
549NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
550{
551 WCHAR fallBackBuf[2];
552 PWCHAR pSuffix;
553 bool bFallback = false;
554
555 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
556 {
557 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
558 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
559 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
560 }
561 else
562 {
563 pSuffix = fallBackBuf;
564 cbBuf = sizeof (fallBackBuf);
565 bFallback = true;
566 }
567
568 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
569 DevicePropertyDriverKeyName,
570 cbBuf,
571 pSuffix,
572 &cbBuf);
573 if (Status == STATUS_SUCCESS && bFallback)
574 Status = STATUS_BUFFER_TOO_SMALL;
575 if (Status == STATUS_BUFFER_TOO_SMALL)
576 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
577
578 return Status;
579}
580
581#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\"
582#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\"
583
584#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX"
585#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY"
586#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop"
587
588NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
589 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
590{
591 NTSTATUS Status = STATUS_SUCCESS;
592 PWCHAR pSuffix;
593 bool bFallback = false;
594 const WCHAR* pKeyPrefix;
595 UINT cbKeyPrefix;
596 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
597 Assert(pVGuid);
598 if (!pVGuid)
599 return STATUS_UNSUCCESSFUL;
600
601 vboxWinVersion_t ver = VBoxQueryWinVersion();
602 if (ver == WINVISTA)
603 {
604 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
605 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
606 }
607 else
608 {
609 Assert(ver == WIN7 || ver == WIN8);
610 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
611 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
612 }
613
614 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
615 if (cbBuf >= cbResult)
616 {
617 wcscpy(pBuf, pKeyPrefix);
618 pSuffix = pBuf + (cbKeyPrefix-2)/2;
619 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
620 pSuffix += pVGuid->Length/2;
621 pSuffix[0] = L'\\';
622 pSuffix += 1;
623 swprintf(pSuffix, L"%04d", VidPnSourceId);
624 }
625 else
626 {
627 Status = STATUS_BUFFER_TOO_SMALL;
628 }
629
630 *pcbResult = cbResult;
631
632 return Status;
633}
634
635#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\"
636#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video"
637
638NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
639{
640 HANDLE hKey;
641 NTSTATUS Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
642 Assert(Status == STATUS_SUCCESS);
643 if (Status == STATUS_SUCCESS)
644 {
645 struct
646 {
647 KEY_BASIC_INFORMATION Name;
648 WCHAR Buf[256];
649 } Buf;
650 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
651 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
652 ULONG ResultLength;
653 BOOL bFound = FALSE;
654 for (ULONG i = 0; !bFound; ++i)
655 {
656 RtlZeroMemory(&Buf, sizeof (Buf));
657 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
658 Assert(Status == STATUS_SUCCESS);
659 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
660 if (Status != STATUS_SUCCESS)
661 break;
662
663 HANDLE hSubKey;
664 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
665 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
666 pSubBuf += Buf.Name.NameLength/2;
667 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
668 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
669 Assert(Status == STATUS_SUCCESS);
670 if (Status == STATUS_SUCCESS)
671 {
672 struct
673 {
674 KEY_VALUE_PARTIAL_INFORMATION Info;
675 UCHAR Buf[sizeof (L"VBoxVideoWddm")]; /* should be enough */
676 } KeyData;
677 ULONG cbResult;
678 UNICODE_STRING RtlStr;
679 RtlInitUnicodeString(&RtlStr, L"Service");
680 Status = ZwQueryValueKey(hSubKey,
681 &RtlStr,
682 KeyValuePartialInformation,
683 &KeyData.Info,
684 sizeof(KeyData),
685 &cbResult);
686 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
687 if (Status == STATUS_SUCCESS)
688 {
689 if (KeyData.Info.Type == REG_SZ)
690 {
691 if (KeyData.Info.DataLength == sizeof (L"VBoxVideoWddm"))
692 {
693 if (!wcscmp(L"VBoxVideoWddm", (PWCHAR)KeyData.Info.Data))
694 {
695 bFound = TRUE;
696 *pcbResult = Buf.Name.NameLength + 2;
697 if (cbBuf >= Buf.Name.NameLength + 2)
698 {
699 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
700 }
701 else
702 {
703 Status = STATUS_BUFFER_TOO_SMALL;
704 }
705 }
706 }
707 }
708 }
709
710 NTSTATUS tmpStatus = ZwClose(hSubKey);
711 Assert(tmpStatus == STATUS_SUCCESS);
712 }
713 else
714 break;
715 }
716 NTSTATUS tmpStatus = ZwClose(hKey);
717 Assert(tmpStatus == STATUS_SUCCESS);
718 }
719
720 return Status;
721}
722
723NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
724{
725 OBJECT_ATTRIBUTES ObjAttr;
726 UNICODE_STRING RtlStr;
727
728 RtlInitUnicodeString(&RtlStr, pName);
729 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
730
731 return ZwOpenKey(phKey, fAccess, &ObjAttr);
732}
733
734NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey)
735{
736 WCHAR Buf[512];
737 ULONG cbBuf = sizeof(Buf);
738 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDeviceExtension, VidPnSourceId, cbBuf, Buf, &cbBuf);
739 Assert(Status == STATUS_SUCCESS);
740 if (Status == STATUS_SUCCESS)
741 {
742 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
743 Assert(Status == STATUS_SUCCESS);
744 if(Status == STATUS_SUCCESS)
745 return STATUS_SUCCESS;
746 }
747
748 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
749 * basically needed to make as less modifications to the current XPDM code as possible */
750 *phKey = NULL;
751
752 return Status;
753}
754
755NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
756{
757 DWORD dwVal;
758 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
759 Assert(Status == STATUS_SUCCESS);
760 if (Status == STATUS_SUCCESS)
761 {
762 *pResult = (int)dwVal;
763 }
764
765 return Status;
766}
767
768NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
769{
770 DWORD dwVal;
771 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
772 Assert(Status == STATUS_SUCCESS);
773 if (Status == STATUS_SUCCESS)
774 {
775 *pResult = (int)dwVal;
776 }
777
778 return Status;
779}
780
781NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
782{
783 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
784 HANDLE hKey;
785 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDeviceExtension, VidPnSourceId, &hKey);
786 Assert(Status == STATUS_SUCCESS);
787 if (Status == STATUS_SUCCESS)
788 {
789 int x, y;
790 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
791 Assert(Status == STATUS_SUCCESS);
792 if (Status == STATUS_SUCCESS)
793 {
794 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
795 Assert(Status == STATUS_SUCCESS);
796 if (Status == STATUS_SUCCESS)
797 {
798 pPos->x = x;
799 pPos->y = y;
800 }
801 }
802 NTSTATUS tmpStatus = ZwClose(hKey);
803 Assert(tmpStatus == STATUS_SUCCESS);
804 }
805 return Status;
806}
807
808NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
809{
810 struct
811 {
812 KEY_VALUE_PARTIAL_INFORMATION Info;
813 UCHAR Buf[32]; /* should be enough */
814 } Buf;
815 ULONG cbBuf;
816 UNICODE_STRING RtlStr;
817 RtlInitUnicodeString(&RtlStr, pName);
818 NTSTATUS Status = ZwQueryValueKey(hKey,
819 &RtlStr,
820 KeyValuePartialInformation,
821 &Buf.Info,
822 sizeof(Buf),
823 &cbBuf);
824 if (Status == STATUS_SUCCESS)
825 {
826 if (Buf.Info.Type == REG_DWORD)
827 {
828 Assert(Buf.Info.DataLength == 4);
829 *pDword = *((PULONG)Buf.Info.Data);
830 return STATUS_SUCCESS;
831 }
832 }
833
834 return STATUS_INVALID_PARAMETER;
835}
836
837NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val)
838{
839 UNICODE_STRING RtlStr;
840 RtlInitUnicodeString(&RtlStr, pName);
841 return ZwSetValueKey(hKey, &RtlStr,
842 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
843 REG_DWORD,
844 &val,
845 sizeof(val));
846}
847
848UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt)
849{
850 if (pDevExt->VideoGuid.Buffer)
851 return &pDevExt->VideoGuid;
852
853 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
854 WCHAR VideoGuidBuf[512];
855 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
856 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
857 Assert(Status == STATUS_SUCCESS);
858 if (Status == STATUS_SUCCESS)
859 {
860 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
861 Assert(pBuf);
862 if (pBuf)
863 {
864 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
865 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
866 return &pDevExt->VideoGuid;
867 }
868 }
869
870 return NULL;
871}
872
873VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt)
874{
875 if (pDevExt->VideoGuid.Buffer)
876 {
877 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
878 pDevExt->VideoGuid.Buffer = NULL;
879 }
880}
881
882/* mm */
883
884NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
885{
886 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
887 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
888 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
889 if (!pBuf)
890 {
891 Assert(0);
892 return STATUS_NO_MEMORY;
893 }
894 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
895 pMm->cPages = cPages;
896 pMm->cAllocs = 0;
897 pMm->pBuffer = pBuf;
898 return STATUS_SUCCESS;
899}
900
901ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
902{
903 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
904 if (iPage == 0xFFFFFFFF)
905 {
906 Assert(0);
907 return VBOXWDDM_MM_VOID;
908 }
909
910 ++pMm->cAllocs;
911 return iPage;
912}
913
914VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
915{
916 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
917 RtlClearBits(&pMm->BitMap, iPage, cPages);
918 --pMm->cAllocs;
919 Assert(pMm->cAllocs < UINT32_MAX);
920}
921
922NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
923{
924 Assert(!pMm->cAllocs);
925 vboxWddmMemFree(pMm->pBuffer);
926 pMm->pBuffer = NULL;
927 return STATUS_SUCCESS;
928}
929
930
931
932typedef struct VBOXVIDEOCM_ALLOC
933{
934 VBOXWDDM_HANDLE hGlobalHandle;
935 uint32_t offData;
936 uint32_t cbData;
937} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
938
939typedef struct VBOXVIDEOCM_ALLOC_REF
940{
941 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
942 VBOXWDDM_HANDLE hSessionHandle;
943 PVBOXVIDEOCM_ALLOC pAlloc;
944 union
945 {
946 PKEVENT pSynchEvent;
947 PRKSEMAPHORE pSynchSemaphore;
948 };
949 VBOXUHGSMI_SYNCHOBJECT_TYPE enmSynchType;
950 volatile uint32_t cRefs;
951 MDL Mdl;
952} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
953
954
955NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
956{
957 NTSTATUS Status = STATUS_UNSUCCESSFUL;
958 UINT cbSize = pAlloc->cbData;
959 UINT cPages = BYTES_TO_PAGES(cbSize);
960 ExAcquireFastMutex(&pMgr->Mutex);
961 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
962 if (iPage != VBOXWDDM_MM_VOID)
963 {
964 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
965 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
966 pAlloc->offData = offData;
967 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
968 ExReleaseFastMutex(&pMgr->Mutex);
969 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
970 return STATUS_SUCCESS;
971
972 Assert(0);
973 Status = STATUS_NO_MEMORY;
974 vboxMmFree(&pMgr->Mm, iPage, cPages);
975 }
976 else
977 {
978 Assert(0);
979 ExReleaseFastMutex(&pMgr->Mutex);
980 Status = STATUS_INSUFFICIENT_RESOURCES;
981 }
982 return Status;
983}
984
985VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
986{
987 UINT cbSize = pAlloc->cbData;
988 UINT cPages = BYTES_TO_PAGES(cbSize);
989 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
990 ExAcquireFastMutex(&pMgr->Mutex);
991 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
992 vboxMmFree(&pMgr->Mm, iPage, cPages);
993 ExReleaseFastMutex(&pMgr->Mutex);
994}
995
996
997NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
998{
999 NTSTATUS Status = STATUS_SUCCESS;
1000 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
1001 if (pAlloc)
1002 {
1003 pAlloc->cbData = cbSize;
1004 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
1005 if (Status == STATUS_SUCCESS)
1006 {
1007 *ppAlloc = pAlloc;
1008 return STATUS_SUCCESS;
1009 }
1010
1011 Assert(0);
1012 vboxWddmMemFree(pAlloc);
1013 }
1014 else
1015 {
1016 Assert(0);
1017 Status = STATUS_NO_MEMORY;
1018 }
1019
1020 return Status;
1021}
1022
1023VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
1024{
1025 vboxVideoCmAllocDealloc(pMgr, pAlloc);
1026 vboxWddmMemFree(pAlloc);
1027}
1028
1029NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1030{
1031 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1032 NTSTATUS Status = STATUS_SUCCESS;
1033
1034 union
1035 {
1036 PKEVENT pSynchEvent;
1037 PRKSEMAPHORE pSynchSemaphore;
1038 };
1039
1040 switch (pUmAlloc->enmSynchType)
1041 {
1042 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
1043 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
1044 (PVOID*)&pSynchEvent,
1045 NULL);
1046 Assert(Status == STATUS_SUCCESS);
1047 Assert(pSynchEvent);
1048 break;
1049 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
1050 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExSemaphoreObjectType, UserMode,
1051 (PVOID*)&pSynchSemaphore,
1052 NULL);
1053 Assert(Status == STATUS_SUCCESS);
1054 Assert(pSynchSemaphore);
1055 break;
1056 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
1057 pSynchEvent = NULL;
1058 Status = STATUS_SUCCESS;
1059 break;
1060 default:
1061 LOGREL(("ERROR: invalid synch info type(%d)", pUmAlloc->enmSynchType));
1062 AssertBreakpoint();
1063 Status = STATUS_INVALID_PARAMETER;
1064 break;
1065 }
1066
1067 if (Status == STATUS_SUCCESS)
1068 {
1069 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
1070 SIZE_T cbLength = pAlloc->cbData;
1071
1072 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero(sizeof (*pAllocRef) + sizeof (PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
1073 if (pAllocRef)
1074 {
1075 pAllocRef->cRefs = 1;
1076 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
1077 __try
1078 {
1079 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
1080 }
1081 __except(EXCEPTION_EXECUTE_HANDLER)
1082 {
1083 Assert(0);
1084 Status = STATUS_UNSUCCESSFUL;
1085 }
1086
1087 if (Status == STATUS_SUCCESS)
1088 {
1089 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
1090 NULL, /* PVOID BaseAddress */
1091 FALSE, /* ULONG BugCheckOnFailure */
1092 NormalPagePriority);
1093 if (pvUm)
1094 {
1095 pAllocRef->pContext = pContext;
1096 pAllocRef->pAlloc = pAlloc;
1097 pAllocRef->enmSynchType = pUmAlloc->enmSynchType;
1098 pAllocRef->pSynchEvent = pSynchEvent;
1099 ExAcquireFastMutex(&pContext->Mutex);
1100 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
1101 ExReleaseFastMutex(&pContext->Mutex);
1102 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
1103 {
1104 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
1105 pUmAlloc->cbData = pAlloc->cbData;
1106 pUmAlloc->pvData = (uint64_t)pvUm;
1107 return STATUS_SUCCESS;
1108 }
1109 }
1110 else
1111 {
1112 Assert(0);
1113 Status = STATUS_INSUFFICIENT_RESOURCES;
1114 }
1115
1116 MmUnlockPages(&pAllocRef->Mdl);
1117 }
1118
1119 vboxWddmMemFree(pAllocRef);
1120 }
1121 else
1122 {
1123 Assert(0);
1124 Status = STATUS_NO_MEMORY;
1125 }
1126
1127 if (pSynchEvent)
1128 {
1129 ObDereferenceObject(pSynchEvent);
1130 }
1131 }
1132 else
1133 {
1134 Assert(0);
1135 }
1136
1137
1138 return Status;
1139}
1140
1141NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle, PVBOXVIDEOCM_ALLOC *ppAlloc)
1142{
1143 NTSTATUS Status = STATUS_SUCCESS;
1144 ExAcquireFastMutex(&pContext->Mutex);
1145 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
1146 ExReleaseFastMutex(&pContext->Mutex);
1147 if (pAllocRef)
1148 {
1149 /* wait for the dereference, i.e. for all commands involving this allocation to complete */
1150 vboxWddmCounterU32Wait(&pAllocRef->cRefs, 1);
1151
1152 MmUnlockPages(&pAllocRef->Mdl);
1153 *ppAlloc = pAllocRef->pAlloc;
1154 if (pAllocRef->pSynchEvent)
1155 {
1156 ObDereferenceObject(pAllocRef->pSynchEvent);
1157 }
1158 vboxWddmMemFree(pAllocRef);
1159 }
1160 else
1161 {
1162 Assert(0);
1163 Status = STATUS_INVALID_PARAMETER;
1164 }
1165
1166 return Status;
1167}
1168
1169static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1170{
1171 ExAcquireFastMutex(&pContext->Mutex);
1172 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
1173 ASMAtomicIncU32(&pAllocRef->cRefs);
1174 ExReleaseFastMutex(&pContext->Mutex);
1175 return pAllocRef;
1176}
1177
1178static VOID vboxVideoAMgrCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
1179{
1180 uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs);
1181 Assert(cRefs < UINT32_MAX/2);
1182 Assert(cRefs >= 1); /* we do not do cleanup-on-zero here, instead we wait for the cRefs to reach 1 in vboxVideoAMgrCtxAllocUnmap before unmapping */
1183}
1184
1185
1186
1187NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1188{
1189 PVBOXVIDEOCM_ALLOC pAlloc;
1190 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1191 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
1192 if (Status == STATUS_SUCCESS)
1193 {
1194 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
1195 if (Status == STATUS_SUCCESS)
1196 return STATUS_SUCCESS;
1197 else
1198 {
1199 Assert(0);
1200 }
1201 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1202 }
1203 else
1204 {
1205 Assert(0);
1206 }
1207 return Status;
1208}
1209
1210NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1211{
1212 PVBOXVIDEOCM_ALLOC pAlloc;
1213 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1214 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
1215 if (Status == STATUS_SUCCESS)
1216 {
1217 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1218 }
1219 else
1220 {
1221 Assert(0);
1222 }
1223 return Status;
1224}
1225
1226#ifdef VBOX_WITH_CRHGSMI
1227static DECLCALLBACK(VOID) vboxVideoAMgrAllocSubmitCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1228{
1229 /* we should be called from our DPC routine */
1230 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1231
1232 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvContext;
1233 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1234 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1235 UINT cBufs = pBody->cBuffers;
1236 for (UINT i = 0; i < cBufs; ++i)
1237 {
1238 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1239 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd->u64GuesData;
1240 if (!pBufCmd->u32GuesData)
1241 {
1242 /* signal completion */
1243 switch (pRef->enmSynchType)
1244 {
1245 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
1246 KeSetEvent(pRef->pSynchEvent, 3, FALSE);
1247 break;
1248 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
1249 KeReleaseSemaphore(pRef->pSynchSemaphore,
1250 3,
1251 1,
1252 FALSE);
1253 break;
1254 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
1255 break;
1256 default:
1257 Assert(0);
1258 }
1259 }
1260
1261 vboxVideoAMgrCtxAllocRefRelease(pRef);
1262 }
1263
1264 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1265}
1266
1267/* submits a set of chromium uhgsmi buffers to host for processing */
1268NTSTATUS vboxVideoAMgrCtxAllocSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_CONTEXT pContext, UINT cBuffers, VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *paBuffers)
1269{
1270 NTSTATUS Status = STATUS_SUCCESS;
1271 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers]));
1272
1273 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd);
1274 if (pDr)
1275 {
1276 // vboxVdmaCBufDrCreate zero initializes the pDr
1277 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
1278 pDr->cbBuf = cbCmd;
1279 pDr->rc = VERR_NOT_IMPLEMENTED;
1280
1281 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1282 pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD;
1283 pHdr->u32CmdSpecific = 0;
1284 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1285 pBody->cBuffers = cBuffers;
1286 for (UINT i = 0; i < cBuffers; ++i)
1287 {
1288 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1289 VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *pBufInfo = &paBuffers[i];
1290 PVBOXVIDEOCM_ALLOC_REF pRef = vboxVideoAMgrCtxAllocRefAcquire(pContext, pBufInfo->hAlloc);
1291 if (pRef)
1292 {
1293#ifdef DEBUG_misha
1294 Assert(pRef->cRefs == 2);
1295#endif
1296 pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData;
1297 pBufCmd->cbBuffer = pBufInfo->Info.cbData;
1298 pBufCmd->u32GuesData = pBufInfo->Info.fSubFlags.bDoNotSignalCompletion;
1299 pBufCmd->u64GuesData = (uint64_t)pRef;
1300 }
1301 else
1302 {
1303 WARN(("vboxVideoAMgrCtxAllocRefAcquire failed for hAlloc(0x%x)\n", pBufInfo->hAlloc));
1304 /* release all previously acquired aloc references */
1305 for (UINT j = 0; j < i; ++j)
1306 {
1307 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmdJ = &pBody->aBuffers[j];
1308 PVBOXVIDEOCM_ALLOC_REF pRefJ = (PVBOXVIDEOCM_ALLOC_REF)pBufCmdJ;
1309 vboxVideoAMgrCtxAllocRefRelease(pRefJ);
1310 }
1311 Status = STATUS_INVALID_PARAMETER;
1312 break;
1313 }
1314 }
1315
1316 if (Status == STATUS_SUCCESS)
1317 {
1318 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
1319 vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxVideoAMgrAllocSubmitCompletion, pDr);
1320 /* mark command as submitted & invisible for the dx runtime since dx did not originate it */
1321 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
1322 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1323 if (RT_SUCCESS(rc))
1324 {
1325 return STATUS_SUCCESS;
1326 }
1327
1328 WARN(("vboxVdmaCBufDrSubmit failed with rc (%d)\n", rc));
1329
1330 /* failure branch */
1331 /* release all previously acquired aloc references */
1332 for (UINT i = 0; i < cBuffers; ++i)
1333 {
1334 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1335 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd;
1336 vboxVideoAMgrCtxAllocRefRelease(pRef);
1337 }
1338 }
1339
1340 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1341 }
1342 else
1343 {
1344 Assert(0);
1345 /* @todo: try flushing.. */
1346 LOGREL(("vboxVdmaCBufDrCreate returned NULL"));
1347 Status = STATUS_INSUFFICIENT_RESOURCES;
1348 }
1349
1350 return Status;
1351}
1352#endif
1353
1354NTSTATUS vboxVideoAMgrCreate(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
1355{
1356 Assert(!(offData & (PAGE_SIZE -1)));
1357 Assert(!(cbData & (PAGE_SIZE -1)));
1358 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
1359 cbData &= (~(PAGE_SIZE -1));
1360 Assert(cbData);
1361 if (!cbData)
1362 return STATUS_INVALID_PARAMETER;
1363
1364 ExInitializeFastMutex(&pMgr->Mutex);
1365 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
1366 Assert(Status == STATUS_SUCCESS);
1367 if (Status == STATUS_SUCCESS)
1368 {
1369 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
1370 Assert(Status == STATUS_SUCCESS);
1371 if (Status == STATUS_SUCCESS)
1372 {
1373 PHYSICAL_ADDRESS PhysicalAddress = {0};
1374 PhysicalAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + offData;
1375 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
1376 Assert(pMgr->pvData);
1377 if (pMgr->pvData)
1378 {
1379 pMgr->offData = offData;
1380 pMgr->cbData = cbData;
1381 return STATUS_SUCCESS;
1382 }
1383 else
1384 {
1385 Status = STATUS_UNSUCCESSFUL;
1386 }
1387 vboxMmTerm(&pMgr->Mm);
1388 }
1389 vboxWddmHTableDestroy(&pMgr->AllocTable);
1390 }
1391
1392 return Status;
1393}
1394
1395NTSTATUS vboxVideoAMgrDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1396{
1397 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1398 vboxMmTerm(&pMgr->Mm);
1399 vboxWddmHTableDestroy(&pMgr->AllocTable);
1400 return STATUS_SUCCESS;
1401}
1402
1403NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1404{
1405 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1406 if (pMgr->pvData)
1407 {
1408 ExInitializeFastMutex(&pCtx->Mutex);
1409 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1410 Assert(Status == STATUS_SUCCESS);
1411 if (Status == STATUS_SUCCESS)
1412 {
1413 pCtx->pMgr = pMgr;
1414 return STATUS_SUCCESS;
1415 }
1416 }
1417 return Status;
1418}
1419
1420NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1421{
1422 if (!pCtx->pMgr)
1423 return STATUS_SUCCESS;
1424
1425 VBOXWDDM_HTABLE_ITERATOR Iter;
1426 NTSTATUS Status = STATUS_SUCCESS;
1427
1428 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1429 do
1430 {
1431 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1432 if (!pRef)
1433 break;
1434
1435 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1436 Assert(Status == STATUS_SUCCESS);
1437 if (Status != STATUS_SUCCESS)
1438 break;
1439 // vboxWddmHTableIterRemoveCur(&Iter);
1440 } while (1);
1441
1442 if (Status == STATUS_SUCCESS)
1443 {
1444 vboxWddmHTableDestroy(&pCtx->AllocTable);
1445 }
1446
1447 return Status;
1448}
1449
1450
1451VOID vboxWddmSleep(uint32_t u32Val)
1452{
1453 LARGE_INTEGER Interval;
1454 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1455
1456 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1457}
1458
1459VOID vboxWddmCounterU32Wait(uint32_t volatile * pu32, uint32_t u32Val)
1460{
1461 LARGE_INTEGER Interval;
1462 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1463 uint32_t u32CurVal;
1464
1465 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1466
1467 while ((u32CurVal = ASMAtomicReadU32(pu32)) != u32Val)
1468 {
1469 Assert(u32CurVal >= u32Val);
1470 Assert(u32CurVal < UINT32_MAX/2);
1471
1472 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1473 }
1474}
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