VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/wddm/VBoxVideoMisc.cpp@ 34345

Last change on this file since 34345 was 34345, checked in by vboxsync, 14 years ago

wddm/3d: propper hide host window on swapchain destruction

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.4 KB
Line 
1/*
2 * Copyright (C) 2010 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 */
12
13#include "../VBoxVideo-win.h"
14#include "../Helper.h"
15
16#include <iprt/asm.h>
17
18#include <stdio.h>
19
20NTSTATUS vboxWddmHTableCreate(PVBOXWDDM_HTABLE pTbl, uint32_t cSize)
21{
22 memset(pTbl, 0, sizeof (*pTbl));
23 pTbl->paData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cSize);
24 if (pTbl->paData)
25 {
26 pTbl->cSize = cSize;
27 return STATUS_SUCCESS;
28 }
29 return STATUS_NO_MEMORY;
30}
31
32VOID vboxWddmHTableDestroy(PVBOXWDDM_HTABLE pTbl)
33{
34 vboxWddmMemFree(pTbl->paData);
35}
36
37DECLINLINE(VBOXWDDM_HANDLE) vboxWddmHTableIndex2Handle(uint32_t iIndex)
38{
39 return iIndex+1;
40}
41
42DECLINLINE(uint32_t) vboxWddmHTableHandle2Index(VBOXWDDM_HANDLE hHandle)
43{
44 return hHandle-1;
45}
46
47NTSTATUS vboxWddmHTableRealloc(PVBOXWDDM_HTABLE pTbl, uint32_t cNewSize)
48{
49 Assert(cNewSize > pTbl->cSize);
50 if (cNewSize > pTbl->cSize)
51 {
52 PVOID *pvNewData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cNewSize);
53 memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize);
54 pTbl->iNext2Search = pTbl->cSize;
55 pTbl->cSize = cNewSize;
56 pTbl->paData = pvNewData;
57 return STATUS_SUCCESS;
58 }
59 else if (cNewSize >= pTbl->cData)
60 return STATUS_NOT_IMPLEMENTED;
61 return STATUS_INVALID_PARAMETER;
62
63}
64VBOXWDDM_HANDLE vboxWddmHTablePut(PVBOXWDDM_HTABLE pTbl, PVOID pvData)
65{
66 if (pTbl->cSize == pTbl->cData)
67 {
68 Assert(0);
69 NTSTATUS Status = vboxWddmHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4));
70 Assert(Status == STATUS_SUCCESS);
71 if (Status != STATUS_SUCCESS)
72 return VBOXWDDM_HANDLE_INVALID;
73 }
74 for (UINT i = pTbl->iNext2Search; ; ++i, i %= pTbl->cSize)
75 {
76 Assert(i < pTbl->cSize);
77 if (!pTbl->paData[i])
78 {
79 pTbl->paData[i] = pvData;
80 ++pTbl->cData;
81 Assert(pTbl->cData <= pTbl->cSize);
82 ++pTbl->iNext2Search;
83 pTbl->iNext2Search %= pTbl->cSize;
84 return vboxWddmHTableIndex2Handle(i);
85 }
86 }
87 Assert(0);
88 return VBOXWDDM_HANDLE_INVALID;
89}
90
91PVOID vboxWddmHTableRemove(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
92{
93 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
94 Assert(iIndex < pTbl->cSize);
95 if (iIndex < pTbl->cSize)
96 {
97 PVOID pvData = pTbl->paData[iIndex];
98 pTbl->paData[iIndex] = NULL;
99 --pTbl->cData;
100 Assert(pTbl->cData <= pTbl->cSize);
101 pTbl->iNext2Search = iIndex;
102 return pvData;
103 }
104 return NULL;
105}
106
107PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
108{
109 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
110 Assert(iIndex < pTbl->cSize);
111 if (iIndex < pTbl->cSize)
112 return pTbl->paData[iIndex];
113 return NULL;
114}
115
116VOID vboxWddmHTableIterInit(PVBOXWDDM_HTABLE pTbl, PVBOXWDDM_HTABLE_ITERATOR pIter)
117{
118 pIter->pTbl = pTbl;
119 pIter->iCur = ~0UL;
120 pIter->cLeft = pTbl->cData;
121}
122
123BOOL vboxWddmHTableIterHasNext(PVBOXWDDM_HTABLE_ITERATOR pIter)
124{
125 return pIter->cLeft;
126}
127
128
129PVOID vboxWddmHTableIterNext(PVBOXWDDM_HTABLE_ITERATOR pIter, VBOXWDDM_HANDLE *phHandle)
130{
131 if (vboxWddmHTableIterHasNext(pIter))
132 {
133 for (uint32_t i = pIter->iCur+1; i < pIter->pTbl->cSize ; ++i)
134 {
135 if (pIter->pTbl->paData[i])
136 {
137 pIter->iCur = i;
138 --pIter->cLeft;
139 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(i);
140 Assert(hHandle);
141 if (phHandle)
142 *phHandle = hHandle;
143 return pIter->pTbl->paData[i];
144 }
145 }
146 }
147
148 Assert(!vboxWddmHTableIterHasNext(pIter));
149 if (phHandle)
150 *phHandle = VBOXWDDM_HANDLE_INVALID;
151 return NULL;
152}
153
154
155PVOID vboxWddmHTableIterRemoveCur(PVBOXWDDM_HTABLE_ITERATOR pIter)
156{
157 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(pIter->iCur);
158 Assert(hHandle);
159 if (hHandle)
160 {
161 PVOID pRet = vboxWddmHTableRemove(pIter->pTbl, hHandle);
162 Assert(pRet);
163 return pRet;
164 }
165 return NULL;
166}
167
168PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate()
169{
170 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmMemAllocZero(sizeof (VBOXWDDM_SWAPCHAIN));
171 Assert(pSwapchain);
172 if (pSwapchain)
173 {
174 InitializeListHead(&pSwapchain->AllocList);
175 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_INITIALIZED;
176 pSwapchain->cRefs = 1;
177 }
178 return pSwapchain;
179}
180
181DECLINLINE(BOOLEAN) vboxWddmSwapchainRetainLocked(PVBOXWDDM_SWAPCHAIN pSwapchain)
182{
183 if (pSwapchain->enmState == VBOXWDDM_OBJSTATE_TYPE_INITIALIZED)
184 {
185 ASMAtomicIncU32(&pSwapchain->cRefs);
186 return TRUE;
187 }
188 return FALSE;
189}
190
191DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
192{
193 KIRQL OldIrql;
194 BOOLEAN bRc;
195 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
196 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
197 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
198 return bRc;
199}
200
201DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain)
202{
203 uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs);
204 Assert(cRefs < UINT32_MAX/2);
205 if (!cRefs)
206 {
207 Assert(pSwapchain->pContext);
208 if (pSwapchain->pContext)
209 {
210 NTSTATUS tmpStatus = vboxVdmaPostHideSwapchain(pSwapchain);
211 Assert(tmpStatus == STATUS_SUCCESS);
212 }
213 vboxWddmMemFree(pSwapchain);
214 }
215}
216
217PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
218{
219 KIRQL OldIrql;
220 PVBOXWDDM_SWAPCHAIN pSwapchain;
221 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
222 pSwapchain = pAlloc->pSwapchain;
223 if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain))
224 pSwapchain = NULL;
225 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
226 return pSwapchain;
227}
228
229VOID vboxWddmSwapchainAllocRemove(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
230{
231 KIRQL OldIrql;
232 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
233 Assert(pAlloc->pSwapchain == pSwapchain);
234 pAlloc->pSwapchain = NULL;
235 RemoveEntryList(&pAlloc->SwapchainEntry);
236 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
237 vboxWddmSwapchainRelease(pSwapchain);
238}
239
240BOOLEAN vboxWddmSwapchainAllocAdd(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
241{
242 KIRQL OldIrql;
243 BOOLEAN bRc;
244 Assert(!pAlloc->pSwapchain);
245 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
246 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
247 if (bRc)
248 {
249 if (pAlloc->pSwapchain)
250 {
251 RemoveEntryList(&pAlloc->SwapchainEntry);
252 }
253 InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry);
254 pAlloc->pSwapchain = pSwapchain;
255 }
256 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
257 return bRc;
258}
259
260#define VBOXSCENTRY_2_ALLOC(_pE) ((PVBOXWDDM_ALLOCATION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, SwapchainEntry)))
261
262static VOID vboxWddmSwapchainAllocRemoveAllInternal(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, BOOLEAN bOnDestroy)
263{
264 KIRQL OldIrql;
265 UINT cRemoved = 0;
266 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
267 PLIST_ENTRY pEntry = pSwapchain->AllocList.Flink;
268 do
269 {
270 if (pEntry != &pSwapchain->AllocList)
271 {
272 PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry);
273 pEntry = pEntry->Flink;
274 Assert(pAlloc->pSwapchain == pSwapchain);
275 pAlloc->pSwapchain = NULL;
276 RemoveEntryList(&pAlloc->SwapchainEntry);
277 ++cRemoved;
278 }
279 else
280 break;
281 } while (1);
282
283 if (bOnDestroy)
284 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_TERMINATED;
285 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
286
287 for (UINT i = 0; i < cRemoved; ++i)
288 vboxWddmSwapchainRelease(pSwapchain);
289}
290
291VOID vboxWddmSwapchainAllocRemoveAll(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
292{
293 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, FALSE);
294}
295
296VOID vboxWddmSwapchainDestroy(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
297{
298 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE);
299 vboxWddmSwapchainRelease(pSwapchain);
300}
301
302static BOOLEAN vboxWddmSwapchainCtxAddLocked(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
303{
304 if (vboxWddmSwapchainRetain(pDevExt, pSwapchain))
305 {
306 Assert(!pSwapchain->hSwapchainKm);
307 Assert(!pSwapchain->pContext);
308 pSwapchain->pContext = pContext;
309 pSwapchain->hSwapchainKm = vboxWddmHTablePut(&pContext->Swapchains, pSwapchain);
310 InsertHeadList(&pDevExt->SwapchainList3D, &pSwapchain->DevExtListEntry);
311 return TRUE;
312 }
313 return FALSE;
314}
315
316static VOID vboxWddmSwapchainCtxRemoveLocked(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
317{
318 Assert(pSwapchain->hSwapchainKm);
319 Assert(pSwapchain->pContext);
320 void * pTst = vboxWddmHTableRemove(&pContext->Swapchains, pSwapchain->hSwapchainKm);
321 Assert(pTst == pSwapchain);
322 RemoveEntryList(&pSwapchain->DevExtListEntry);
323// pSwapchain->pContext = NULL;
324 pSwapchain->hSwapchainKm = NULL;
325 if (pSwapchain->pLastReportedRects)
326 {
327 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
328 pSwapchain->pLastReportedRects = NULL;
329 }
330 vboxWddmSwapchainRelease(pSwapchain);
331}
332
333BOOLEAN vboxWddmSwapchainCtxAdd(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
334{
335 BOOLEAN bRc;
336 ExAcquireFastMutex(&pDevExt->ContextMutex);
337 bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
338 ExReleaseFastMutex(&pDevExt->ContextMutex);
339 return bRc;
340}
341
342VOID vboxWddmSwapchainCtxRemove(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
343{
344 ExAcquireFastMutex(&pDevExt->ContextMutex);
345 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
346 ExReleaseFastMutex(&pDevExt->ContextMutex);
347}
348
349VOID vboxWddmSwapchainCtxDestroyAll(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext)
350{
351 VBOXWDDM_HTABLE_ITERATOR Iter;
352 ExAcquireFastMutex(&pDevExt->ContextMutex);
353 vboxWddmHTableIterInit(&pContext->Swapchains, &Iter);
354 do
355 {
356 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL);
357 if (!pSwapchain)
358 break;
359
360 /* yes, we can call remove locked even when using iterator */
361 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
362// vboxWddmHTableIterRemoveCur(&Iter);
363
364 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
365 } while (1);
366 ExReleaseFastMutex(&pDevExt->ContextMutex);
367}
368
369NTSTATUS vboxWddmSwapchainCtxEscape(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize)
370{
371 Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])));
372 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
373 return STATUS_INVALID_PARAMETER;
374 Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]));
375 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
376 return STATUS_INVALID_PARAMETER;
377
378 PVBOXWDDM_SWAPCHAIN pSwapchain;
379 PVBOXWDDM_ALLOCATION *apAlloc = NULL;
380 if (pSwapchainInfo->SwapchainInfo.cAllocs)
381 {
382 apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
383 Assert(apAlloc);
384 if (!apAlloc)
385 return STATUS_NO_MEMORY;
386 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
387 {
388 DXGKARGCB_GETHANDLEDATA GhData;
389 GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
390 GhData.Type = DXGK_HANDLE_ALLOCATION;
391 GhData.Flags.Value = 0;
392 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
393 Assert(pAlloc);
394 if (!pAlloc)
395 return STATUS_INVALID_PARAMETER;
396 apAlloc[i] = pAlloc;
397 }
398 }
399
400 if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
401 {
402// ExAcquireFastMutex(&pContext->SwapchainMutex);
403 ExAcquireFastMutex(&pDevExt->ContextMutex);
404 pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
405 Assert(pSwapchain);
406 if (!pSwapchain)
407 {
408 ExReleaseFastMutex(&pDevExt->ContextMutex);
409 return STATUS_INVALID_PARAMETER;
410 }
411 Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
412 Assert(pSwapchain->pContext == pContext);
413 if (pSwapchain->pContext != pContext)
414 {
415 ExReleaseFastMutex(&pDevExt->ContextMutex);
416 return STATUS_INVALID_PARAMETER;
417 }
418 }
419 else if (pSwapchainInfo->SwapchainInfo.cAllocs)
420 {
421 pSwapchain = vboxWddmSwapchainCreate();
422 if (!pSwapchain)
423 return STATUS_NO_MEMORY;
424
425 ExAcquireFastMutex(&pDevExt->ContextMutex);
426 BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
427 Assert(bRc);
428 }
429 else
430 return STATUS_INVALID_PARAMETER;
431
432 memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
433 if (pSwapchain->pLastReportedRects)
434 {
435 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
436 pSwapchain->pLastReportedRects = NULL;
437 }
438
439 vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);
440
441 if (pSwapchainInfo->SwapchainInfo.cAllocs)
442 {
443 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
444 {
445 vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
446 }
447 pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
448 }
449 else
450 {
451 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
452 }
453
454// ExReleaseFastMutex(&pContext->SwapchainMutex);
455 ExReleaseFastMutex(&pDevExt->ContextMutex);
456
457 if (pSwapchainInfo->SwapchainInfo.cAllocs)
458 {
459 Assert(pSwapchain->pContext);
460 Assert(pSwapchain->hSwapchainKm);
461 pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
462 }
463 else
464 {
465 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
466 pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
467 }
468
469 return STATUS_SUCCESS;
470}
471
472#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
473
474NTSTATUS vboxWddmRegQueryDrvKeyName(PDEVICE_EXTENSION pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
475{
476 WCHAR fallBackBuf[2];
477 PWCHAR pSuffix;
478 bool bFallback = false;
479
480 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
481 {
482 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
483 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
484 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
485 }
486 else
487 {
488 pSuffix = fallBackBuf;
489 cbBuf = sizeof (fallBackBuf);
490 bFallback = true;
491 }
492
493 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
494 DevicePropertyDriverKeyName,
495 cbBuf,
496 pSuffix,
497 &cbBuf);
498 if (Status == STATUS_SUCCESS && bFallback)
499 Status = STATUS_BUFFER_TOO_SMALL;
500 if (Status == STATUS_BUFFER_TOO_SMALL)
501 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
502
503 return Status;
504}
505
506#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\"
507#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\"
508
509#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX"
510#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY"
511#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop"
512
513NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PDEVICE_EXTENSION pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
514 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
515{
516 NTSTATUS Status = STATUS_SUCCESS;
517 PWCHAR pSuffix;
518 bool bFallback = false;
519 const WCHAR* pKeyPrefix;
520 UINT cbKeyPrefix;
521 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
522 Assert(pVGuid);
523 if (!pVGuid)
524 return STATUS_UNSUCCESSFUL;
525
526 winVersion_t ver = vboxQueryWinVersion();
527 if (ver == WINVISTA)
528 {
529 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
530 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
531 }
532 else
533 {
534 Assert(ver == WIN7);
535 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
536 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
537 }
538
539 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
540 if (cbBuf >= cbResult)
541 {
542 wcscpy(pBuf, pKeyPrefix);
543 pSuffix = pBuf + (cbKeyPrefix-2)/2;
544 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
545 pSuffix += pVGuid->Length/2;
546 pSuffix[0] = L'\\';
547 pSuffix += 1;
548 swprintf(pSuffix, L"%04d", VidPnSourceId);
549 }
550 else
551 {
552 Status = STATUS_BUFFER_TOO_SMALL;
553 }
554
555 *pcbResult = cbResult;
556
557 return Status;
558}
559
560#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\"
561#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video"
562
563NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
564{
565 HANDLE hKey;
566 NTSTATUS Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
567 Assert(Status == STATUS_SUCCESS);
568 if (Status == STATUS_SUCCESS)
569 {
570 struct
571 {
572 KEY_BASIC_INFORMATION Name;
573 WCHAR Buf[256];
574 } Buf;
575 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
576 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
577 ULONG ResultLength;
578 BOOL bFound = FALSE;
579 for (ULONG i = 0; !bFound; ++i)
580 {
581 RtlZeroMemory(&Buf, sizeof (Buf));
582 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
583 Assert(Status == STATUS_SUCCESS);
584 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
585 if (Status != STATUS_SUCCESS)
586 break;
587
588 HANDLE hSubKey;
589 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
590 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
591 pSubBuf += Buf.Name.NameLength/2;
592 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
593 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
594 Assert(Status == STATUS_SUCCESS);
595 if (Status == STATUS_SUCCESS)
596 {
597 struct
598 {
599 KEY_VALUE_PARTIAL_INFORMATION Info;
600 UCHAR Buf[sizeof (L"VBoxVideoWddm")]; /* should be enough */
601 } KeyData;
602 ULONG cbResult;
603 UNICODE_STRING RtlStr;
604 RtlInitUnicodeString(&RtlStr, L"Service");
605 Status = ZwQueryValueKey(hSubKey,
606 &RtlStr,
607 KeyValuePartialInformation,
608 &KeyData.Info,
609 sizeof(KeyData),
610 &cbResult);
611 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
612 if (Status == STATUS_SUCCESS)
613 {
614 if (KeyData.Info.Type == REG_SZ)
615 {
616 if (KeyData.Info.DataLength == sizeof (L"VBoxVideoWddm"))
617 {
618 if (!wcscmp(L"VBoxVideoWddm", (PWCHAR)KeyData.Info.Data))
619 {
620 bFound = TRUE;
621 *pcbResult = Buf.Name.NameLength + 2;
622 if (cbBuf >= Buf.Name.NameLength + 2)
623 {
624 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
625 }
626 else
627 {
628 Status = STATUS_BUFFER_TOO_SMALL;
629 }
630 }
631 }
632 }
633 }
634
635 NTSTATUS tmpStatus = ZwClose(hSubKey);
636 Assert(tmpStatus == STATUS_SUCCESS);
637 }
638 else
639 break;
640 }
641 NTSTATUS tmpStatus = ZwClose(hKey);
642 Assert(tmpStatus == STATUS_SUCCESS);
643 }
644
645 return Status;
646}
647
648NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
649{
650 OBJECT_ATTRIBUTES ObjAttr;
651 UNICODE_STRING RtlStr;
652
653 RtlInitUnicodeString(&RtlStr, pName);
654 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
655
656 return ZwOpenKey(phKey, fAccess, &ObjAttr);
657}
658
659NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PDEVICE_EXTENSION pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey)
660{
661 WCHAR Buf[512];
662 ULONG cbBuf = sizeof(Buf);
663 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDeviceExtension, VidPnSourceId, cbBuf, Buf, &cbBuf);
664 Assert(Status == STATUS_SUCCESS);
665 if (Status == STATUS_SUCCESS)
666 {
667 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
668 Assert(Status == STATUS_SUCCESS);
669 if(Status == STATUS_SUCCESS)
670 return STATUS_SUCCESS;
671 }
672
673 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
674 * basically needed to make as less modifications to the current XPDM code as possible */
675 *phKey = NULL;
676
677 return Status;
678}
679
680NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
681{
682 DWORD dwVal;
683 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
684 Assert(Status == STATUS_SUCCESS);
685 if (Status == STATUS_SUCCESS)
686 {
687 *pResult = (int)dwVal;
688 }
689
690 return Status;
691}
692
693NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
694{
695 DWORD dwVal;
696 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
697 Assert(Status == STATUS_SUCCESS);
698 if (Status == STATUS_SUCCESS)
699 {
700 *pResult = (int)dwVal;
701 }
702
703 return Status;
704}
705
706NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PDEVICE_EXTENSION pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
707{
708 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
709 HANDLE hKey;
710 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDeviceExtension, VidPnSourceId, &hKey);
711 Assert(Status == STATUS_SUCCESS);
712 if (Status == STATUS_SUCCESS)
713 {
714 int x, y;
715 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
716 Assert(Status == STATUS_SUCCESS);
717 if (Status == STATUS_SUCCESS)
718 {
719 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
720 Assert(Status == STATUS_SUCCESS);
721 if (Status == STATUS_SUCCESS)
722 {
723 pPos->x = x;
724 pPos->y = y;
725 }
726 }
727 NTSTATUS tmpStatus = ZwClose(hKey);
728 Assert(tmpStatus == STATUS_SUCCESS);
729 }
730 return Status;
731}
732
733NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
734{
735 struct
736 {
737 KEY_VALUE_PARTIAL_INFORMATION Info;
738 UCHAR Buf[32]; /* should be enough */
739 } Buf;
740 ULONG cbBuf;
741 UNICODE_STRING RtlStr;
742 RtlInitUnicodeString(&RtlStr, pName);
743 NTSTATUS Status = ZwQueryValueKey(hKey,
744 &RtlStr,
745 KeyValuePartialInformation,
746 &Buf.Info,
747 sizeof(Buf),
748 &cbBuf);
749 if (Status == STATUS_SUCCESS)
750 {
751 if (Buf.Info.Type == REG_DWORD)
752 {
753 Assert(Buf.Info.DataLength == 4);
754 *pDword = *((PULONG)Buf.Info.Data);
755 return STATUS_SUCCESS;
756 }
757 }
758
759 return STATUS_INVALID_PARAMETER;
760}
761
762NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val)
763{
764 UNICODE_STRING RtlStr;
765 RtlInitUnicodeString(&RtlStr, pName);
766 return ZwSetValueKey(hKey, &RtlStr,
767 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
768 REG_DWORD,
769 &val,
770 sizeof(val));
771}
772
773UNICODE_STRING* vboxWddmVGuidGet(PDEVICE_EXTENSION pDevExt)
774{
775 if (pDevExt->VideoGuid.Buffer)
776 return &pDevExt->VideoGuid;
777
778 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
779 WCHAR VideoGuidBuf[512];
780 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
781 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
782 Assert(Status == STATUS_SUCCESS);
783 if (Status == STATUS_SUCCESS)
784 {
785 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
786 Assert(pBuf);
787 if (pBuf)
788 {
789 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
790 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
791 return &pDevExt->VideoGuid;
792 }
793 }
794
795 return NULL;
796}
797
798VOID vboxWddmVGuidFree(PDEVICE_EXTENSION pDevExt)
799{
800 if (pDevExt->VideoGuid.Buffer)
801 {
802 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
803 pDevExt->VideoGuid.Buffer = NULL;
804 }
805}
806
807/* mm */
808
809NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
810{
811 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
812 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
813 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
814 if (!pBuf)
815 {
816 Assert(0);
817 return STATUS_NO_MEMORY;
818 }
819 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
820 pMm->cPages = cPages;
821 pMm->cAllocs = 0;
822 pMm->pBuffer = pBuf;
823 return STATUS_SUCCESS;
824}
825
826ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
827{
828 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
829 if (iPage == 0xFFFFFFFF)
830 {
831 Assert(0);
832 return VBOXWDDM_MM_VOID;
833 }
834
835 ++pMm->cAllocs;
836 return iPage;
837}
838
839VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
840{
841 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
842 RtlClearBits(&pMm->BitMap, iPage, cPages);
843 --pMm->cAllocs;
844 Assert(pMm->cAllocs < UINT32_MAX);
845}
846
847NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
848{
849 Assert(!pMm->cAllocs);
850 vboxWddmMemFree(pMm->pBuffer);
851 pMm->pBuffer = NULL;
852 return STATUS_SUCCESS;
853}
854
855
856
857typedef struct VBOXVIDEOCM_ALLOC
858{
859 VBOXWDDM_HANDLE hGlobalHandle;
860 uint32_t offData;
861 uint32_t cbData;
862} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
863
864typedef struct VBOXVIDEOCM_ALLOC_REF
865{
866 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
867 VBOXWDDM_HANDLE hSessionHandle;
868 PVBOXVIDEOCM_ALLOC pAlloc;
869 union
870 {
871 PKEVENT pSynchEvent;
872 PRKSEMAPHORE pSynchSemaphore;
873 };
874 VBOXUHGSMI_SYNCHOBJECT_TYPE enmSynchType;
875 MDL Mdl;
876} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
877
878
879NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
880{
881 NTSTATUS Status = STATUS_UNSUCCESSFUL;
882 UINT cbSize = pAlloc->cbData;
883 UINT cPages = BYTES_TO_PAGES(cbSize);
884 ExAcquireFastMutex(&pMgr->Mutex);
885 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
886 if (iPage != VBOXWDDM_MM_VOID)
887 {
888 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
889 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
890 pAlloc->offData = offData;
891 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
892 ExReleaseFastMutex(&pMgr->Mutex);
893 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
894 return STATUS_SUCCESS;
895
896 Assert(0);
897 Status = STATUS_NO_MEMORY;
898 vboxMmFree(&pMgr->Mm, iPage, cPages);
899 }
900 else
901 {
902 Assert(0);
903 ExReleaseFastMutex(&pMgr->Mutex);
904 Status = STATUS_INSUFFICIENT_RESOURCES;
905 }
906 return Status;
907}
908
909VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
910{
911 UINT cbSize = pAlloc->cbData;
912 UINT cPages = BYTES_TO_PAGES(cbSize);
913 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
914 ExAcquireFastMutex(&pMgr->Mutex);
915 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
916 vboxMmFree(&pMgr->Mm, iPage, cPages);
917 ExReleaseFastMutex(&pMgr->Mutex);
918}
919
920
921NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
922{
923 NTSTATUS Status = STATUS_SUCCESS;
924 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
925 if (pAlloc)
926 {
927 pAlloc->cbData = cbSize;
928 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
929 if (Status == STATUS_SUCCESS)
930 {
931 *ppAlloc = pAlloc;
932 return STATUS_SUCCESS;
933 }
934
935 Assert(0);
936 vboxWddmMemFree(pAlloc);
937 }
938 else
939 {
940 Assert(0);
941 Status = STATUS_NO_MEMORY;
942 }
943
944 return Status;
945}
946
947VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
948{
949 vboxVideoCmAllocDealloc(pMgr, pAlloc);
950 vboxWddmMemFree(pAlloc);
951}
952
953NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
954{
955 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
956 NTSTATUS Status = STATUS_SUCCESS;
957
958 union
959 {
960 PKEVENT pSynchEvent;
961 PRKSEMAPHORE pSynchSemaphore;
962 };
963
964 switch (pUmAlloc->enmSynchType)
965 {
966 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
967 Status = ObReferenceObjectByHandle(pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
968 (PVOID*)&pSynchEvent,
969 NULL);
970 Assert(Status == STATUS_SUCCESS);
971 break;
972 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
973 Status = ObReferenceObjectByHandle(pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExSemaphoreObjectType, UserMode,
974 (PVOID*)&pSynchSemaphore,
975 NULL);
976 Assert(Status == STATUS_SUCCESS);
977 break;
978 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
979 pSynchEvent = NULL;
980 Status = STATUS_SUCCESS;
981 break;
982 default:
983 drprintf((__FUNCTION__ ": ERROR: invalid synch info type(%d)\n", pUmAlloc->enmSynchType));
984 AssertBreakpoint();
985 Status = STATUS_INVALID_PARAMETER;
986 break;
987 }
988
989 if (Status == STATUS_SUCCESS)
990 {
991 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
992 SIZE_T cbLength = pAlloc->cbData;
993
994 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero(sizeof (*pAllocRef) + sizeof (PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
995 if (pAllocRef)
996 {
997 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
998 __try
999 {
1000 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
1001 }
1002 __except(EXCEPTION_EXECUTE_HANDLER)
1003 {
1004 Assert(0);
1005 Status = STATUS_UNSUCCESSFUL;
1006 }
1007
1008 if (Status == STATUS_SUCCESS)
1009 {
1010 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
1011 NULL, /* PVOID BaseAddress */
1012 FALSE, /* ULONG BugCheckOnFailure */
1013 NormalPagePriority);
1014 if (pvUm)
1015 {
1016 pAllocRef->pContext = pContext;
1017 pAllocRef->pAlloc = pAlloc;
1018 pAllocRef->enmSynchType = pUmAlloc->enmSynchType;
1019 pAllocRef->pSynchEvent = pSynchEvent;
1020 ExAcquireFastMutex(&pContext->Mutex);
1021 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
1022 ExReleaseFastMutex(&pContext->Mutex);
1023 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
1024 {
1025 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
1026 pUmAlloc->cbData = pAlloc->cbData;
1027 pUmAlloc->pvData = (uint8_t*)pvUm;
1028 return STATUS_SUCCESS;
1029 }
1030 }
1031 else
1032 {
1033 Assert(0);
1034 Status = STATUS_INSUFFICIENT_RESOURCES;
1035 }
1036
1037 MmUnlockPages(&pAllocRef->Mdl);
1038 }
1039
1040 vboxWddmMemFree(pAllocRef);
1041 }
1042 else
1043 {
1044 Assert(0);
1045 Status = STATUS_NO_MEMORY;
1046 }
1047
1048 if (pSynchEvent)
1049 {
1050 ObDereferenceObject(pSynchEvent);
1051 }
1052 }
1053 else
1054 {
1055 Assert(0);
1056 }
1057
1058
1059 return Status;
1060}
1061
1062NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle, PVBOXVIDEOCM_ALLOC *ppAlloc)
1063{
1064 NTSTATUS Status = STATUS_SUCCESS;
1065 ExAcquireFastMutex(&pContext->Mutex);
1066 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
1067 ExReleaseFastMutex(&pContext->Mutex);
1068 if (pAllocRef)
1069 {
1070 MmUnlockPages(&pAllocRef->Mdl);
1071 *ppAlloc = pAllocRef->pAlloc;
1072 if (pAllocRef->pSynchEvent)
1073 {
1074 ObDereferenceObject(pAllocRef->pSynchEvent);
1075 }
1076 vboxWddmMemFree(pAllocRef);
1077 }
1078 else
1079 {
1080 Assert(0);
1081 Status = STATUS_INVALID_PARAMETER;
1082 }
1083
1084 return Status;
1085}
1086
1087static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1088{
1089 ExAcquireFastMutex(&pContext->Mutex);
1090 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
1091 ExReleaseFastMutex(&pContext->Mutex);
1092 return pAllocRef;
1093}
1094
1095static VOID vboxVideoCmCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
1096{
1097
1098}
1099
1100
1101
1102NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1103{
1104 PVBOXVIDEOCM_ALLOC pAlloc;
1105 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1106 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
1107 if (Status == STATUS_SUCCESS)
1108 {
1109 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
1110 if (Status == STATUS_SUCCESS)
1111 return STATUS_SUCCESS;
1112 else
1113 {
1114 Assert(0);
1115 }
1116 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1117 }
1118 else
1119 {
1120 Assert(0);
1121 }
1122 return Status;
1123}
1124
1125NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1126{
1127 PVBOXVIDEOCM_ALLOC pAlloc;
1128 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1129 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
1130 if (Status == STATUS_SUCCESS)
1131 {
1132 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1133 }
1134 else
1135 {
1136 Assert(0);
1137 }
1138 return Status;
1139}
1140
1141#ifdef VBOX_WITH_VDMA
1142static DECLCALLBACK(VOID) vboxVideoAMgrAllocSubmitCompletion(PDEVICE_EXTENSION pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1143{
1144 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvContext;
1145 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1146 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1147 UINT cBufs = pBody->cBuffers;
1148 for (UINT i = 0; i < cBufs; ++i)
1149 {
1150 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1151 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd->u64GuesData;
1152 if (!pBufCmd->u32GuesData)
1153 {
1154 /* signal completion */
1155 switch (pRef->enmSynchType)
1156 {
1157 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
1158 KeSetEvent(pRef->pSynchEvent, 3, FALSE);
1159 break;
1160 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
1161 KeReleaseSemaphore(pRef->pSynchSemaphore,
1162 3,
1163 1,
1164 FALSE);
1165 break;
1166 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
1167 break;
1168 default:
1169 Assert(0);
1170 }
1171 }
1172
1173 vboxVideoCmCtxAllocRefRelease(pRef);
1174 }
1175
1176 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1177}
1178
1179NTSTATUS vboxVideoAMgrCtxAllocSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_CONTEXT pContext, UINT cBuffers, VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *paBuffers)
1180{
1181 NTSTATUS Status = STATUS_SUCCESS;
1182 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers]));
1183
1184 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd);
1185 if (pDr)
1186 {
1187 // vboxVdmaCBufDrCreate zero initializes the pDr
1188 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
1189 pDr->cbBuf = cbCmd;
1190 pDr->rc = VERR_NOT_IMPLEMENTED;
1191
1192 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1193 pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD;
1194 pHdr->u32CmdSpecific = 0;
1195 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1196 pBody->cBuffers = cBuffers;
1197 for (UINT i = 0; i < cBuffers; ++i)
1198 {
1199 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1200 VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *pBufInfo = &paBuffers[i];
1201 PVBOXVIDEOCM_ALLOC_REF pRef = vboxVideoAMgrCtxAllocRefAcquire(pContext, pBufInfo->hAlloc);
1202 if (pRef)
1203 {
1204 pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData;
1205 pBufCmd->cbBuffer = pBufInfo->Info.cbData;
1206 pBufCmd->u32GuesData = pBufInfo->Info.fSubFlags.bDoNotSignalCompletion;
1207 pBufCmd->u64GuesData = (uint64_t)pRef;
1208 }
1209 else
1210 {
1211 Assert(0);
1212 Status = STATUS_INVALID_PARAMETER;
1213 break;
1214 }
1215 }
1216
1217 if (Status == STATUS_SUCCESS)
1218 {
1219 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
1220 vboxVdmaDdiCmdInit(pDdiCmd, 0, NULL, vboxVideoAMgrAllocSubmitCompletion, pDr);
1221 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
1222 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1223 Assert(rc == VINF_SUCCESS);
1224 if (RT_SUCCESS(rc))
1225 {
1226 return STATUS_SUCCESS;
1227 }
1228 }
1229
1230 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1231 }
1232 else
1233 {
1234 Assert(0);
1235 /* @todo: try flushing.. */
1236 drprintf((__FUNCTION__": vboxVdmaCBufDrCreate returned NULL\n"));
1237 Status = STATUS_INSUFFICIENT_RESOURCES;
1238 }
1239
1240 return Status;
1241}
1242#endif
1243
1244NTSTATUS vboxVideoAMgrCreate(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
1245{
1246 Assert(!(offData & (PAGE_SIZE -1)));
1247 Assert(!(cbData & (PAGE_SIZE -1)));
1248 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
1249 cbData &= (~(PAGE_SIZE -1));
1250 Assert(cbData);
1251 if (!cbData)
1252 return STATUS_INVALID_PARAMETER;
1253
1254 ExInitializeFastMutex(&pMgr->Mutex);
1255 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
1256 Assert(Status == STATUS_SUCCESS);
1257 if (Status == STATUS_SUCCESS)
1258 {
1259 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
1260 Assert(Status == STATUS_SUCCESS);
1261 if (Status == STATUS_SUCCESS)
1262 {
1263 PHYSICAL_ADDRESS PhysicalAddress = {0};
1264 PhysicalAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + offData;
1265 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
1266 Assert(pMgr->pvData);
1267 if (pMgr->pvData)
1268 {
1269 pMgr->offData = offData;
1270 pMgr->cbData = cbData;
1271 return STATUS_SUCCESS;
1272 }
1273 else
1274 {
1275 Status = STATUS_UNSUCCESSFUL;
1276 }
1277 vboxMmTerm(&pMgr->Mm);
1278 }
1279 vboxWddmHTableDestroy(&pMgr->AllocTable);
1280 }
1281
1282 return Status;
1283}
1284
1285NTSTATUS vboxVideoAMgrDestroy(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1286{
1287 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1288 vboxMmTerm(&pMgr->Mm);
1289 vboxWddmHTableDestroy(&pMgr->AllocTable);
1290 return STATUS_SUCCESS;
1291}
1292
1293NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1294{
1295 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1296 if (pMgr->pvData)
1297 {
1298 ExInitializeFastMutex(&pCtx->Mutex);
1299 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1300 Assert(Status == STATUS_SUCCESS);
1301 if (Status == STATUS_SUCCESS)
1302 {
1303 pCtx->pMgr = pMgr;
1304 return STATUS_SUCCESS;
1305 }
1306 }
1307 return Status;
1308}
1309
1310NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1311{
1312 if (!pCtx->pMgr)
1313 return STATUS_SUCCESS;
1314
1315 VBOXWDDM_HTABLE_ITERATOR Iter;
1316 NTSTATUS Status = STATUS_SUCCESS;
1317
1318 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1319 do
1320 {
1321 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1322 if (!pRef)
1323 break;
1324
1325 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1326 Assert(Status == STATUS_SUCCESS);
1327 if (Status != STATUS_SUCCESS)
1328 break;
1329 // vboxWddmHTableIterRemoveCur(&Iter);
1330 } while (1);
1331
1332 if (Status == STATUS_SUCCESS)
1333 {
1334 vboxWddmHTableDestroy(&pCtx->AllocTable);
1335 }
1336
1337 return Status;
1338}
1339
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