VirtualBox

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

Last change on this file since 41636 was 41636, checked in by vboxsync, 12 years ago

wddm: fix win8 halt issues

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.2 KB
Line 
1/* $Id: VBoxMPMisc.cpp 41636 2012-06-09 12:56:51Z 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(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 VBoxWddmVrListInit(&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
211DECLINLINE(BOOLEAN) 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
221DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain)
222{
223 const uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs);
224 Assert(cRefs < UINT32_MAX/2);
225 if (!cRefs)
226 {
227 VBoxWddmVrListClear(&pSwapchain->VisibleRegions);
228 vboxWddmMemFree(pSwapchain);
229 }
230}
231
232PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
233{
234 KIRQL OldIrql;
235 PVBOXWDDM_SWAPCHAIN pSwapchain;
236 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
237 pSwapchain = pAlloc->pSwapchain;
238 if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain))
239 pSwapchain = NULL;
240 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
241 return pSwapchain;
242}
243
244VOID vboxWddmSwapchainAllocRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
245{
246 KIRQL OldIrql;
247 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
248 Assert(pAlloc->pSwapchain == pSwapchain);
249 pAlloc->pSwapchain = NULL;
250 RemoveEntryList(&pAlloc->SwapchainEntry);
251 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
252 vboxWddmSwapchainRelease(pSwapchain);
253}
254
255BOOLEAN vboxWddmSwapchainAllocAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
256{
257 KIRQL OldIrql;
258 BOOLEAN bRc;
259 Assert(!pAlloc->pSwapchain);
260 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
261 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
262 if (bRc)
263 {
264 if (pAlloc->pSwapchain)
265 {
266 RemoveEntryList(&pAlloc->SwapchainEntry);
267 }
268 InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry);
269 pAlloc->pSwapchain = pSwapchain;
270 }
271 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
272 return bRc;
273}
274
275#define VBOXSCENTRY_2_ALLOC(_pE) ((PVBOXWDDM_ALLOCATION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, SwapchainEntry)))
276
277static VOID vboxWddmSwapchainAllocRemoveAllInternal(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, BOOLEAN bOnDestroy)
278{
279 KIRQL OldIrql;
280 UINT cRemoved = 0;
281 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
282 PLIST_ENTRY pEntry = pSwapchain->AllocList.Flink;
283 do
284 {
285 if (pEntry != &pSwapchain->AllocList)
286 {
287 PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry);
288 pEntry = pEntry->Flink;
289 Assert(pAlloc->pSwapchain == pSwapchain);
290 pAlloc->pSwapchain = NULL;
291 RemoveEntryList(&pAlloc->SwapchainEntry);
292 ++cRemoved;
293 }
294 else
295 break;
296 } while (1);
297
298 if (bOnDestroy)
299 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_TERMINATED;
300 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
301
302 for (UINT i = 0; i < cRemoved; ++i)
303 vboxWddmSwapchainRelease(pSwapchain);
304}
305
306VOID vboxWddmSwapchainAllocRemoveAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
307{
308 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, FALSE);
309}
310
311VOID vboxWddmSwapchainDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
312{
313 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE);
314
315 Assert(pSwapchain->pContext);
316 if (pSwapchain->pContext)
317 {
318 NTSTATUS tmpStatus = vboxVdmaGgCmdCancel(pDevExt, pSwapchain->pContext, pSwapchain);
319 if (tmpStatus != STATUS_SUCCESS)
320 {
321 WARN(("vboxVdmaGgCmdCancel returned Status (0x%x)", tmpStatus));
322 }
323 }
324
325 vboxWddmSwapchainRelease(pSwapchain);
326}
327
328static BOOLEAN vboxWddmSwapchainCtxAddLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
329{
330 if (vboxWddmSwapchainRetain(pDevExt, pSwapchain))
331 {
332 Assert(!pSwapchain->hSwapchainKm);
333 Assert(!pSwapchain->pContext);
334 pSwapchain->pContext = pContext;
335 pSwapchain->hSwapchainKm = vboxWddmHTablePut(&pContext->Swapchains, pSwapchain);
336 InsertHeadList(&pDevExt->SwapchainList3D, &pSwapchain->DevExtListEntry);
337 return TRUE;
338 }
339 return FALSE;
340}
341
342static VOID vboxWddmSwapchainCtxRemoveLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
343{
344 Assert(pSwapchain->hSwapchainKm);
345 Assert(pSwapchain->pContext);
346 void * pTst = vboxWddmHTableRemove(&pContext->Swapchains, pSwapchain->hSwapchainKm);
347 Assert(pTst == pSwapchain);
348 RemoveEntryList(&pSwapchain->DevExtListEntry);
349 pSwapchain->hSwapchainKm = NULL;
350 VBoxWddmVrListClear(&pSwapchain->VisibleRegions);
351 vboxWddmSwapchainRelease(pSwapchain);
352}
353
354/* adds the given swapchain to the context's swapchain list
355 * @return true on success */
356BOOLEAN vboxWddmSwapchainCtxAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
357{
358 BOOLEAN bRc;
359 ExAcquireFastMutex(&pDevExt->ContextMutex);
360 bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
361 ExReleaseFastMutex(&pDevExt->ContextMutex);
362 return bRc;
363}
364
365/* removes the given swapchain from the context's swapchain list
366 * */
367VOID vboxWddmSwapchainCtxRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
368{
369 ExAcquireFastMutex(&pDevExt->ContextMutex);
370 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
371 ExReleaseFastMutex(&pDevExt->ContextMutex);
372}
373
374/* destroys all swapchains for the given context
375 * */
376VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
377{
378 VBOXWDDM_HTABLE_ITERATOR Iter;
379 do
380 {
381 ExAcquireFastMutex(&pDevExt->ContextMutex);
382 vboxWddmHTableIterInit(&pContext->Swapchains, &Iter);
383 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL);
384 if (!pSwapchain)
385 break;
386
387 /* yes, we can call remove locked even when using iterator */
388 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
389
390 ExReleaseFastMutex(&pDevExt->ContextMutex);
391 /* we must not do vboxWddmSwapchainDestroy inside a context mutex */
392 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
393 /* start from the very beginning, we will quit the loop when no swapchains left */
394 } while (1);
395
396 /* no swapchains left, we exiteed the while loop via the "break", and we still owning the mutex */
397 ExReleaseFastMutex(&pDevExt->ContextMutex);
398}
399
400/* process the swapchain info passed from user-mode display driver & synchronizes the driver state with it */
401NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize)
402{
403 Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])));
404 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
405 return STATUS_INVALID_PARAMETER;
406 Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]));
407 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
408 return STATUS_INVALID_PARAMETER;
409
410 PVBOXWDDM_SWAPCHAIN pSwapchain = NULL;
411 PVBOXWDDM_ALLOCATION *apAlloc = NULL;
412 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
413 NTSTATUS Status = STATUS_SUCCESS;
414
415 do {
416 if (pSwapchainInfo->SwapchainInfo.cAllocs)
417 {
418 /* ensure we do not overflow the 32bit buffer size value */
419 if (VBOXWDDM_ARRAY_MAXELEMENTSU32(VBOXWDDM_ALLOCATION) < pSwapchainInfo->SwapchainInfo.cAllocs)
420 {
421 WARN(("number of allocations passed in too big (%d), max is (%d)", pSwapchainInfo->SwapchainInfo.cAllocs, VBOXWDDM_ARRAY_MAXELEMENTSU32(VBOXWDDM_ALLOCATION)));
422 Status = STATUS_INVALID_PARAMETER;
423 break;
424 }
425
426 apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
427 Assert(apAlloc);
428 if (!apAlloc)
429 {
430 Status = STATUS_NO_MEMORY;
431 break;
432 }
433 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
434 {
435 DXGKARGCB_GETHANDLEDATA GhData;
436 GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
437 GhData.Type = DXGK_HANDLE_ALLOCATION;
438 GhData.Flags.Value = 0;
439 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
440 Assert(pAlloc);
441 if (!pAlloc)
442 {
443 Status = STATUS_INVALID_PARAMETER;
444 break;
445 }
446 apAlloc[i] = pAlloc;
447 }
448
449 if (!NT_SUCCESS(Status))
450 break;
451 }
452
453 if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
454 {
455 ExAcquireFastMutex(&pDevExt->ContextMutex);
456 pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
457 Assert(pSwapchain);
458 if (!pSwapchain)
459 {
460 ExReleaseFastMutex(&pDevExt->ContextMutex);
461 Status = STATUS_INVALID_PARAMETER;
462 break;
463 }
464 Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
465 Assert(pSwapchain->pContext == pContext);
466 if (pSwapchain->pContext != pContext)
467 {
468 ExReleaseFastMutex(&pDevExt->ContextMutex);
469 Status = STATUS_INVALID_PARAMETER;
470 break;
471 }
472 }
473 else if (pSwapchainInfo->SwapchainInfo.cAllocs)
474 {
475 pSwapchain = vboxWddmSwapchainCreate(apAlloc[0]->SurfDesc.width, apAlloc[0]->SurfDesc.height);
476 if (!pSwapchain)
477 {
478 Status = STATUS_NO_MEMORY;
479 break;
480 }
481
482 ExAcquireFastMutex(&pDevExt->ContextMutex);
483 BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
484 Assert(bRc);
485 }
486 else
487 {
488 Status = STATUS_INVALID_PARAMETER;
489 break;
490 }
491
492 /* do not zero up the view rect since it may still be valid */
493// memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
494 /* @todo: do we really need to zero this up here ? */
495 VBoxWddmVrListClear(&pSwapchain->VisibleRegions);
496
497 vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);
498
499 if (pSwapchainInfo->SwapchainInfo.cAllocs)
500 {
501 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
502 {
503 vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
504 }
505 pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
506 }
507 else
508 {
509 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
510 }
511
512 ExReleaseFastMutex(&pDevExt->ContextMutex);
513
514 if (pSwapchainInfo->SwapchainInfo.cAllocs)
515 {
516 Assert(pSwapchain->pContext);
517 Assert(pSwapchain->hSwapchainKm);
518 pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
519 }
520 else
521 {
522 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
523 pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
524 }
525
526 Assert(Status == STATUS_SUCCESS);
527 } while (0);
528
529 /* cleanup */
530 if (apAlloc)
531 vboxWddmMemFree(apAlloc);
532
533 return Status;
534}
535
536NTSTATUS vboxWddmSwapchainCtxInit(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
537{
538 NTSTATUS Status = vboxWddmHTableCreate(&pContext->Swapchains, 4);
539 if (!NT_SUCCESS(Status))
540 {
541 WARN(("vboxWddmHTableCreate failes, Status (x%x)", Status));
542 return Status;
543 }
544
545 return STATUS_SUCCESS;
546}
547
548VOID vboxWddmSwapchainCtxTerm(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
549{
550 vboxWddmSwapchainCtxDestroyAll(pDevExt, pContext);
551 vboxWddmHTableDestroy(&pContext->Swapchains);
552}
553
554#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
555
556NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
557{
558 WCHAR fallBackBuf[2];
559 PWCHAR pSuffix;
560 bool bFallback = false;
561
562 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
563 {
564 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
565 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
566 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
567 }
568 else
569 {
570 pSuffix = fallBackBuf;
571 cbBuf = sizeof (fallBackBuf);
572 bFallback = true;
573 }
574
575 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
576 DevicePropertyDriverKeyName,
577 cbBuf,
578 pSuffix,
579 &cbBuf);
580 if (Status == STATUS_SUCCESS && bFallback)
581 Status = STATUS_BUFFER_TOO_SMALL;
582 if (Status == STATUS_BUFFER_TOO_SMALL)
583 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
584
585 return Status;
586}
587
588#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\"
589#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\"
590
591#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX"
592#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY"
593#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop"
594
595NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
596 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
597{
598 NTSTATUS Status = STATUS_SUCCESS;
599 PWCHAR pSuffix;
600 bool bFallback = false;
601 const WCHAR* pKeyPrefix;
602 UINT cbKeyPrefix;
603 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
604 Assert(pVGuid);
605 if (!pVGuid)
606 return STATUS_UNSUCCESSFUL;
607
608 vboxWinVersion_t ver = VBoxQueryWinVersion();
609 if (ver == WINVISTA)
610 {
611 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
612 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
613 }
614 else
615 {
616 Assert(ver == WIN7 || ver == WIN8);
617 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
618 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
619 }
620
621 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
622 if (cbBuf >= cbResult)
623 {
624 wcscpy(pBuf, pKeyPrefix);
625 pSuffix = pBuf + (cbKeyPrefix-2)/2;
626 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
627 pSuffix += pVGuid->Length/2;
628 pSuffix[0] = L'\\';
629 pSuffix += 1;
630 swprintf(pSuffix, L"%04d", VidPnSourceId);
631 }
632 else
633 {
634 Status = STATUS_BUFFER_TOO_SMALL;
635 }
636
637 *pcbResult = cbResult;
638
639 return Status;
640}
641
642#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\"
643#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video"
644
645NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
646{
647 HANDLE hKey;
648 NTSTATUS Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
649 Assert(Status == STATUS_SUCCESS);
650 if (Status == STATUS_SUCCESS)
651 {
652 struct
653 {
654 KEY_BASIC_INFORMATION Name;
655 WCHAR Buf[256];
656 } Buf;
657 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
658 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
659 ULONG ResultLength;
660 BOOL bFound = FALSE;
661 for (ULONG i = 0; !bFound; ++i)
662 {
663 RtlZeroMemory(&Buf, sizeof (Buf));
664 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
665 Assert(Status == STATUS_SUCCESS);
666 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
667 if (Status != STATUS_SUCCESS)
668 break;
669
670 HANDLE hSubKey;
671 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
672 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
673 pSubBuf += Buf.Name.NameLength/2;
674 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
675 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
676 Assert(Status == STATUS_SUCCESS);
677 if (Status == STATUS_SUCCESS)
678 {
679 struct
680 {
681 KEY_VALUE_PARTIAL_INFORMATION Info;
682 UCHAR Buf[sizeof (L"VBoxVideoWddm")]; /* should be enough */
683 } KeyData;
684 ULONG cbResult;
685 UNICODE_STRING RtlStr;
686 RtlInitUnicodeString(&RtlStr, L"Service");
687 Status = ZwQueryValueKey(hSubKey,
688 &RtlStr,
689 KeyValuePartialInformation,
690 &KeyData.Info,
691 sizeof(KeyData),
692 &cbResult);
693 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
694 if (Status == STATUS_SUCCESS)
695 {
696 if (KeyData.Info.Type == REG_SZ)
697 {
698 if (KeyData.Info.DataLength == sizeof (L"VBoxVideoWddm"))
699 {
700 if (!wcscmp(L"VBoxVideoWddm", (PWCHAR)KeyData.Info.Data))
701 {
702 bFound = TRUE;
703 *pcbResult = Buf.Name.NameLength + 2;
704 if (cbBuf >= Buf.Name.NameLength + 2)
705 {
706 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
707 }
708 else
709 {
710 Status = STATUS_BUFFER_TOO_SMALL;
711 }
712 }
713 }
714 }
715 }
716
717 NTSTATUS tmpStatus = ZwClose(hSubKey);
718 Assert(tmpStatus == STATUS_SUCCESS);
719 }
720 else
721 break;
722 }
723 NTSTATUS tmpStatus = ZwClose(hKey);
724 Assert(tmpStatus == STATUS_SUCCESS);
725 }
726
727 return Status;
728}
729
730NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
731{
732 OBJECT_ATTRIBUTES ObjAttr;
733 UNICODE_STRING RtlStr;
734
735 RtlInitUnicodeString(&RtlStr, pName);
736 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
737
738 return ZwOpenKey(phKey, fAccess, &ObjAttr);
739}
740
741NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey)
742{
743 WCHAR Buf[512];
744 ULONG cbBuf = sizeof(Buf);
745 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDeviceExtension, VidPnSourceId, cbBuf, Buf, &cbBuf);
746 Assert(Status == STATUS_SUCCESS);
747 if (Status == STATUS_SUCCESS)
748 {
749 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
750 Assert(Status == STATUS_SUCCESS);
751 if(Status == STATUS_SUCCESS)
752 return STATUS_SUCCESS;
753 }
754
755 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
756 * basically needed to make as less modifications to the current XPDM code as possible */
757 *phKey = NULL;
758
759 return Status;
760}
761
762NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
763{
764 DWORD dwVal;
765 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
766 Assert(Status == STATUS_SUCCESS);
767 if (Status == STATUS_SUCCESS)
768 {
769 *pResult = (int)dwVal;
770 }
771
772 return Status;
773}
774
775NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
776{
777 DWORD dwVal;
778 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
779 Assert(Status == STATUS_SUCCESS);
780 if (Status == STATUS_SUCCESS)
781 {
782 *pResult = (int)dwVal;
783 }
784
785 return Status;
786}
787
788NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
789{
790 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
791 HANDLE hKey;
792 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDeviceExtension, VidPnSourceId, &hKey);
793 Assert(Status == STATUS_SUCCESS);
794 if (Status == STATUS_SUCCESS)
795 {
796 int x, y;
797 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
798 Assert(Status == STATUS_SUCCESS);
799 if (Status == STATUS_SUCCESS)
800 {
801 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
802 Assert(Status == STATUS_SUCCESS);
803 if (Status == STATUS_SUCCESS)
804 {
805 pPos->x = x;
806 pPos->y = y;
807 }
808 }
809 NTSTATUS tmpStatus = ZwClose(hKey);
810 Assert(tmpStatus == STATUS_SUCCESS);
811 }
812 return Status;
813}
814
815NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
816{
817 struct
818 {
819 KEY_VALUE_PARTIAL_INFORMATION Info;
820 UCHAR Buf[32]; /* should be enough */
821 } Buf;
822 ULONG cbBuf;
823 UNICODE_STRING RtlStr;
824 RtlInitUnicodeString(&RtlStr, pName);
825 NTSTATUS Status = ZwQueryValueKey(hKey,
826 &RtlStr,
827 KeyValuePartialInformation,
828 &Buf.Info,
829 sizeof(Buf),
830 &cbBuf);
831 if (Status == STATUS_SUCCESS)
832 {
833 if (Buf.Info.Type == REG_DWORD)
834 {
835 Assert(Buf.Info.DataLength == 4);
836 *pDword = *((PULONG)Buf.Info.Data);
837 return STATUS_SUCCESS;
838 }
839 }
840
841 return STATUS_INVALID_PARAMETER;
842}
843
844NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val)
845{
846 UNICODE_STRING RtlStr;
847 RtlInitUnicodeString(&RtlStr, pName);
848 return ZwSetValueKey(hKey, &RtlStr,
849 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
850 REG_DWORD,
851 &val,
852 sizeof(val));
853}
854
855UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt)
856{
857 if (pDevExt->VideoGuid.Buffer)
858 return &pDevExt->VideoGuid;
859
860 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
861 WCHAR VideoGuidBuf[512];
862 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
863 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
864 Assert(Status == STATUS_SUCCESS);
865 if (Status == STATUS_SUCCESS)
866 {
867 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
868 Assert(pBuf);
869 if (pBuf)
870 {
871 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
872 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
873 return &pDevExt->VideoGuid;
874 }
875 }
876
877 return NULL;
878}
879
880VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt)
881{
882 if (pDevExt->VideoGuid.Buffer)
883 {
884 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
885 pDevExt->VideoGuid.Buffer = NULL;
886 }
887}
888
889/* mm */
890
891NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
892{
893 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
894 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
895 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
896 if (!pBuf)
897 {
898 Assert(0);
899 return STATUS_NO_MEMORY;
900 }
901 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
902 pMm->cPages = cPages;
903 pMm->cAllocs = 0;
904 pMm->pBuffer = pBuf;
905 return STATUS_SUCCESS;
906}
907
908ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
909{
910 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
911 if (iPage == 0xFFFFFFFF)
912 {
913 Assert(0);
914 return VBOXWDDM_MM_VOID;
915 }
916
917 ++pMm->cAllocs;
918 return iPage;
919}
920
921VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
922{
923 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
924 RtlClearBits(&pMm->BitMap, iPage, cPages);
925 --pMm->cAllocs;
926 Assert(pMm->cAllocs < UINT32_MAX);
927}
928
929NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
930{
931 Assert(!pMm->cAllocs);
932 vboxWddmMemFree(pMm->pBuffer);
933 pMm->pBuffer = NULL;
934 return STATUS_SUCCESS;
935}
936
937
938
939typedef struct VBOXVIDEOCM_ALLOC
940{
941 VBOXWDDM_HANDLE hGlobalHandle;
942 uint32_t offData;
943 uint32_t cbData;
944} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
945
946typedef struct VBOXVIDEOCM_ALLOC_REF
947{
948 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
949 VBOXWDDM_HANDLE hSessionHandle;
950 PVBOXVIDEOCM_ALLOC pAlloc;
951 PKEVENT pSynchEvent;
952 VBOXUHGSMI_BUFFER_TYPE_FLAGS fUhgsmiType;
953 volatile uint32_t cRefs;
954 MDL Mdl;
955} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
956
957
958NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
959{
960 NTSTATUS Status = STATUS_UNSUCCESSFUL;
961 UINT cbSize = pAlloc->cbData;
962 UINT cPages = BYTES_TO_PAGES(cbSize);
963 ExAcquireFastMutex(&pMgr->Mutex);
964 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
965 if (iPage != VBOXWDDM_MM_VOID)
966 {
967 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
968 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
969 pAlloc->offData = offData;
970 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
971 ExReleaseFastMutex(&pMgr->Mutex);
972 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
973 return STATUS_SUCCESS;
974
975 Assert(0);
976 Status = STATUS_NO_MEMORY;
977 vboxMmFree(&pMgr->Mm, iPage, cPages);
978 }
979 else
980 {
981 Assert(0);
982 ExReleaseFastMutex(&pMgr->Mutex);
983 Status = STATUS_INSUFFICIENT_RESOURCES;
984 }
985 return Status;
986}
987
988VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
989{
990 UINT cbSize = pAlloc->cbData;
991 UINT cPages = BYTES_TO_PAGES(cbSize);
992 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
993 ExAcquireFastMutex(&pMgr->Mutex);
994 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
995 vboxMmFree(&pMgr->Mm, iPage, cPages);
996 ExReleaseFastMutex(&pMgr->Mutex);
997}
998
999
1000NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
1001{
1002 NTSTATUS Status = STATUS_SUCCESS;
1003 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
1004 if (pAlloc)
1005 {
1006 pAlloc->cbData = cbSize;
1007 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
1008 if (Status == STATUS_SUCCESS)
1009 {
1010 *ppAlloc = pAlloc;
1011 return STATUS_SUCCESS;
1012 }
1013
1014 Assert(0);
1015 vboxWddmMemFree(pAlloc);
1016 }
1017 else
1018 {
1019 Assert(0);
1020 Status = STATUS_NO_MEMORY;
1021 }
1022
1023 return Status;
1024}
1025
1026VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
1027{
1028 vboxVideoCmAllocDealloc(pMgr, pAlloc);
1029 vboxWddmMemFree(pAlloc);
1030}
1031
1032NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1033{
1034 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1035 NTSTATUS Status = STATUS_SUCCESS;
1036 PKEVENT pSynchEvent = NULL;
1037
1038 if (pUmAlloc->hSynch)
1039 {
1040 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
1041 (PVOID*)&pSynchEvent,
1042 NULL);
1043 Assert(Status == STATUS_SUCCESS);
1044 Assert(pSynchEvent);
1045 }
1046
1047 if (Status == STATUS_SUCCESS)
1048 {
1049 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
1050 SIZE_T cbLength = pAlloc->cbData;
1051
1052 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero(sizeof (*pAllocRef) + sizeof (PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
1053 if (pAllocRef)
1054 {
1055 pAllocRef->cRefs = 1;
1056 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
1057 __try
1058 {
1059 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
1060 }
1061 __except(EXCEPTION_EXECUTE_HANDLER)
1062 {
1063 Assert(0);
1064 Status = STATUS_UNSUCCESSFUL;
1065 }
1066
1067 if (Status == STATUS_SUCCESS)
1068 {
1069 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
1070 NULL, /* PVOID BaseAddress */
1071 FALSE, /* ULONG BugCheckOnFailure */
1072 NormalPagePriority);
1073 if (pvUm)
1074 {
1075 pAllocRef->pContext = pContext;
1076 pAllocRef->pAlloc = pAlloc;
1077 pAllocRef->fUhgsmiType = pUmAlloc->fUhgsmiType;
1078 pAllocRef->pSynchEvent = pSynchEvent;
1079 ExAcquireFastMutex(&pContext->Mutex);
1080 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
1081 ExReleaseFastMutex(&pContext->Mutex);
1082 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
1083 {
1084 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
1085 pUmAlloc->cbData = pAlloc->cbData;
1086 pUmAlloc->pvData = (uint64_t)pvUm;
1087 return STATUS_SUCCESS;
1088 }
1089 }
1090 else
1091 {
1092 Assert(0);
1093 Status = STATUS_INSUFFICIENT_RESOURCES;
1094 }
1095
1096 MmUnlockPages(&pAllocRef->Mdl);
1097 }
1098
1099 vboxWddmMemFree(pAllocRef);
1100 }
1101 else
1102 {
1103 Assert(0);
1104 Status = STATUS_NO_MEMORY;
1105 }
1106
1107 if (pSynchEvent)
1108 ObDereferenceObject(pSynchEvent);
1109 }
1110 else
1111 {
1112 Assert(0);
1113 }
1114
1115
1116 return Status;
1117}
1118
1119NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle, PVBOXVIDEOCM_ALLOC *ppAlloc)
1120{
1121 NTSTATUS Status = STATUS_SUCCESS;
1122 ExAcquireFastMutex(&pContext->Mutex);
1123 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
1124 ExReleaseFastMutex(&pContext->Mutex);
1125 if (pAllocRef)
1126 {
1127 /* wait for the dereference, i.e. for all commands involving this allocation to complete */
1128 vboxWddmCounterU32Wait(&pAllocRef->cRefs, 1);
1129
1130 MmUnlockPages(&pAllocRef->Mdl);
1131 *ppAlloc = pAllocRef->pAlloc;
1132 if (pAllocRef->pSynchEvent)
1133 ObDereferenceObject(pAllocRef->pSynchEvent);
1134 vboxWddmMemFree(pAllocRef);
1135 }
1136 else
1137 {
1138 Assert(0);
1139 Status = STATUS_INVALID_PARAMETER;
1140 }
1141
1142 return Status;
1143}
1144
1145static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1146{
1147 ExAcquireFastMutex(&pContext->Mutex);
1148 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
1149 ASMAtomicIncU32(&pAllocRef->cRefs);
1150 ExReleaseFastMutex(&pContext->Mutex);
1151 return pAllocRef;
1152}
1153
1154static VOID vboxVideoAMgrCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
1155{
1156 uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs);
1157 Assert(cRefs < UINT32_MAX/2);
1158 Assert(cRefs >= 1); /* we do not do cleanup-on-zero here, instead we wait for the cRefs to reach 1 in vboxVideoAMgrCtxAllocUnmap before unmapping */
1159}
1160
1161
1162
1163NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1164{
1165 PVBOXVIDEOCM_ALLOC pAlloc;
1166 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1167 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
1168 if (Status == STATUS_SUCCESS)
1169 {
1170 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
1171 if (Status == STATUS_SUCCESS)
1172 return STATUS_SUCCESS;
1173 else
1174 {
1175 Assert(0);
1176 }
1177 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1178 }
1179 else
1180 {
1181 Assert(0);
1182 }
1183 return Status;
1184}
1185
1186NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1187{
1188 PVBOXVIDEOCM_ALLOC pAlloc;
1189 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1190 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
1191 if (Status == STATUS_SUCCESS)
1192 {
1193 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1194 }
1195 else
1196 {
1197 Assert(0);
1198 }
1199 return Status;
1200}
1201
1202#ifdef VBOX_WITH_CRHGSMI
1203static DECLCALLBACK(VOID) vboxVideoAMgrAllocSubmitCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1204{
1205 /* we should be called from our DPC routine */
1206 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1207
1208 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvContext;
1209 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1210 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1211 UINT cBufs = pBody->cBuffers;
1212 for (UINT i = 0; i < cBufs; ++i)
1213 {
1214 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1215 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd->u64GuestData;
1216 if (!pBufCmd->u32GuestData)
1217 {
1218 /* signal completion */
1219 if (pRef->pSynchEvent)
1220 KeSetEvent(pRef->pSynchEvent, 3, FALSE);
1221 }
1222
1223 vboxVideoAMgrCtxAllocRefRelease(pRef);
1224 }
1225
1226 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1227}
1228
1229/* submits a set of chromium uhgsmi buffers to host for processing */
1230NTSTATUS vboxVideoAMgrCtxAllocSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_CONTEXT pContext, UINT cBuffers, VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *paBuffers)
1231{
1232 /* ensure we do not overflow the 32bit buffer size value */
1233 if (VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXVDMACMD_CHROMIUM_CMD, aBuffers) < cBuffers)
1234 {
1235 WARN(("number of buffers passed too big (%d), max is (%d)", cBuffers, VBOXWDDM_TRAILARRAY_MAXELEMENTSU32(VBOXVDMACMD_CHROMIUM_CMD, aBuffers)));
1236 return STATUS_INVALID_PARAMETER;
1237 }
1238
1239 NTSTATUS Status = STATUS_SUCCESS;
1240 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers]));
1241
1242 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd);
1243 if (pDr)
1244 {
1245 // vboxVdmaCBufDrCreate zero initializes the pDr
1246 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
1247 pDr->cbBuf = cbCmd;
1248 pDr->rc = VERR_NOT_IMPLEMENTED;
1249
1250 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1251 pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD;
1252 pHdr->u32CmdSpecific = 0;
1253 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1254 pBody->cBuffers = cBuffers;
1255 for (UINT i = 0; i < cBuffers; ++i)
1256 {
1257 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1258 VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *pBufInfo = &paBuffers[i];
1259 PVBOXVIDEOCM_ALLOC_REF pRef = vboxVideoAMgrCtxAllocRefAcquire(pContext, pBufInfo->hAlloc);
1260 if (pRef)
1261 {
1262#ifdef DEBUG_misha
1263 Assert(pRef->cRefs == 2);
1264#endif
1265 pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData;
1266 pBufCmd->cbBuffer = pBufInfo->Info.cbData;
1267 pBufCmd->u32GuestData = pBufInfo->Info.bDoNotSignalCompletion;
1268 pBufCmd->u64GuestData = (uint64_t)pRef;
1269 }
1270 else
1271 {
1272 WARN(("vboxVideoAMgrCtxAllocRefAcquire failed for hAlloc(0x%x)\n", pBufInfo->hAlloc));
1273 /* release all previously acquired aloc references */
1274 for (UINT j = 0; j < i; ++j)
1275 {
1276 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmdJ = &pBody->aBuffers[j];
1277 PVBOXVIDEOCM_ALLOC_REF pRefJ = (PVBOXVIDEOCM_ALLOC_REF)pBufCmdJ;
1278 vboxVideoAMgrCtxAllocRefRelease(pRefJ);
1279 }
1280 Status = STATUS_INVALID_PARAMETER;
1281 break;
1282 }
1283 }
1284
1285 if (Status == STATUS_SUCCESS)
1286 {
1287 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
1288 vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxVideoAMgrAllocSubmitCompletion, pDr);
1289 /* mark command as submitted & invisible for the dx runtime since dx did not originate it */
1290 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
1291 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1292 if (RT_SUCCESS(rc))
1293 {
1294 return STATUS_SUCCESS;
1295 }
1296
1297 WARN(("vboxVdmaCBufDrSubmit failed with rc (%d)\n", rc));
1298
1299 /* failure branch */
1300 /* release all previously acquired aloc references */
1301 for (UINT i = 0; i < cBuffers; ++i)
1302 {
1303 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1304 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd;
1305 vboxVideoAMgrCtxAllocRefRelease(pRef);
1306 }
1307 }
1308
1309 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1310 }
1311 else
1312 {
1313 Assert(0);
1314 /* @todo: try flushing.. */
1315 LOGREL(("vboxVdmaCBufDrCreate returned NULL"));
1316 Status = STATUS_INSUFFICIENT_RESOURCES;
1317 }
1318
1319 return Status;
1320}
1321#endif
1322
1323NTSTATUS vboxVideoAMgrCreate(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
1324{
1325 Assert(!(offData & (PAGE_SIZE -1)));
1326 Assert(!(cbData & (PAGE_SIZE -1)));
1327 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
1328 cbData &= (~(PAGE_SIZE -1));
1329 Assert(cbData);
1330 if (!cbData)
1331 return STATUS_INVALID_PARAMETER;
1332
1333 ExInitializeFastMutex(&pMgr->Mutex);
1334 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
1335 Assert(Status == STATUS_SUCCESS);
1336 if (Status == STATUS_SUCCESS)
1337 {
1338 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
1339 Assert(Status == STATUS_SUCCESS);
1340 if (Status == STATUS_SUCCESS)
1341 {
1342 PHYSICAL_ADDRESS PhysicalAddress = {0};
1343 PhysicalAddress.QuadPart = VBoxCommonFromDeviceExt(pDevExt)->phVRAM.QuadPart + offData;
1344 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
1345 Assert(pMgr->pvData);
1346 if (pMgr->pvData)
1347 {
1348 pMgr->offData = offData;
1349 pMgr->cbData = cbData;
1350 return STATUS_SUCCESS;
1351 }
1352 else
1353 {
1354 Status = STATUS_UNSUCCESSFUL;
1355 }
1356 vboxMmTerm(&pMgr->Mm);
1357 }
1358 vboxWddmHTableDestroy(&pMgr->AllocTable);
1359 }
1360
1361 return Status;
1362}
1363
1364NTSTATUS vboxVideoAMgrDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1365{
1366 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1367 vboxMmTerm(&pMgr->Mm);
1368 vboxWddmHTableDestroy(&pMgr->AllocTable);
1369 return STATUS_SUCCESS;
1370}
1371
1372NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1373{
1374 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1375 if (pMgr->pvData)
1376 {
1377 ExInitializeFastMutex(&pCtx->Mutex);
1378 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1379 Assert(Status == STATUS_SUCCESS);
1380 if (Status == STATUS_SUCCESS)
1381 {
1382 pCtx->pMgr = pMgr;
1383 return STATUS_SUCCESS;
1384 }
1385 }
1386 return Status;
1387}
1388
1389NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1390{
1391 if (!pCtx->pMgr)
1392 return STATUS_SUCCESS;
1393
1394 VBOXWDDM_HTABLE_ITERATOR Iter;
1395 NTSTATUS Status = STATUS_SUCCESS;
1396
1397 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1398 do
1399 {
1400 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1401 if (!pRef)
1402 break;
1403
1404 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1405 Assert(Status == STATUS_SUCCESS);
1406 if (Status != STATUS_SUCCESS)
1407 break;
1408 // vboxWddmHTableIterRemoveCur(&Iter);
1409 } while (1);
1410
1411 if (Status == STATUS_SUCCESS)
1412 {
1413 vboxWddmHTableDestroy(&pCtx->AllocTable);
1414 }
1415
1416 return Status;
1417}
1418
1419
1420VOID vboxWddmSleep(uint32_t u32Val)
1421{
1422 LARGE_INTEGER Interval;
1423 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1424
1425 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1426}
1427
1428VOID vboxWddmCounterU32Wait(uint32_t volatile * pu32, uint32_t u32Val)
1429{
1430 LARGE_INTEGER Interval;
1431 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1432 uint32_t u32CurVal;
1433
1434 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1435
1436 while ((u32CurVal = ASMAtomicReadU32(pu32)) != u32Val)
1437 {
1438 Assert(u32CurVal >= u32Val);
1439 Assert(u32CurVal < UINT32_MAX/2);
1440
1441 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1442 }
1443}
1444
1445/* dump user-mode driver debug info */
1446static char g_aVBoxUmdD3DCAPS9[304];
1447static VBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS g_VBoxUmdD3DCAPS9Flags;
1448static BOOLEAN g_bVBoxUmdD3DCAPS9IsInited = FALSE;
1449
1450static void vboxUmdDumpDword(DWORD *pvData, DWORD cData)
1451{
1452 char aBuf[16*4];
1453 DWORD dw1, dw2, dw3, dw4;
1454 for (UINT i = 0; i < (cData & (~3)); i+=4)
1455 {
1456 dw1 = *pvData++;
1457 dw2 = *pvData++;
1458 dw3 = *pvData++;
1459 dw4 = *pvData++;
1460 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", dw1, dw2, dw3, dw4);
1461 LOGREL(("%s", aBuf));
1462 }
1463
1464 cData = cData % 4;
1465 switch (cData)
1466 {
1467 case 3:
1468 dw1 = *pvData++;
1469 dw2 = *pvData++;
1470 dw3 = *pvData++;
1471 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x\n", dw1, dw2, dw3);
1472 LOGREL(("%s", aBuf));
1473 break;
1474 case 2:
1475 dw1 = *pvData++;
1476 dw2 = *pvData++;
1477 sprintf(aBuf, "0x%08x, 0x%08x\n", dw1, dw2);
1478 LOGREL(("%s", aBuf));
1479 break;
1480 case 1:
1481 dw1 = *pvData++;
1482 sprintf(aBuf, "0x%8x\n", dw1);
1483 LOGREL(("%s", aBuf));
1484 break;
1485 default:
1486 break;
1487 }
1488}
1489
1490static void vboxUmdDumpD3DCAPS9(void *pvData, PVBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS pFlags)
1491{
1492 AssertCompile(!(sizeof (g_aVBoxUmdD3DCAPS9) % sizeof (DWORD)));
1493 LOGREL(("*****Start Dumping D3DCAPS9:*******"));
1494 LOGREL(("WoW64 flag(%d)", (UINT)pFlags->WoW64));
1495 vboxUmdDumpDword((DWORD*)pvData, sizeof (g_aVBoxUmdD3DCAPS9) / sizeof (DWORD));
1496 LOGREL(("*****End Dumping D3DCAPS9**********"));
1497}
1498
1499NTSTATUS vboxUmdDumpBuf(PVBOXDISPIFESCAPE_DBGDUMPBUF pBuf, uint32_t cbBuffer)
1500{
1501 if (cbBuffer < RT_OFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]))
1502 {
1503 WARN(("Buffer too small"));
1504 return STATUS_BUFFER_TOO_SMALL;
1505 }
1506
1507 NTSTATUS Status = STATUS_SUCCESS;
1508 uint32_t cbString = cbBuffer - RT_OFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]);
1509 switch (pBuf->enmType)
1510 {
1511 case VBOXDISPIFESCAPE_DBGDUMPBUF_TYPE_D3DCAPS9:
1512 {
1513 if (cbString != sizeof (g_aVBoxUmdD3DCAPS9))
1514 {
1515 WARN(("wrong caps size, expected %d, but was %d", sizeof (g_aVBoxUmdD3DCAPS9), cbString));
1516 Status = STATUS_INVALID_PARAMETER;
1517 break;
1518 }
1519
1520 if (g_bVBoxUmdD3DCAPS9IsInited)
1521 {
1522 if (!memcmp(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9)))
1523 break;
1524
1525 WARN(("caps do not match!"));
1526 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1527 break;
1528 }
1529
1530 memcpy(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9));
1531 g_VBoxUmdD3DCAPS9Flags = pBuf->Flags;
1532 g_bVBoxUmdD3DCAPS9IsInited = TRUE;
1533 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1534 }
1535 }
1536
1537 return Status;
1538}
1539
1540#if 0
1541VOID vboxShRcTreeInit(PVBOXMP_DEVEXT pDevExt)
1542{
1543 ExInitializeFastMutex(&pDevExt->ShRcTreeMutex);
1544 pDevExt->ShRcTree = NULL;
1545}
1546
1547VOID vboxShRcTreeTerm(PVBOXMP_DEVEXT pDevExt)
1548{
1549 Assert(!pDevExt->ShRcTree);
1550 pDevExt->ShRcTree = NULL;
1551}
1552
1553BOOLEAN vboxShRcTreePut(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1554{
1555 HANDLE hSharedRc = pAlloc->hSharedHandle;
1556 if (!hSharedRc)
1557 {
1558 WARN(("invalid call with zero shared handle!"));
1559 return FALSE;
1560 }
1561 pAlloc->ShRcTreeEntry.Key = (AVLPVKEY)hSharedRc;
1562 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1563 bool bRc = RTAvlPVInsert(&pDevExt->ShRcTree, &pAlloc->ShRcTreeEntry);
1564 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1565 Assert(bRc);
1566 return (BOOLEAN)bRc;
1567}
1568
1569#define PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(_p) ((PVBOXWDDM_ALLOCATION)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, ShRcTreeEntry)))
1570PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc)
1571{
1572 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1573 PAVLPVNODECORE pNode = RTAvlPVGet(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1574 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1575 if (!pNode)
1576 return NULL;
1577 PVBOXWDDM_ALLOCATION pAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1578 return pAlloc;
1579}
1580
1581BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1582{
1583 HANDLE hSharedRc = pAlloc->hSharedHandle;
1584 if (!hSharedRc)
1585 {
1586 WARN(("invalid call with zero shared handle!"));
1587 return FALSE;
1588 }
1589 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1590 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1591 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1592 if (!pNode)
1593 return NULL;
1594 PVBOXWDDM_ALLOCATION pRetAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1595 Assert(pRetAlloc == pAlloc);
1596 return !!pRetAlloc;
1597}
1598#endif
1599
1600
1601/* visible rects */
1602typedef struct VBOXWDDMVR_REG
1603{
1604 LIST_ENTRY ListEntry;
1605 RECT Rect;
1606} VBOXWDDMVR_REG, *PVBOXWDDMVR_REG;
1607
1608#define PVBOXWDDMVR_REG_FROM_ENTRY(_pEntry) ((PVBOXWDDMVR_REG)(((uint8_t*)(_pEntry)) - RT_OFFSETOF(VBOXWDDMVR_REG, ListEntry)))
1609
1610#ifdef DEBUG_misha
1611//# define VBOXVDBG_VR_LAL_DISABLE
1612#endif
1613
1614#ifndef VBOXVDBG_VR_LAL_DISABLE
1615static LOOKASIDE_LIST_EX g_VBoxWddmVrLookasideList;
1616#endif
1617
1618static PVBOXWDDMVR_REG vboxWddmVrRegCreate()
1619{
1620#ifndef VBOXVDBG_VR_LAL_DISABLE
1621 PVBOXWDDMVR_REG pReg = (PVBOXWDDMVR_REG)ExAllocateFromLookasideListEx(&g_VBoxWddmVrLookasideList);
1622 if (!pReg)
1623 {
1624 WARN(("ExAllocateFromLookasideListEx failed!"));
1625 }
1626 return pReg;
1627#else
1628 return (PVBOXWDDMVR_REG)vboxWddmMemAlloc(sizeof (VBOXWDDMVR_REG));
1629#endif
1630}
1631
1632static void vboxWddmVrRegTerm(PVBOXWDDMVR_REG pReg)
1633{
1634#ifndef VBOXVDBG_VR_LAL_DISABLE
1635 ExFreeToLookasideListEx(&g_VBoxWddmVrLookasideList, pReg);
1636#else
1637 vboxWddmMemFree(pReg);
1638#endif
1639}
1640
1641void VBoxWddmVrListClear(PVBOXWDDMVR_LIST pList)
1642{
1643 PLIST_ENTRY pNext;
1644 for (PLIST_ENTRY pEntry = pList->ListHead.Flink; pEntry != &pList->ListHead; pEntry = pNext)
1645 {
1646 pNext = pEntry->Flink;
1647 PVBOXWDDMVR_REG pReg = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry);
1648 vboxWddmVrRegTerm(pReg);
1649 }
1650 VBoxWddmVrListInit(pList);
1651}
1652
1653#define VBOXWDDMVR_MEMTAG 'vDBV'
1654
1655NTSTATUS VBoxWddmVrInit()
1656{
1657#ifndef VBOXVDBG_VR_LAL_DISABLE
1658 NTSTATUS Status = ExInitializeLookasideListEx(&g_VBoxWddmVrLookasideList,
1659 NULL, /* PALLOCATE_FUNCTION_EX Allocate */
1660 NULL, /* PFREE_FUNCTION_EX Free */
1661 NonPagedPool,
1662 0, /* ULONG Flags */
1663 sizeof (VBOXWDDMVR_REG),
1664 VBOXWDDMVR_MEMTAG,
1665 0 /* USHORT Depth - reserved, must be null */
1666 );
1667 if (!NT_SUCCESS(Status))
1668 {
1669 WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status));
1670 return Status;
1671 }
1672#endif
1673
1674 return STATUS_SUCCESS;
1675}
1676
1677void VBoxWddmVrTerm()
1678{
1679#ifndef VBOXVDBG_VR_LAL_DISABLE
1680 ExDeleteLookasideListEx(&g_VBoxWddmVrLookasideList);
1681#endif
1682}
1683
1684typedef DECLCALLBACK(int) FNVBOXWDDMVR_CB_COMPARATOR(const PVBOXWDDMVR_REG pReg1, const PVBOXWDDMVR_REG pReg2);
1685typedef FNVBOXWDDMVR_CB_COMPARATOR *PFNVBOXWDDMVR_CB_COMPARATOR;
1686
1687static DECLCALLBACK(int) vboxWddmVrRegNonintersectedComparator(const RECT* pRect1, const RECT* pRect2)
1688{
1689 Assert(!vboxWddmRectIsIntersect(pRect1, pRect2));
1690 if (pRect1->top != pRect2->top)
1691 return pRect1->top - pRect2->top;
1692 return pRect1->left - pRect2->left;
1693}
1694
1695#ifdef DEBUG_misha
1696static void vboxWddmVrDbgListDoVerify(PVBOXWDDMVR_LIST pList)
1697{
1698 PLIST_ENTRY pEntry1 = pList->ListHead.Flink;
1699
1700 for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink)
1701 {
1702 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
1703 for (PLIST_ENTRY pEntry2 = pEntry1->Flink; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->Flink)
1704 {
1705 PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2);
1706 Assert(vboxWddmVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
1707 }
1708 }
1709}
1710
1711#define vboxWddmVrDbgListVerify vboxWddmVrDbgListDoVerify
1712#else
1713#define vboxWddmVrDbgListVerify(_p) do {} while (0)
1714#endif
1715
1716static NTSTATUS vboxWddmVrListUniteIntersection(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_LIST pIntersection);
1717
1718#define VBOXWDDMVR_INVALID_COORD (~0UL)
1719
1720DECLINLINE(void) vboxWddmVrListRegAdd(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg, PLIST_ENTRY pPlace, BOOLEAN fAfter)
1721{
1722 if (fAfter)
1723 InsertHeadList(pPlace, &pReg->ListEntry);
1724 else
1725 InsertTailList(pPlace, &pReg->ListEntry);
1726 ++pList->cEntries;
1727 vboxWddmVrDbgListVerify(pList);
1728}
1729
1730DECLINLINE(void) vboxWddmVrListRegRemove(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg)
1731{
1732 RemoveEntryList(&pReg->ListEntry);
1733 --pList->cEntries;
1734}
1735
1736static void vboxWddmVrListRegAddOrder(PVBOXWDDMVR_LIST pList, PLIST_ENTRY pMemberEntry, PVBOXWDDMVR_REG pReg)
1737{
1738 do
1739 {
1740 if (pMemberEntry != &pList->ListHead)
1741 {
1742 PVBOXWDDMVR_REG pMemberReg = PVBOXWDDMVR_REG_FROM_ENTRY(pMemberEntry);
1743 if (vboxWddmVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
1744 {
1745 pMemberEntry = pMemberEntry->Flink;
1746 continue;
1747 }
1748 }
1749 vboxWddmVrListRegAdd(pList, pReg, pMemberEntry, FALSE);
1750 break;
1751 } while (1);
1752}
1753
1754static void vboxWddmVrListAddNonintersected(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_LIST pList2)
1755{
1756 PLIST_ENTRY pEntry1 = pList1->ListHead.Flink;
1757
1758 for (PLIST_ENTRY pEntry2 = pList2->ListHead.Flink; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.Flink)
1759 {
1760 PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2);
1761 do {
1762 if (pEntry1 != &pList1->ListHead)
1763 {
1764 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
1765 if (vboxWddmVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
1766 {
1767 pEntry1 = pEntry1->Flink;
1768 continue;
1769 }
1770 }
1771 vboxWddmVrListRegRemove(pList2, pReg2);
1772 vboxWddmVrListRegAdd(pList1, pReg2, pEntry1, FALSE);
1773 break;
1774 } while (1);
1775 }
1776
1777 Assert(VBoxWddmVrListIsEmpty(pList2));
1778}
1779
1780static NTSTATUS vboxWddmVrListRegIntersectSubstNoJoin(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_REG pReg1, const RECT * pRect2)
1781{
1782 UINT topLim = VBOXWDDMVR_INVALID_COORD;
1783 UINT bottomLim = VBOXWDDMVR_INVALID_COORD;
1784 LIST_ENTRY List;
1785 PVBOXWDDMVR_REG pBottomReg = NULL;
1786#ifdef DEBUG_misha
1787 RECT tmpRect = pReg1->Rect;
1788 vboxWddmVrDbgListVerify(pList1);
1789#endif
1790
1791 InitializeListHead(&List);
1792
1793 Assert(vboxWddmRectIsIntersect(&pReg1->Rect, pRect2));
1794
1795 if (pReg1->Rect.top < pRect2->top)
1796 {
1797 Assert(pRect2->top < pReg1->Rect.bottom);
1798 PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate();
1799 pRegResult->Rect.top = pReg1->Rect.top;
1800 pRegResult->Rect.left = pReg1->Rect.left;
1801 pRegResult->Rect.bottom = pRect2->top;
1802 pRegResult->Rect.right = pReg1->Rect.right;
1803 topLim = pRect2->top;
1804 InsertTailList(&List, &pRegResult->ListEntry);
1805 }
1806
1807 if (pReg1->Rect.bottom > pRect2->bottom)
1808 {
1809 Assert(pRect2->bottom > pReg1->Rect.top);
1810 PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate();
1811 pRegResult->Rect.top = pRect2->bottom;
1812 pRegResult->Rect.left = pReg1->Rect.left;
1813 pRegResult->Rect.bottom = pReg1->Rect.bottom;
1814 pRegResult->Rect.right = pReg1->Rect.right;
1815 bottomLim = pRect2->bottom;
1816 pBottomReg = pRegResult;
1817 }
1818
1819 if (pReg1->Rect.left < pRect2->left)
1820 {
1821 Assert(pRect2->left < pReg1->Rect.right);
1822 PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate();
1823 pRegResult->Rect.top = topLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.top : topLim;
1824 pRegResult->Rect.left = pReg1->Rect.left;
1825 pRegResult->Rect.bottom = bottomLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.bottom : bottomLim;
1826 pRegResult->Rect.right = pRect2->left;
1827 InsertTailList(&List, &pRegResult->ListEntry);
1828 }
1829
1830 if (pReg1->Rect.right > pRect2->right)
1831 {
1832 Assert(pRect2->right > pReg1->Rect.left);
1833 PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate();
1834 pRegResult->Rect.top = topLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.top : topLim;
1835 pRegResult->Rect.left = pRect2->right;
1836 pRegResult->Rect.bottom = bottomLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.bottom : bottomLim;
1837 pRegResult->Rect.right = pReg1->Rect.right;
1838 InsertTailList(&List, &pRegResult->ListEntry);
1839 }
1840
1841 if (pBottomReg)
1842 InsertTailList(&List, &pBottomReg->ListEntry);
1843
1844 PLIST_ENTRY pMemberEntry = pReg1->ListEntry.Flink;
1845 vboxWddmVrListRegRemove(pList1, pReg1);
1846 vboxWddmVrRegTerm(pReg1);
1847
1848 if (IsListEmpty(&List))
1849 return STATUS_SUCCESS; /* the region is covered by the pRect2 */
1850
1851 PLIST_ENTRY pEntry = List.Flink, pNext;
1852 for (; pEntry != &List; pEntry = pNext)
1853 {
1854 pNext = pEntry->Flink;
1855 PVBOXWDDMVR_REG pReg = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry);
1856
1857 vboxWddmVrListRegAddOrder(pList1, pMemberEntry, pReg);
1858 pMemberEntry = pEntry->Flink; /* the following elements should go after the given pEntry since they are ordered already */
1859 }
1860 return STATUS_SUCCESS;
1861}
1862
1863typedef DECLCALLBACK(PLIST_ENTRY) FNVBOXWDDMVR_CB_INTERSECTED_VISITOR(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_REG pReg1, const RECT * pRect2, void *pvContext, PLIST_ENTRY *ppNext);
1864typedef FNVBOXWDDMVR_CB_INTERSECTED_VISITOR *PFNVBOXWDDMVR_CB_INTERSECTED_VISITOR;
1865
1866static void vboxWddmVrListVisitIntersected(PVBOXWDDMVR_LIST pList1, UINT cRects, const RECT *aRects, PFNVBOXWDDMVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
1867{
1868 PLIST_ENTRY pEntry1 = pList1->ListHead.Flink;
1869 PLIST_ENTRY pNext1;
1870 UINT iFirst2 = 0;
1871
1872 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
1873 {
1874 pNext1 = pEntry1->Flink;
1875 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
1876 for (UINT i = iFirst2; i < cRects; ++i)
1877 {
1878 const RECT *pRect2 = &aRects[i];
1879 if (pReg1->Rect.bottom <= pRect2->top)
1880 continue;
1881 else if (pRect2->bottom <= pReg1->Rect.top)
1882 continue;
1883 /* y coords intersect */
1884 else if (pReg1->Rect.right <= pRect2->left)
1885 continue;
1886 else if (pRect2->right <= pReg1->Rect.left)
1887 continue;
1888 /* x coords intersect */
1889
1890 /* the visitor can modify the list 1, apply necessary adjustments after it */
1891 PLIST_ENTRY pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
1892 if (pEntry1 == &pList1->ListHead)
1893 break;
1894 }
1895 }
1896}
1897
1898
1899static void vboxWddmVrListJoinRectsHV(PVBOXWDDMVR_LIST pList, BOOLEAN fHorizontal)
1900{
1901 PLIST_ENTRY pNext1, pNext2;
1902
1903 for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
1904 {
1905 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
1906 pNext1 = pEntry1->Flink;
1907 for (PLIST_ENTRY pEntry2 = pEntry1->Flink; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
1908 {
1909 PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2);
1910 pNext2 = pEntry2->Flink;
1911 if (fHorizontal)
1912 {
1913 if (pReg1->Rect.top == pReg2->Rect.top)
1914 {
1915 if (pReg1->Rect.right == pReg2->Rect.left)
1916 {
1917 /* join rectangles */
1918 vboxWddmVrListRegRemove(pList, pReg2);
1919 if (pReg1->Rect.bottom > pReg2->Rect.bottom)
1920 {
1921 LONG oldRight1 = pReg1->Rect.right;
1922 LONG oldBottom1 = pReg1->Rect.bottom;
1923 pReg1->Rect.right = pReg2->Rect.right;
1924 pReg1->Rect.bottom = pReg2->Rect.bottom;
1925
1926 vboxWddmVrDbgListVerify(pList);
1927
1928 pReg2->Rect.left = pReg1->Rect.left;
1929 pReg2->Rect.top = pReg1->Rect.bottom;
1930 pReg2->Rect.right = oldRight1;
1931 pReg2->Rect.bottom = oldBottom1;
1932 vboxWddmVrListRegAddOrder(pList, pReg1->ListEntry.Flink, pReg2);
1933 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
1934 * and thus can match one of the previous rects */
1935 pNext1 = pList->ListHead.Flink;
1936 break;
1937 }
1938 else if (pReg1->Rect.bottom < pReg2->Rect.bottom)
1939 {
1940 pReg1->Rect.right = pReg2->Rect.right;
1941 vboxWddmVrDbgListVerify(pList);
1942 pReg2->Rect.top = pReg1->Rect.bottom;
1943 vboxWddmVrListRegAddOrder(pList, pReg1->ListEntry.Flink, pReg2);
1944 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
1945 * and thus can match one of the previous rects */
1946 pNext1 = pList->ListHead.Flink;
1947 break;
1948 }
1949 else
1950 {
1951 pReg1->Rect.right = pReg2->Rect.right;
1952 vboxWddmVrDbgListVerify(pList);
1953 /* reset the pNext1 since it could be the pReg2 being destroyed */
1954 pNext1 = pEntry1->Flink;
1955 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
1956 vboxWddmVrRegTerm(pReg2);
1957 }
1958 }
1959 continue;
1960 }
1961 else if (pReg1->Rect.bottom == pReg2->Rect.bottom)
1962 {
1963 Assert(pReg1->Rect.top < pReg2->Rect.top); /* <- since pReg1 > pReg2 && pReg1->Rect.top != pReg2->Rect.top*/
1964 if (pReg1->Rect.right == pReg2->Rect.left)
1965 {
1966 /* join rectangles */
1967 vboxWddmVrListRegRemove(pList, pReg2);
1968
1969 pReg1->Rect.bottom = pReg2->Rect.top;
1970 vboxWddmVrDbgListVerify(pList);
1971 pReg2->Rect.left = pReg1->Rect.left;
1972
1973 vboxWddmVrListRegAddOrder(pList, pReg2->ListEntry.Flink, pReg2);
1974
1975 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
1976 * and thus can match one of the previous rects */
1977 pNext1 = pList->ListHead.Flink;
1978 break;
1979 }
1980 else if (pReg1->Rect.left == pReg2->Rect.right)
1981 {
1982 /* join rectangles */
1983 vboxWddmVrListRegRemove(pList, pReg2);
1984
1985 pReg1->Rect.bottom = pReg2->Rect.top;
1986 vboxWddmVrDbgListVerify(pList);
1987 pReg2->Rect.right = pReg1->Rect.right;
1988
1989 vboxWddmVrListRegAddOrder(pList, pReg2->ListEntry.Flink, pReg2);
1990
1991 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
1992 * and thus can match one of the previous rects */
1993 pNext1 = pList->ListHead.Flink;
1994 break;
1995 }
1996 continue;
1997 }
1998 }
1999 else
2000 {
2001 if (pReg1->Rect.bottom == pReg2->Rect.top)
2002 {
2003 if (pReg1->Rect.left == pReg2->Rect.left)
2004 {
2005 if (pReg1->Rect.right == pReg2->Rect.right)
2006 {
2007 /* join rects */
2008 vboxWddmVrListRegRemove(pList, pReg2);
2009
2010 pReg1->Rect.bottom = pReg2->Rect.bottom;
2011 vboxWddmVrDbgListVerify(pList);
2012
2013 /* reset the pNext1 since it could be the pReg2 being destroyed */
2014 pNext1 = pEntry1->Flink;
2015 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
2016 vboxWddmVrRegTerm(pReg2);
2017 continue;
2018 }
2019 /* no more to be done for for pReg1 */
2020 break;
2021 }
2022 else if (pReg1->Rect.right > pReg2->Rect.left)
2023 {
2024 /* no more to be done for for pReg1 */
2025 break;
2026 }
2027
2028 continue;
2029 }
2030 else if (pReg1->Rect.bottom < pReg2->Rect.top)
2031 {
2032 /* no more to be done for for pReg1 */
2033 break;
2034 }
2035 }
2036 }
2037 }
2038}
2039
2040static void vboxWddmVrListJoinRects(PVBOXWDDMVR_LIST pList)
2041{
2042 vboxWddmVrListJoinRectsHV(pList, TRUE);
2043 vboxWddmVrListJoinRectsHV(pList, FALSE);
2044}
2045
2046typedef struct VBOXWDDMVR_CBDATA_SUBST
2047{
2048 NTSTATUS Status;
2049 BOOLEAN fChanged;
2050} VBOXWDDMVR_CBDATA_SUBST, *PVBOXWDDMVR_CBDATA_SUBST;
2051
2052static DECLCALLBACK(PLIST_ENTRY) vboxWddmVrListSubstNoJoinCb(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg1, const RECT *pRect2, void *pvContext, PLIST_ENTRY *ppNext)
2053{
2054 PVBOXWDDMVR_CBDATA_SUBST pData = (PVBOXWDDMVR_CBDATA_SUBST)pvContext;
2055 /* store the prev to get the new Flink out of it*/
2056 PLIST_ENTRY pPrev = pReg1->ListEntry.Blink;
2057 pData->fChanged = TRUE;
2058
2059 Assert(vboxWddmRectIsIntersect(&pReg1->Rect, pRect2));
2060
2061 /* NOTE: the pReg1 will be invalid after the vboxWddmVrListRegIntersectSubstNoJoin call!!! */
2062 NTSTATUS Status = vboxWddmVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
2063 if (NT_SUCCESS(Status))
2064 {
2065 *ppNext = pPrev->Flink;
2066 return &pList->ListHead;
2067 }
2068 WARN(("vboxWddmVrListRegIntersectSubstNoJoin failed!"));
2069 Assert(!NT_SUCCESS(Status));
2070 pData->Status = Status;
2071 *ppNext = &pList->ListHead;
2072 return &pList->ListHead;
2073}
2074
2075static NTSTATUS vboxWddmVrListSubstNoJoin(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged)
2076{
2077 if (VBoxWddmVrListIsEmpty(pList))
2078 return STATUS_SUCCESS;
2079
2080 VBOXWDDMVR_CBDATA_SUBST Data;
2081 Data.Status = STATUS_SUCCESS;
2082 Data.fChanged = FALSE;
2083
2084 *pfChanged = FALSE;
2085
2086 vboxWddmVrListVisitIntersected(pList, cRects, aRects, vboxWddmVrListSubstNoJoinCb, &Data);
2087 if (!NT_SUCCESS(Data.Status))
2088 {
2089 WARN(("vboxWddmVrListVisitIntersected failed!"));
2090 return Data.Status;
2091 }
2092
2093 *pfChanged = Data.fChanged;
2094 return STATUS_SUCCESS;
2095}
2096
2097#if 0
2098static const PRECT vboxWddmVrRectsOrder(UINT cRects, const PRECT aRects)
2099{
2100#ifdef DEBUG
2101 {
2102 for (UINT i = 0; i < cRects; ++i)
2103 {
2104 RECT *pRectI = &aRects[i];
2105 for (UINT j = i + 1; j < cRects; ++j)
2106 {
2107 RECT *pRectJ = &aRects[j];
2108 Assert(!vboxWddmRectIsIntersect(pRectI, pRectJ));
2109 }
2110 }
2111 }
2112#endif
2113
2114 RECT * pRects = (RECT *)aRects;
2115 /* check if rects are ordered already */
2116 for (UINT i = 0; i < cRects - 1; ++i)
2117 {
2118 RECT *pRect1 = &pRects[i];
2119 RECT *pRect2 = &pRects[i+1];
2120 if (vboxWddmVrRegNonintersectedComparator(pRect1, pRect2) < 0)
2121 continue;
2122
2123 WARN(("rects are unoreded!"));
2124
2125 if (pRects == aRects)
2126 {
2127 pRects = (RECT *)vboxWddmMemAlloc(sizeof (RECT) * cRects);
2128 if (!pRects)
2129 {
2130 WARN(("vboxWddmMemAlloc failed!"));
2131 return NULL;
2132 }
2133
2134 memcpy(pRects, aRects, sizeof (RECT) * cRects);
2135 }
2136
2137 Assert(pRects != aRects);
2138
2139 int j = (int)i - 1;
2140 do {
2141 RECT Tmp = *pRect1;
2142 *pRect1 = *pRect2;
2143 *pRect2 = Tmp;
2144
2145 if (j < 0)
2146 break;
2147
2148 if (vboxWddmVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
2149 break;
2150
2151 pRect2 = pRect1--;
2152 --j;
2153 } while (1);
2154 }
2155
2156 return pRects;
2157}
2158#endif
2159
2160void VBoxWddmVrListTranslate(PVBOXWDDMVR_LIST pList, LONG x, LONG y)
2161{
2162 for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink)
2163 {
2164 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
2165 vboxWddmRectTranslate(&pReg1->Rect, x, y);
2166 }
2167}
2168
2169NTSTATUS VBoxWddmVrListRectsSubst(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged)
2170{
2171#if 0
2172 const PRECT pRects = vboxWddmVrRectsOrder(cRects, aRects);
2173 if (!pRects)
2174 {
2175 WARN(("vboxWddmVrRectsOrder failed!"));
2176 return STATUS_NO_MEMORY;
2177 }
2178#endif
2179
2180 NTSTATUS Status = vboxWddmVrListSubstNoJoin(pList, cRects, aRects, pfChanged);
2181 if (!NT_SUCCESS(Status))
2182 {
2183 WARN(("vboxWddmVrListSubstNoJoin failed!"));
2184 goto done;
2185 }
2186
2187 if (!*pfChanged)
2188 goto done;
2189
2190 vboxWddmVrListJoinRects(pList);
2191
2192done:
2193#if 0
2194 if (pRects != aRects)
2195 vboxWddmMemFree(pRects);
2196#endif
2197 return Status;
2198}
2199
2200NTSTATUS VBoxWddmVrListRectsAdd(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged)
2201{
2202 UINT cCovered = 0;
2203
2204#if 0
2205#ifdef DEBUG
2206 {
2207 for (UINT i = 0; i < cRects; ++i)
2208 {
2209 RECT *pRectI = &aRects[i];
2210 for (UINT j = i + 1; j < cRects; ++j)
2211 {
2212 RECT *pRectJ = &aRects[j];
2213 Assert(!vboxWddmRectIsIntersect(pRectI, pRectJ));
2214 }
2215 }
2216 }
2217#endif
2218#endif
2219
2220 /* early sort out the case when there are no new rects */
2221 for (UINT i = 0; i < cRects; ++i)
2222 {
2223 for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink)
2224 {
2225 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
2226 if (vboxWddmRectIsCoveres(&pReg1->Rect, &aRects[i]))
2227 {
2228 cCovered++;
2229 break;
2230 }
2231 }
2232 }
2233
2234 if (cCovered == cRects)
2235 {
2236 *pfChanged = FALSE;
2237 return STATUS_SUCCESS;
2238 }
2239
2240 /* rects are not covered, need to go the slow way */
2241
2242 VBOXWDDMVR_LIST DiffList;
2243 VBoxWddmVrListInit(&DiffList);
2244 PRECT pListRects = NULL;
2245 UINT cAllocatedRects = 0;
2246 BOOLEAN fNeedRectreate = TRUE;
2247 BOOLEAN fChanged = FALSE;
2248 NTSTATUS Status = STATUS_SUCCESS;
2249
2250 for (UINT i = 0; i < cRects; ++i)
2251 {
2252 PVBOXWDDMVR_REG pReg = vboxWddmVrRegCreate();
2253 if (!pReg)
2254 {
2255 WARN(("vboxWddmVrRegCreate failed!"));
2256 Status = STATUS_NO_MEMORY;
2257 break;
2258 }
2259 pReg->Rect = aRects[i];
2260
2261 UINT cListRects = VBoxWddmVrListRectsCount(pList);
2262 if (!cListRects)
2263 {
2264 vboxWddmVrListRegAdd(pList, pReg, &pList->ListHead, FALSE);
2265 fChanged = TRUE;
2266 continue;
2267 }
2268 else
2269 {
2270 Assert(VBoxWddmVrListIsEmpty(&DiffList));
2271 vboxWddmVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, FALSE);
2272 }
2273
2274 if (cAllocatedRects < cListRects)
2275 {
2276 cAllocatedRects = cListRects + cRects;
2277 Assert(fNeedRectreate);
2278 if (pListRects)
2279 vboxWddmMemFree(pListRects);
2280 pListRects = (PRECT)vboxWddmMemAlloc(sizeof (RECT) * cAllocatedRects);
2281 if (!pListRects)
2282 {
2283 WARN(("vboxWddmMemAllocZero failed!"));
2284 Status = STATUS_NO_MEMORY;
2285 break;
2286 }
2287 }
2288
2289
2290 if (fNeedRectreate)
2291 {
2292 Status = VBoxWddmVrListRectsGet(pList, cListRects, pListRects);
2293 Assert(Status == STATUS_SUCCESS);
2294 fNeedRectreate = FALSE;
2295 }
2296
2297 BOOLEAN fDummyChanged = FALSE;
2298 Status = vboxWddmVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
2299 if (!NT_SUCCESS(Status))
2300 {
2301 WARN(("vboxWddmVrListSubstNoJoin failed!"));
2302 Status = STATUS_NO_MEMORY;
2303 break;
2304 }
2305
2306 if (!VBoxWddmVrListIsEmpty(&DiffList))
2307 {
2308 vboxWddmVrListAddNonintersected(pList, &DiffList);
2309 fNeedRectreate = TRUE;
2310 fChanged = TRUE;
2311 }
2312
2313 Assert(VBoxWddmVrListIsEmpty(&DiffList));
2314 }
2315
2316 if (pListRects)
2317 vboxWddmMemFree(pListRects);
2318
2319 Assert(VBoxWddmVrListIsEmpty(&DiffList) || Status != STATUS_SUCCESS);
2320 VBoxWddmVrListClear(&DiffList);
2321
2322 if (fChanged)
2323 vboxWddmVrListJoinRects(pList);
2324
2325 *pfChanged = fChanged;
2326
2327 return STATUS_SUCCESS;
2328}
2329
2330NTSTATUS VBoxWddmVrListRectsGet(PVBOXWDDMVR_LIST pList, UINT cRects, PRECT aRects)
2331{
2332 if (cRects < VBoxWddmVrListRectsCount(pList))
2333 return STATUS_BUFFER_TOO_SMALL;
2334
2335 UINT i = 0;
2336 for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink, ++i)
2337 {
2338 PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1);
2339 aRects[i] = pReg1->Rect;
2340 }
2341 return STATUS_SUCCESS;
2342}
2343
2344NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr)
2345{
2346 HANDLE hKey;
2347 OBJECT_ATTRIBUTES ObjAttr;
2348
2349 InitializeObjectAttributes(&ObjAttr, pRegStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2350
2351 NTSTATUS Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjAttr);
2352 if (!NT_SUCCESS(Status))
2353 {
2354 WARN(("ZwOpenKey for settings key failed, Status 0x%x", Status));
2355 return Status;
2356 }
2357
2358 DWORD dwValue = 0;
2359 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_LOG_UM, &dwValue);
2360 if (NT_SUCCESS(Status))
2361 g_VBoxLogUm = dwValue;
2362
2363 ZwClose(hKey);
2364
2365 return Status;
2366}
2367
2368NTSTATUS vboxWddmThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
2369{
2370 NTSTATUS fStatus;
2371 HANDLE hThread;
2372 OBJECT_ATTRIBUTES fObjectAttributes;
2373
2374 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2375
2376 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
2377 NULL, NULL);
2378
2379 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
2380 &fObjectAttributes, NULL, NULL,
2381 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
2382 if (!NT_SUCCESS(fStatus))
2383 return fStatus;
2384
2385 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
2386 KernelMode, (PVOID*) ppThread, NULL);
2387 ZwClose(hThread);
2388 return STATUS_SUCCESS;
2389}
2390
2391#ifdef VBOX_VDMA_WITH_WATCHDOG
2392static int vboxWddmWdProgram(PVBOXMP_DEVEXT pDevExt, uint32_t cMillis)
2393{
2394 int rc = VINF_SUCCESS;
2395 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMICommandAlloc(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, sizeof (VBOXVDMA_CTL), HGSMI_CH_VBVA, VBVA_VDMA_CTL);
2396 if (pCmd)
2397 {
2398 pCmd->enmCtl = VBOXVDMA_CTL_TYPE_WATCHDOG;
2399 pCmd->u32Offset = cMillis;
2400 pCmd->i32Result = VERR_NOT_SUPPORTED;
2401
2402 const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
2403 Assert(pHdr);
2404 if (pHdr)
2405 {
2406 do
2407 {
2408 HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
2409 Assert(offCmd != HGSMIOFFSET_VOID);
2410 if (offCmd != HGSMIOFFSET_VOID)
2411 {
2412 VBoxVideoCmnPortWriteUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port, offCmd);
2413 rc = VBoxSHGSMICommandDoneSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
2414 AssertRC(rc);
2415 if (RT_SUCCESS(rc))
2416 {
2417 rc = pCmd->i32Result;
2418 AssertRC(rc);
2419 }
2420 break;
2421 }
2422 else
2423 rc = VERR_INVALID_PARAMETER;
2424 /* fail to submit, cancel it */
2425 VBoxSHGSMICommandCancelSynch(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pHdr);
2426 } while (0);
2427 }
2428
2429 VBoxSHGSMICommandFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pCmd);
2430 }
2431 else
2432 {
2433 LOGREL(("HGSMIHeapAlloc failed"));
2434 rc = VERR_OUT_OF_RESOURCES;
2435 }
2436 return rc;
2437}
2438
2439static uint32_t g_VBoxWdTimeout = 4000;
2440/* if null g_VBoxWdTimeout / 2 is used */
2441static uint32_t g_VBoxWdTimerPeriod = 0;
2442
2443static VOID vboxWddmWdThread(PVOID pvUser)
2444{
2445 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvUser;
2446 BOOLEAN bExit = FALSE;
2447 int rc;
2448 while (1)
2449 {
2450 if (!bExit)
2451 {
2452 rc = vboxWddmWdProgram(pDevExt, g_VBoxWdTimeout /* ms */);
2453 AssertRC(rc);
2454 }
2455 else
2456 {
2457 rc = vboxWddmWdProgram(pDevExt, 0 /* to disable WatchDog */);
2458 AssertRC(rc);
2459 break;
2460 }
2461 LARGE_INTEGER Timeout;
2462 uint32_t timerTimeOut = g_VBoxWdTimerPeriod ? g_VBoxWdTimerPeriod : g_VBoxWdTimeout / 2;
2463 Timeout.QuadPart = 10000ULL * timerTimeOut /* ms */;
2464 NTSTATUS Status = KeWaitForSingleObject(&pDevExt->WdEvent, Executive, KernelMode, FALSE, &Timeout);
2465 if (Status != STATUS_TIMEOUT)
2466 bExit = TRUE;
2467 }
2468}
2469
2470NTSTATUS vboxWddmWdInit(PVBOXMP_DEVEXT pDevExt)
2471{
2472 KeInitializeEvent(&pDevExt->WdEvent, NotificationEvent, FALSE);
2473
2474 NTSTATUS Status = vboxWddmThreadCreate(&pDevExt->pWdThread, vboxWddmWdThread, pDevExt);
2475 if (!NT_SUCCESS(Status))
2476 {
2477 WARN(("vboxWddmThreadCreate failed, Status 0x%x", Status));
2478 pDevExt->pWdThread = NULL;
2479 }
2480 return Status;
2481}
2482
2483NTSTATUS vboxWddmWdTerm(PVBOXMP_DEVEXT pDevExt)
2484{
2485 if (!pDevExt->pWdThread)
2486 return STATUS_SUCCESS;
2487
2488 KeSetEvent(&pDevExt->WdEvent, 0, FALSE);
2489
2490 KeWaitForSingleObject(pDevExt->pWdThread, Executive, KernelMode, FALSE, NULL);
2491 ObDereferenceObject(pDevExt->pWdThread);
2492 pDevExt->pWdThread = NULL;
2493 return STATUS_SUCCESS;
2494}
2495#endif
2496
2497static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags)
2498{
2499 PHGSMIGUESTCOMMANDCONTEXT pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
2500 VBVASCANLINECFG *pCfg;
2501 int rc = VINF_SUCCESS;
2502
2503 /* Allocate the IO buffer. */
2504 pCfg = (VBVASCANLINECFG *)VBoxHGSMIBufferAlloc(pCtx,
2505 sizeof (VBVASCANLINECFG), HGSMI_CH_VBVA,
2506 VBVA_SCANLINE_CFG);
2507
2508 if (pCfg)
2509 {
2510 /* Prepare data to be sent to the host. */
2511 pCfg->rc = VERR_NOT_IMPLEMENTED;
2512 pCfg->fFlags = fFlags;
2513 rc = VBoxHGSMIBufferSubmit(pCtx, pCfg);
2514 if (RT_SUCCESS(rc))
2515 {
2516 AssertRC(pCfg->rc);
2517 rc = pCfg->rc;
2518 }
2519 /* Free the IO buffer. */
2520 VBoxHGSMIBufferFree(pCtx, pCfg);
2521 }
2522 else
2523 rc = VERR_NO_MEMORY;
2524 return rc;
2525}
2526
2527NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
2528{
2529 if (!fEnable)
2530 {
2531 KeCancelTimer(&pDevExt->VSyncTimer);
2532 }
2533 else
2534 {
2535 LARGE_INTEGER DueTime;
2536 DueTime.QuadPart = -166666LL; /* 60 Hz */
2537 KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 17, &pDevExt->VSyncDpc);
2538 }
2539 return STATUS_SUCCESS;
2540}
2541
2542NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGetScanLine)
2543{
2544 Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pGetScanLine->VidPnTargetId);
2545 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[pGetScanLine->VidPnTargetId];
2546 Assert(pTarget->HeightTotal);
2547 Assert(pTarget->HeightVisible);
2548 Assert(pTarget->HeightTotal > pTarget->HeightVisible);
2549 Assert(pTarget->ScanLineState < pTarget->HeightTotal);
2550 if (pTarget->HeightTotal)
2551 {
2552 uint32_t curScanLine = pTarget->ScanLineState;
2553 ++pTarget->ScanLineState;
2554 if (pTarget->ScanLineState >= pTarget->HeightTotal)
2555 pTarget->ScanLineState = 0;
2556
2557
2558 BOOL bVBlank = (!curScanLine || curScanLine > pTarget->HeightVisible);
2559 pGetScanLine->ScanLine = curScanLine;
2560 pGetScanLine->InVerticalBlank = bVBlank;
2561 }
2562 else
2563 {
2564 pGetScanLine->InVerticalBlank = TRUE;
2565 pGetScanLine->ScanLine = 0;
2566 }
2567 return STATUS_SUCCESS;
2568}
2569
2570static VOID vboxWddmSlVSyncDpc(
2571 __in struct _KDPC *Dpc,
2572 __in_opt PVOID DeferredContext,
2573 __in_opt PVOID SystemArgument1,
2574 __in_opt PVOID SystemArgument2
2575)
2576{
2577 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext;
2578 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
2579 BOOLEAN bNeedDpc = FALSE;
2580 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
2581 {
2582 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i];
2583 PVBOXWDDM_ALLOCATION pPrimary = pSource->pPrimaryAllocation;
2584 if (pPrimary && pPrimary->offVram != VBOXVIDEOOFFSET_VOID)
2585 {
2586 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
2587 notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC;
2588 /* @todo: !!!this is not correct in case we want source[i]->target[i!=j] mapping */
2589 notify.CrtcVsync.VidPnTargetId = i;
2590 notify.CrtcVsync.PhysicalAddress.QuadPart = pPrimary->offVram;
2591 /* yes, we can report VSync at dispatch */
2592 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
2593 bNeedDpc = TRUE;
2594 }
2595 }
2596
2597 if (bNeedDpc)
2598 {
2599 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
2600 }
2601}
2602
2603NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt)
2604{
2605 KeInitializeTimer(&pDevExt->VSyncTimer);
2606 KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt);
2607 return STATUS_SUCCESS;
2608}
2609
2610NTSTATUS VBoxWddmSlTerm(PVBOXMP_DEVEXT pDevExt)
2611{
2612 KeCancelTimer(&pDevExt->VSyncTimer);
2613 return STATUS_SUCCESS;
2614}
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