VirtualBox

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

Last change on this file since 89361 was 84697, checked in by vboxsync, 5 years ago

WDDM: log the refresh rate for debug purposes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.9 KB
Line 
1/* $Id: VBoxMPMisc.cpp 84697 2020-06-05 15:03:45Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPWddm.h"
19#include <VBoxVideoVBE.h>
20#include <iprt/param.h>
21#include <iprt/utf16.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 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 AssertNtStatusSuccess(Status);
86 if (Status != STATUS_SUCCESS)
87 return VBOXWDDM_HANDLE_INVALID;
88 }
89 for (UINT i = pTbl->iNext2Search; ; i = (i + 1) % 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 /* not reached */
103}
104
105PVOID vboxWddmHTableRemove(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
106{
107 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
108 Assert(iIndex < pTbl->cSize);
109 if (iIndex < pTbl->cSize)
110 {
111 PVOID pvData = pTbl->paData[iIndex];
112 pTbl->paData[iIndex] = NULL;
113 --pTbl->cData;
114 Assert(pTbl->cData <= pTbl->cSize);
115 pTbl->iNext2Search = iIndex;
116 return pvData;
117 }
118 return NULL;
119}
120
121PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
122{
123 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
124 Assert(iIndex < pTbl->cSize);
125 if (iIndex < pTbl->cSize)
126 return pTbl->paData[iIndex];
127 return NULL;
128}
129
130VOID vboxWddmHTableIterInit(PVBOXWDDM_HTABLE pTbl, PVBOXWDDM_HTABLE_ITERATOR pIter)
131{
132 pIter->pTbl = pTbl;
133 pIter->iCur = ~0UL;
134 pIter->cLeft = pTbl->cData;
135}
136
137BOOL vboxWddmHTableIterHasNext(PVBOXWDDM_HTABLE_ITERATOR pIter)
138{
139 return pIter->cLeft;
140}
141
142
143PVOID vboxWddmHTableIterNext(PVBOXWDDM_HTABLE_ITERATOR pIter, VBOXWDDM_HANDLE *phHandle)
144{
145 if (vboxWddmHTableIterHasNext(pIter))
146 {
147 for (uint32_t i = pIter->iCur+1; i < pIter->pTbl->cSize ; ++i)
148 {
149 if (pIter->pTbl->paData[i])
150 {
151 pIter->iCur = i;
152 --pIter->cLeft;
153 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(i);
154 Assert(hHandle);
155 if (phHandle)
156 *phHandle = hHandle;
157 return pIter->pTbl->paData[i];
158 }
159 }
160 }
161
162 Assert(!vboxWddmHTableIterHasNext(pIter));
163 if (phHandle)
164 *phHandle = VBOXWDDM_HANDLE_INVALID;
165 return NULL;
166}
167
168
169PVOID vboxWddmHTableIterRemoveCur(PVBOXWDDM_HTABLE_ITERATOR pIter)
170{
171 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(pIter->iCur);
172 Assert(hHandle);
173 if (hHandle)
174 {
175 PVOID pRet = vboxWddmHTableRemove(pIter->pTbl, hHandle);
176 Assert(pRet);
177 return pRet;
178 }
179 return NULL;
180}
181
182NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
183{
184 WCHAR fallBackBuf[2];
185 PWCHAR pSuffix;
186 bool bFallback = false;
187
188 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
189 {
190 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
191 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
192 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
193 }
194 else
195 {
196 pSuffix = fallBackBuf;
197 cbBuf = sizeof (fallBackBuf);
198 bFallback = true;
199 }
200
201 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
202 DevicePropertyDriverKeyName,
203 cbBuf,
204 pSuffix,
205 &cbBuf);
206 if (Status == STATUS_SUCCESS && bFallback)
207 Status = STATUS_BUFFER_TOO_SMALL;
208 if (Status == STATUS_BUFFER_TOO_SMALL)
209 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
210
211 return Status;
212}
213
214NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
215 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
216{
217 NTSTATUS Status = STATUS_SUCCESS;
218 const WCHAR* pKeyPrefix;
219 UINT cbKeyPrefix;
220 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
221 Assert(pVGuid);
222 if (!pVGuid)
223 return STATUS_UNSUCCESSFUL;
224
225 uint32_t build;
226 vboxWinVersion_t ver = VBoxQueryWinVersion(&build);
227 if (ver == WINVERSION_VISTA)
228 {
229 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
230 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
231 }
232 else if (ver >= WINVERSION_10 && build >= 17763)
233 {
234 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN10_17763;
235 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN10_17763);
236 }
237 else
238 {
239 Assert(ver > WINVERSION_VISTA);
240 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
241 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
242 }
243
244 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
245 if (cbBuf >= cbResult)
246 {
247 ssize_t cwcFmt = RTUtf16Printf(pBuf, cbBuf / sizeof(WCHAR), "%ls%.*ls\\%04d",
248 pKeyPrefix, pVGuid->Length / sizeof(WCHAR), pVGuid->Buffer, VidPnSourceId);
249 Assert((size_t)cwcFmt + 1 == cbResult / sizeof(WCHAR)); RT_NOREF(cwcFmt);
250 }
251 else
252 {
253 Status = STATUS_BUFFER_TOO_SMALL;
254 }
255
256 *pcbResult = cbResult;
257
258 return Status;
259}
260
261NTSTATUS vboxWddmRegQueryVideoGuidString(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
262{
263 BOOLEAN fNewMethodSucceeded = FALSE;
264 HANDLE hKey = NULL;
265 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DEVICE, GENERIC_READ, &hKey);
266 if (NT_SUCCESS(Status))
267 {
268 struct
269 {
270 KEY_VALUE_PARTIAL_INFORMATION Info;
271 UCHAR Buf[1024]; /* should be enough */
272 } KeyData;
273 ULONG cbResult;
274 UNICODE_STRING RtlStr;
275 RtlInitUnicodeString(&RtlStr, L"VideoID");
276 Status = ZwQueryValueKey(hKey,
277 &RtlStr,
278 KeyValuePartialInformation,
279 &KeyData.Info,
280 sizeof(KeyData),
281 &cbResult);
282 if (NT_SUCCESS(Status))
283 {
284 if (KeyData.Info.Type == REG_SZ)
285 {
286 fNewMethodSucceeded = TRUE;
287 *pcbResult = KeyData.Info.DataLength + 2;
288 if (cbBuf >= KeyData.Info.DataLength)
289 {
290 memcpy(pBuf, KeyData.Info.Data, KeyData.Info.DataLength + 2);
291 Status = STATUS_SUCCESS;
292 }
293 else
294 Status = STATUS_BUFFER_TOO_SMALL;
295 }
296 }
297 else
298 {
299 WARN(("ZwQueryValueKey failed, Status 0x%x", Status));
300 }
301
302 NTSTATUS rcNt2 = ZwClose(hKey);
303 AssertNtStatusSuccess(rcNt2);
304 }
305 else
306 {
307 WARN(("IoOpenDeviceRegistryKey failed Status 0x%x", Status));
308 }
309
310 if (fNewMethodSucceeded)
311 return Status;
312 else
313 WARN(("failed to acquire the VideoID, falling back to the old impl"));
314
315 Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
316 //AssertNtStatusSuccess(Status);
317 if (Status == STATUS_SUCCESS)
318 {
319 struct
320 {
321 KEY_BASIC_INFORMATION Name;
322 WCHAR Buf[256];
323 } Buf;
324 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
325 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
326 ULONG ResultLength;
327 BOOL bFound = FALSE;
328 for (ULONG i = 0; !bFound; ++i)
329 {
330 RtlZeroMemory(&Buf, sizeof (Buf));
331 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
332 AssertNtStatusSuccess(Status);
333 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
334 if (Status != STATUS_SUCCESS)
335 break;
336
337 HANDLE hSubKey;
338 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
339 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
340 pSubBuf += Buf.Name.NameLength/2;
341 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
342 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
343 //AssertNtStatusSuccess(Status);
344 if (Status == STATUS_SUCCESS)
345 {
346 struct
347 {
348 KEY_VALUE_PARTIAL_INFORMATION Info;
349 UCHAR Buf[sizeof (VBOX_WDDM_DRIVERNAME)]; /* should be enough */
350 } KeyData;
351 ULONG cbResult;
352 UNICODE_STRING RtlStr;
353 RtlInitUnicodeString(&RtlStr, L"Service");
354 Status = ZwQueryValueKey(hSubKey,
355 &RtlStr,
356 KeyValuePartialInformation,
357 &KeyData.Info,
358 sizeof(KeyData),
359 &cbResult);
360 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
361 if (Status == STATUS_SUCCESS)
362 {
363 if (KeyData.Info.Type == REG_SZ)
364 {
365 if (KeyData.Info.DataLength == sizeof (VBOX_WDDM_DRIVERNAME))
366 {
367 if (!wcscmp(VBOX_WDDM_DRIVERNAME, (PWCHAR)KeyData.Info.Data))
368 {
369 bFound = TRUE;
370 *pcbResult = Buf.Name.NameLength + 2;
371 if (cbBuf >= Buf.Name.NameLength + 2)
372 {
373 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
374 }
375 else
376 {
377 Status = STATUS_BUFFER_TOO_SMALL;
378 }
379 }
380 }
381 }
382 }
383
384 NTSTATUS rcNt2 = ZwClose(hSubKey);
385 AssertNtStatusSuccess(rcNt2);
386 }
387 else
388 break;
389 }
390 NTSTATUS rcNt2 = ZwClose(hKey);
391 AssertNtStatusSuccess(rcNt2);
392 }
393
394 return Status;
395}
396
397NTSTATUS vboxWddmRegOpenKeyEx(OUT PHANDLE phKey, IN HANDLE hRootKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
398{
399 OBJECT_ATTRIBUTES ObjAttr;
400 UNICODE_STRING RtlStr;
401
402 RtlInitUnicodeString(&RtlStr, pName);
403 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hRootKey, NULL);
404
405 return ZwOpenKey(phKey, fAccess, &ObjAttr);
406}
407
408NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
409{
410 return vboxWddmRegOpenKeyEx(phKey, NULL, pName, fAccess);
411}
412
413NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
414 OUT PHANDLE phKey)
415{
416 WCHAR Buf[512];
417 ULONG cbBuf = sizeof(Buf);
418 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDevExt, VidPnSourceId, cbBuf, Buf, &cbBuf);
419 AssertNtStatusSuccess(Status);
420 if (Status == STATUS_SUCCESS)
421 {
422 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
423 AssertNtStatusSuccess(Status);
424 if(Status == STATUS_SUCCESS)
425 return STATUS_SUCCESS;
426 }
427
428 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
429 * basically needed to make as less modifications to the current XPDM code as possible */
430 *phKey = NULL;
431
432 return Status;
433}
434
435NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
436{
437 DWORD dwVal;
438 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
439 AssertNtStatusSuccess(Status);
440 if (Status == STATUS_SUCCESS)
441 {
442 *pResult = (int)dwVal;
443 }
444
445 return Status;
446}
447
448NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
449{
450 DWORD dwVal;
451 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
452 AssertNtStatusSuccess(Status);
453 if (Status == STATUS_SUCCESS)
454 {
455 *pResult = (int)dwVal;
456 }
457
458 return Status;
459}
460
461NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
462{
463 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
464 HANDLE hKey;
465 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDevExt, VidPnSourceId, &hKey);
466 //AssertNtStatusSuccess(Status);
467 if (Status == STATUS_SUCCESS)
468 {
469 int x, y;
470 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
471 AssertNtStatusSuccess(Status);
472 if (Status == STATUS_SUCCESS)
473 {
474 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
475 AssertNtStatusSuccess(Status);
476 if (Status == STATUS_SUCCESS)
477 {
478 pPos->x = x;
479 pPos->y = y;
480 }
481 }
482 NTSTATUS rcNt2 = ZwClose(hKey);
483 AssertNtStatusSuccess(rcNt2);
484 }
485
486 return Status;
487}
488
489void vboxWddmDisplaySettingsCheckPos(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
490{
491 POINT Pos = {0};
492 NTSTATUS Status = vboxWddmDisplaySettingsQueryPos(pDevExt, VidPnSourceId, &Pos);
493 if (!NT_SUCCESS(Status))
494 {
495 Log(("vboxWddmDisplaySettingsQueryPos failed %#x", Status));
496 return;
497 }
498
499 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
500
501 if (!memcmp(&pSource->VScreenPos, &Pos, sizeof (Pos)))
502 return;
503
504 pSource->VScreenPos = Pos;
505 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS;
506
507 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
508}
509
510NTSTATUS vboxWddmRegDrvFlagsSet(PVBOXMP_DEVEXT pDevExt, DWORD fVal)
511{
512 HANDLE hKey = NULL;
513 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
514 if (!NT_SUCCESS(Status))
515 {
516 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
517 return Status;
518 }
519
520 Status = vboxWddmRegSetValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, fVal);
521 if (!NT_SUCCESS(Status))
522 WARN(("vboxWddmRegSetValueDword failed, Status = 0x%x", Status));
523
524 NTSTATUS rcNt2 = ZwClose(hKey);
525 AssertNtStatusSuccess(rcNt2);
526
527 return Status;
528}
529
530DWORD vboxWddmRegDrvFlagsGet(PVBOXMP_DEVEXT pDevExt, DWORD fDefault)
531{
532 HANDLE hKey = NULL;
533 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey);
534 if (!NT_SUCCESS(Status))
535 {
536 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
537 return fDefault;
538 }
539
540 DWORD dwVal = 0;
541 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal);
542 if (!NT_SUCCESS(Status))
543 {
544 WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
545 dwVal = fDefault;
546 }
547
548 NTSTATUS rcNt2 = ZwClose(hKey);
549 AssertNtStatusSuccess(rcNt2);
550
551 return dwVal;
552}
553
554NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
555{
556 struct
557 {
558 KEY_VALUE_PARTIAL_INFORMATION Info;
559 UCHAR Buf[32]; /* should be enough */
560 } Buf;
561 ULONG cbBuf;
562 UNICODE_STRING RtlStr;
563 RtlInitUnicodeString(&RtlStr, pName);
564 NTSTATUS Status = ZwQueryValueKey(hKey,
565 &RtlStr,
566 KeyValuePartialInformation,
567 &Buf.Info,
568 sizeof(Buf),
569 &cbBuf);
570 if (Status == STATUS_SUCCESS)
571 {
572 if (Buf.Info.Type == REG_DWORD)
573 {
574 Assert(Buf.Info.DataLength == 4);
575 *pDword = *((PULONG)Buf.Info.Data);
576 return STATUS_SUCCESS;
577 }
578 }
579
580 return STATUS_INVALID_PARAMETER;
581}
582
583NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, IN DWORD val)
584{
585 UNICODE_STRING RtlStr;
586 RtlInitUnicodeString(&RtlStr, pName);
587 return ZwSetValueKey(hKey, &RtlStr,
588 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
589 REG_DWORD,
590 &val,
591 sizeof(val));
592}
593
594UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt)
595{
596 if (pDevExt->VideoGuid.Buffer)
597 return &pDevExt->VideoGuid;
598
599 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
600 WCHAR VideoGuidBuf[512];
601 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
602 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(pDevExt ,cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
603 AssertNtStatusSuccess(Status);
604 if (Status == STATUS_SUCCESS)
605 {
606 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
607 Assert(pBuf);
608 if (pBuf)
609 {
610 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
611 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
612 return &pDevExt->VideoGuid;
613 }
614 }
615
616 return NULL;
617}
618
619VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt)
620{
621 if (pDevExt->VideoGuid.Buffer)
622 {
623 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
624 pDevExt->VideoGuid.Buffer = NULL;
625 }
626}
627
628/* mm */
629
630NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
631{
632 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
633 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
634 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
635 if (!pBuf)
636 {
637 Assert(0);
638 return STATUS_NO_MEMORY;
639 }
640 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
641 pMm->cPages = cPages;
642 pMm->cAllocs = 0;
643 pMm->pBuffer = pBuf;
644 return STATUS_SUCCESS;
645}
646
647ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
648{
649 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
650 if (iPage == 0xFFFFFFFF)
651 {
652 Assert(0);
653 return VBOXWDDM_MM_VOID;
654 }
655
656 ++pMm->cAllocs;
657 return iPage;
658}
659
660VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
661{
662 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
663 RtlClearBits(&pMm->BitMap, iPage, cPages);
664 --pMm->cAllocs;
665 Assert(pMm->cAllocs < UINT32_MAX);
666}
667
668NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
669{
670 Assert(!pMm->cAllocs);
671 vboxWddmMemFree(pMm->pBuffer);
672 pMm->pBuffer = NULL;
673 return STATUS_SUCCESS;
674}
675
676
677
678typedef struct VBOXVIDEOCM_ALLOC
679{
680 VBOXWDDM_HANDLE hGlobalHandle;
681 uint32_t offData;
682 uint32_t cbData;
683} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
684
685typedef struct VBOXVIDEOCM_ALLOC_REF
686{
687 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
688 VBOXWDDM_HANDLE hSessionHandle;
689 PVBOXVIDEOCM_ALLOC pAlloc;
690 PKEVENT pSynchEvent;
691 VBOXUHGSMI_BUFFER_TYPE_FLAGS fUhgsmiType;
692 volatile uint32_t cRefs;
693 PVOID pvUm;
694 MDL Mdl;
695} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
696
697
698NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
699{
700 NTSTATUS Status = STATUS_UNSUCCESSFUL;
701 UINT cbSize = pAlloc->cbData;
702 UINT cPages = BYTES_TO_PAGES(cbSize);
703 ExAcquireFastMutex(&pMgr->Mutex);
704 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
705 if (iPage != VBOXWDDM_MM_VOID)
706 {
707 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
708 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
709 pAlloc->offData = offData;
710 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
711 ExReleaseFastMutex(&pMgr->Mutex);
712 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
713 return STATUS_SUCCESS;
714
715 Assert(0);
716 Status = STATUS_NO_MEMORY;
717 vboxMmFree(&pMgr->Mm, iPage, cPages);
718 }
719 else
720 {
721 Assert(0);
722 ExReleaseFastMutex(&pMgr->Mutex);
723 Status = STATUS_INSUFFICIENT_RESOURCES;
724 }
725 return Status;
726}
727
728VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
729{
730 UINT cbSize = pAlloc->cbData;
731 UINT cPages = BYTES_TO_PAGES(cbSize);
732 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
733 ExAcquireFastMutex(&pMgr->Mutex);
734 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
735 vboxMmFree(&pMgr->Mm, iPage, cPages);
736 ExReleaseFastMutex(&pMgr->Mutex);
737}
738
739
740NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
741{
742 NTSTATUS Status = STATUS_SUCCESS;
743 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
744 if (pAlloc)
745 {
746 pAlloc->cbData = cbSize;
747 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
748 if (Status == STATUS_SUCCESS)
749 {
750 *ppAlloc = pAlloc;
751 return STATUS_SUCCESS;
752 }
753
754 Assert(0);
755 vboxWddmMemFree(pAlloc);
756 }
757 else
758 {
759 Assert(0);
760 Status = STATUS_NO_MEMORY;
761 }
762
763 return Status;
764}
765
766VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
767{
768 vboxVideoCmAllocDealloc(pMgr, pAlloc);
769 vboxWddmMemFree(pAlloc);
770}
771
772NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
773{
774 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
775 NTSTATUS Status = STATUS_SUCCESS;
776 PKEVENT pSynchEvent = NULL;
777
778 if (pUmAlloc->hSynch)
779 {
780 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
781 (PVOID*)&pSynchEvent,
782 NULL);
783 AssertNtStatusSuccess(Status);
784 Assert(pSynchEvent);
785 }
786
787 if (Status == STATUS_SUCCESS)
788 {
789 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
790 SIZE_T cbLength = pAlloc->cbData;
791
792 PVBOXVIDEOCM_ALLOC_REF pAllocRef;
793 pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero( sizeof(*pAllocRef)
794 + sizeof(PFN_NUMBER)
795 * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
796 if (pAllocRef)
797 {
798 pAllocRef->cRefs = 1;
799 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
800 __try
801 {
802 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
803 }
804 __except(EXCEPTION_EXECUTE_HANDLER)
805 {
806 Assert(0);
807 Status = STATUS_UNSUCCESSFUL;
808 }
809
810 if (Status == STATUS_SUCCESS)
811 {
812 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
813 NULL, /* PVOID BaseAddress */
814 FALSE, /* ULONG BugCheckOnFailure */
815 NormalPagePriority);
816 if (pvUm)
817 {
818 pAllocRef->pvUm = pvUm;
819 pAllocRef->pContext = pContext;
820 pAllocRef->pAlloc = pAlloc;
821 pAllocRef->fUhgsmiType = pUmAlloc->fUhgsmiType;
822 pAllocRef->pSynchEvent = pSynchEvent;
823 ExAcquireFastMutex(&pContext->Mutex);
824 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
825 ExReleaseFastMutex(&pContext->Mutex);
826 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
827 {
828 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
829 pUmAlloc->cbData = pAlloc->cbData;
830 pUmAlloc->pvData = (uintptr_t)pvUm;
831 return STATUS_SUCCESS;
832 }
833
834 MmUnmapLockedPages(pvUm, &pAllocRef->Mdl);
835 }
836 else
837 {
838 Assert(0);
839 Status = STATUS_INSUFFICIENT_RESOURCES;
840 }
841
842 MmUnlockPages(&pAllocRef->Mdl);
843 }
844
845 vboxWddmMemFree(pAllocRef);
846 }
847 else
848 {
849 Assert(0);
850 Status = STATUS_NO_MEMORY;
851 }
852
853 if (pSynchEvent)
854 ObDereferenceObject(pSynchEvent);
855 }
856 else
857 {
858 Assert(0);
859 }
860
861
862 return Status;
863}
864
865NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle,
866 PVBOXVIDEOCM_ALLOC *ppAlloc)
867{
868 NTSTATUS Status = STATUS_SUCCESS;
869 ExAcquireFastMutex(&pContext->Mutex);
870 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
871 ExReleaseFastMutex(&pContext->Mutex);
872 if (pAllocRef)
873 {
874 /* wait for the dereference, i.e. for all commands involving this allocation to complete */
875 vboxWddmCounterU32Wait(&pAllocRef->cRefs, 1);
876
877 MmUnmapLockedPages(pAllocRef->pvUm, &pAllocRef->Mdl);
878
879 MmUnlockPages(&pAllocRef->Mdl);
880 *ppAlloc = pAllocRef->pAlloc;
881 if (pAllocRef->pSynchEvent)
882 ObDereferenceObject(pAllocRef->pSynchEvent);
883 vboxWddmMemFree(pAllocRef);
884 }
885 else
886 {
887 Assert(0);
888 Status = STATUS_INVALID_PARAMETER;
889 }
890
891 return Status;
892}
893
894static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext,
895 VBOXDISP_KMHANDLE hSesionHandle)
896{
897 ExAcquireFastMutex(&pContext->Mutex);
898 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
899 if (pAllocRef)
900 ASMAtomicIncU32(&pAllocRef->cRefs);
901 ExReleaseFastMutex(&pContext->Mutex);
902 return pAllocRef;
903}
904
905static VOID vboxVideoAMgrCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
906{
907 uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs);
908 Assert(cRefs < UINT32_MAX/2);
909 Assert(cRefs >= 1); /* we do not do cleanup-on-zero here, instead we wait for the cRefs to reach 1 in
910 vboxVideoAMgrCtxAllocUnmap before unmapping */
911 NOREF(cRefs);
912}
913
914
915
916NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
917{
918 PVBOXVIDEOCM_ALLOC pAlloc;
919 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
920 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
921 if (Status == STATUS_SUCCESS)
922 {
923 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
924 if (Status == STATUS_SUCCESS)
925 return STATUS_SUCCESS;
926 else
927 {
928 Assert(0);
929 }
930 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
931 }
932 else
933 {
934 Assert(0);
935 }
936 return Status;
937}
938
939NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
940{
941 PVBOXVIDEOCM_ALLOC pAlloc;
942 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
943 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
944 if (Status == STATUS_SUCCESS)
945 {
946 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
947 }
948 else
949 {
950 Assert(0);
951 }
952 return Status;
953}
954
955NTSTATUS vboxVideoAMgrCreate(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
956{
957 Assert(!(offData & (PAGE_SIZE -1)));
958 Assert(!(cbData & (PAGE_SIZE -1)));
959 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
960 cbData &= (~(PAGE_SIZE -1));
961 Assert(cbData);
962 if (!cbData)
963 return STATUS_INVALID_PARAMETER;
964
965 ExInitializeFastMutex(&pMgr->Mutex);
966 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
967 AssertNtStatusSuccess(Status);
968 if (Status == STATUS_SUCCESS)
969 {
970 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
971 AssertNtStatusSuccess(Status);
972 if (Status == STATUS_SUCCESS)
973 {
974 PHYSICAL_ADDRESS PhysicalAddress = {0};
975 PhysicalAddress.QuadPart = VBoxCommonFromDeviceExt(pDevExt)->phVRAM.QuadPart + offData;
976 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
977 Assert(pMgr->pvData);
978 if (pMgr->pvData)
979 {
980 pMgr->offData = offData;
981 pMgr->cbData = cbData;
982 return STATUS_SUCCESS;
983 }
984 else
985 {
986 Status = STATUS_UNSUCCESSFUL;
987 }
988 vboxMmTerm(&pMgr->Mm);
989 }
990 vboxWddmHTableDestroy(&pMgr->AllocTable);
991 }
992
993 return Status;
994}
995
996NTSTATUS vboxVideoAMgrDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
997{
998 RT_NOREF(pDevExt);
999 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1000 vboxMmTerm(&pMgr->Mm);
1001 vboxWddmHTableDestroy(&pMgr->AllocTable);
1002 return STATUS_SUCCESS;
1003}
1004
1005NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1006{
1007 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1008 if (pMgr->pvData)
1009 {
1010 ExInitializeFastMutex(&pCtx->Mutex);
1011 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1012 AssertNtStatusSuccess(Status);
1013 if (Status == STATUS_SUCCESS)
1014 {
1015 pCtx->pMgr = pMgr;
1016 return STATUS_SUCCESS;
1017 }
1018 }
1019 return Status;
1020}
1021
1022NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1023{
1024 if (!pCtx->pMgr)
1025 return STATUS_SUCCESS;
1026
1027 VBOXWDDM_HTABLE_ITERATOR Iter;
1028 NTSTATUS Status = STATUS_SUCCESS;
1029
1030 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1031 do
1032 {
1033 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1034 if (!pRef)
1035 break;
1036
1037 Assert(0);
1038
1039 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1040 AssertNtStatusSuccess(Status);
1041 if (Status != STATUS_SUCCESS)
1042 break;
1043 // vboxWddmHTableIterRemoveCur(&Iter);
1044 } while (1);
1045
1046 if (Status == STATUS_SUCCESS)
1047 {
1048 vboxWddmHTableDestroy(&pCtx->AllocTable);
1049 }
1050
1051 return Status;
1052}
1053
1054
1055VOID vboxWddmSleep(uint32_t u32Val)
1056{
1057 RT_NOREF(u32Val);
1058 LARGE_INTEGER Interval;
1059 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1060
1061 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1062}
1063
1064VOID vboxWddmCounterU32Wait(uint32_t volatile * pu32, uint32_t u32Val)
1065{
1066 LARGE_INTEGER Interval;
1067 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1068 uint32_t u32CurVal;
1069
1070 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1071
1072 while ((u32CurVal = ASMAtomicReadU32(pu32)) != u32Val)
1073 {
1074 Assert(u32CurVal >= u32Val);
1075 Assert(u32CurVal < UINT32_MAX/2);
1076
1077 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1078 }
1079}
1080
1081/* dump user-mode driver debug info */
1082static char g_aVBoxUmdD3DCAPS9[304];
1083static VBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS g_VBoxUmdD3DCAPS9Flags;
1084static BOOLEAN g_bVBoxUmdD3DCAPS9IsInited = FALSE;
1085
1086static void vboxUmdDumpDword(DWORD *pvData, DWORD cData)
1087{
1088 DWORD dw1, dw2, dw3, dw4;
1089 for (UINT i = 0; i < (cData & (~3)); i+=4)
1090 {
1091 dw1 = *pvData++;
1092 dw2 = *pvData++;
1093 dw3 = *pvData++;
1094 dw4 = *pvData++;
1095 LOGREL(("0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", dw1, dw2, dw3, dw4));
1096 }
1097
1098 cData = cData % 4;
1099 switch (cData)
1100 {
1101 case 3:
1102 dw1 = *pvData++;
1103 dw2 = *pvData++;
1104 dw3 = *pvData++;
1105 LOGREL(("0x%08x, 0x%08x, 0x%08x\n", dw1, dw2, dw3));
1106 break;
1107 case 2:
1108 dw1 = *pvData++;
1109 dw2 = *pvData++;
1110 LOGREL(("0x%08x, 0x%08x\n", dw1, dw2));
1111 break;
1112 case 1:
1113 dw1 = *pvData++;
1114 LOGREL(("0x%8x\n", dw1));
1115 break;
1116 default:
1117 break;
1118 }
1119}
1120
1121static void vboxUmdDumpD3DCAPS9(void *pvData, PVBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS pFlags)
1122{
1123 AssertCompile(!(sizeof (g_aVBoxUmdD3DCAPS9) % sizeof (DWORD)));
1124 LOGREL(("*****Start Dumping D3DCAPS9:*******"));
1125 LOGREL(("WoW64 flag(%d)", (UINT)pFlags->WoW64));
1126 vboxUmdDumpDword((DWORD*)pvData, sizeof (g_aVBoxUmdD3DCAPS9) / sizeof (DWORD));
1127 LOGREL(("*****End Dumping D3DCAPS9**********"));
1128}
1129
1130NTSTATUS vboxUmdDumpBuf(PVBOXDISPIFESCAPE_DBGDUMPBUF pBuf, uint32_t cbBuffer)
1131{
1132 if (cbBuffer < RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]))
1133 {
1134 WARN(("Buffer too small"));
1135 return STATUS_BUFFER_TOO_SMALL;
1136 }
1137
1138 NTSTATUS Status = STATUS_SUCCESS;
1139 uint32_t cbString = cbBuffer - RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]);
1140 switch (pBuf->enmType)
1141 {
1142 case VBOXDISPIFESCAPE_DBGDUMPBUF_TYPE_D3DCAPS9:
1143 {
1144 if (cbString != sizeof (g_aVBoxUmdD3DCAPS9))
1145 {
1146 WARN(("wrong caps size, expected %d, but was %d", sizeof (g_aVBoxUmdD3DCAPS9), cbString));
1147 Status = STATUS_INVALID_PARAMETER;
1148 break;
1149 }
1150
1151 if (g_bVBoxUmdD3DCAPS9IsInited)
1152 {
1153 if (!memcmp(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9)))
1154 break;
1155
1156 WARN(("caps do not match!"));
1157 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1158 break;
1159 }
1160
1161 memcpy(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9));
1162 g_VBoxUmdD3DCAPS9Flags = pBuf->Flags;
1163 g_bVBoxUmdD3DCAPS9IsInited = TRUE;
1164 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1165 }
1166 default: break; /* Shuts up MSC. */
1167 }
1168
1169 return Status;
1170}
1171
1172#if 0
1173VOID vboxShRcTreeInit(PVBOXMP_DEVEXT pDevExt)
1174{
1175 ExInitializeFastMutex(&pDevExt->ShRcTreeMutex);
1176 pDevExt->ShRcTree = NULL;
1177}
1178
1179VOID vboxShRcTreeTerm(PVBOXMP_DEVEXT pDevExt)
1180{
1181 Assert(!pDevExt->ShRcTree);
1182 pDevExt->ShRcTree = NULL;
1183}
1184
1185BOOLEAN vboxShRcTreePut(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1186{
1187 HANDLE hSharedRc = pAlloc->hSharedHandle;
1188 if (!hSharedRc)
1189 {
1190 WARN(("invalid call with zero shared handle!"));
1191 return FALSE;
1192 }
1193 pAlloc->ShRcTreeEntry.Key = (AVLPVKEY)hSharedRc;
1194 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1195 bool bRc = RTAvlPVInsert(&pDevExt->ShRcTree, &pAlloc->ShRcTreeEntry);
1196 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1197 Assert(bRc);
1198 return (BOOLEAN)bRc;
1199}
1200
1201#define PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(_p) \
1202 ((PVBOXWDDM_ALLOCATION)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, ShRcTreeEntry)))
1203
1204PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc)
1205{
1206 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1207 PAVLPVNODECORE pNode = RTAvlPVGet(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1208 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1209 if (!pNode)
1210 return NULL;
1211 PVBOXWDDM_ALLOCATION pAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1212 return pAlloc;
1213}
1214
1215BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1216{
1217 HANDLE hSharedRc = pAlloc->hSharedHandle;
1218 if (!hSharedRc)
1219 {
1220 WARN(("invalid call with zero shared handle!"));
1221 return FALSE;
1222 }
1223 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1224 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1225 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1226 if (!pNode)
1227 return NULL;
1228 PVBOXWDDM_ALLOCATION pRetAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1229 Assert(pRetAlloc == pAlloc);
1230 return !!pRetAlloc;
1231}
1232#endif
1233
1234NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr)
1235{
1236 HANDLE hKey;
1237 OBJECT_ATTRIBUTES ObjAttr;
1238
1239 InitializeObjectAttributes(&ObjAttr, pRegStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1240
1241 NTSTATUS Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjAttr);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 WARN(("ZwOpenKey for settings key failed, Status 0x%x", Status));
1245 return Status;
1246 }
1247
1248 DWORD dwValue = 0;
1249 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_LOG_UM, &dwValue);
1250 if (NT_SUCCESS(Status))
1251 g_VBoxLogUm = dwValue;
1252
1253 g_RefreshRate = 0;
1254 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_RATE, &dwValue);
1255 if (NT_SUCCESS(Status))
1256 {
1257 LOGREL(("WDDM: Guest refresh rate %u", dwValue));
1258 g_RefreshRate = dwValue;
1259 }
1260
1261 if (g_RefreshRate == 0 || g_RefreshRate > 240)
1262 g_RefreshRate = VBOXWDDM_DEFAULT_REFRESH_RATE;
1263
1264 ZwClose(hKey);
1265
1266 return Status;
1267}
1268
1269NTSTATUS vboxWddmThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
1270{
1271 NTSTATUS fStatus;
1272 HANDLE hThread;
1273 OBJECT_ATTRIBUTES fObjectAttributes;
1274
1275 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1276
1277 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
1278 NULL, NULL);
1279
1280 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
1281 &fObjectAttributes, NULL, NULL,
1282 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
1283 if (!NT_SUCCESS(fStatus))
1284 return fStatus;
1285
1286 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
1287 KernelMode, (PVOID*) ppThread, NULL);
1288 ZwClose(hThread);
1289 return STATUS_SUCCESS;
1290}
1291
1292static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags)
1293{
1294 PHGSMIGUESTCOMMANDCONTEXT pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
1295 VBVASCANLINECFG *pCfg;
1296 int rc = VINF_SUCCESS;
1297
1298 /* Allocate the IO buffer. */
1299 pCfg = (VBVASCANLINECFG *)VBoxHGSMIBufferAlloc(pCtx,
1300 sizeof (VBVASCANLINECFG), HGSMI_CH_VBVA,
1301 VBVA_SCANLINE_CFG);
1302
1303 if (pCfg)
1304 {
1305 /* Prepare data to be sent to the host. */
1306 pCfg->rc = VERR_NOT_IMPLEMENTED;
1307 pCfg->fFlags = fFlags;
1308 rc = VBoxHGSMIBufferSubmit(pCtx, pCfg);
1309 if (RT_SUCCESS(rc))
1310 {
1311 AssertRC(pCfg->rc);
1312 rc = pCfg->rc;
1313 }
1314 /* Free the IO buffer. */
1315 VBoxHGSMIBufferFree(pCtx, pCfg);
1316 }
1317 else
1318 rc = VERR_NO_MEMORY;
1319 return rc;
1320}
1321
1322NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
1323{
1324 if (!pDevExt->bVSyncTimerEnabled == !fEnable)
1325 return STATUS_SUCCESS;
1326
1327 if (!fEnable)
1328 {
1329 KeCancelTimer(&pDevExt->VSyncTimer);
1330 }
1331 else
1332 {
1333 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1334
1335 LARGE_INTEGER DueTime;
1336 DueTime.QuadPart = -10000000LL / g_RefreshRate; /* 100ns units per second / Freq Hz */
1337 KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 1000 / g_RefreshRate, &pDevExt->VSyncDpc);
1338 }
1339
1340 pDevExt->bVSyncTimerEnabled = !!fEnable;
1341
1342 return STATUS_SUCCESS;
1343}
1344
1345NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGetScanLine)
1346{
1347 Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pGetScanLine->VidPnTargetId);
1348 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[pGetScanLine->VidPnTargetId];
1349 Assert(pTarget->Size.cx);
1350 Assert(pTarget->Size.cy);
1351 if (pTarget->Size.cy)
1352 {
1353 uint32_t curScanLine = 0;
1354 BOOL bVBlank = FALSE;
1355 LARGE_INTEGER DevVSyncTime;
1356 DevVSyncTime.QuadPart = ASMAtomicReadU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart);
1357 LARGE_INTEGER VSyncTime;
1358 KeQuerySystemTime(&VSyncTime);
1359
1360 if (VSyncTime.QuadPart < DevVSyncTime.QuadPart)
1361 {
1362 WARN(("vsync time is less than the one stored in device"));
1363 bVBlank = TRUE;
1364 }
1365 else
1366 {
1367 VSyncTime.QuadPart = VSyncTime.QuadPart - DevVSyncTime.QuadPart;
1368 /*
1369 * Check whether we are in VBlank state or actively drawing a scan line.
1370 * 10% of the VSync interval are dedicated to VBlank.
1371 *
1372 * Time intervals are in 100ns steps.
1373 */
1374 LARGE_INTEGER VSyncPeriod;
1375 VSyncPeriod.QuadPart = VSyncTime.QuadPart % (10000000LL / g_RefreshRate);
1376 LARGE_INTEGER VBlankStart;
1377 VBlankStart.QuadPart = ((10000000LL / g_RefreshRate) * 9) / 10;
1378 if (VSyncPeriod.QuadPart >= VBlankStart.QuadPart)
1379 bVBlank = TRUE;
1380 else
1381 curScanLine = (uint32_t)((pTarget->Size.cy * VSyncPeriod.QuadPart) / VBlankStart.QuadPart);
1382 }
1383
1384 pGetScanLine->ScanLine = curScanLine;
1385 pGetScanLine->InVerticalBlank = bVBlank;
1386 }
1387 else
1388 {
1389 pGetScanLine->InVerticalBlank = TRUE;
1390 pGetScanLine->ScanLine = 0;
1391 }
1392 return STATUS_SUCCESS;
1393}
1394
1395static BOOLEAN vboxWddmSlVSyncIrqCb(PVOID pvContext)
1396{
1397 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1398 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1399 BOOLEAN bNeedDpc = FALSE;
1400 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1401 {
1402 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1403 if (pTarget->fConnected)
1404 {
1405 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1406 notify.InterruptType = g_VBoxDisplayOnly?
1407 DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
1408 DXGK_INTERRUPT_CRTC_VSYNC;
1409 notify.CrtcVsync.VidPnTargetId = i;
1410 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1411 bNeedDpc = TRUE;
1412 }
1413 }
1414
1415 if (bNeedDpc)
1416 {
1417 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1418 }
1419
1420 return FALSE;
1421}
1422
1423static VOID vboxWddmSlVSyncDpc(
1424 __in struct _KDPC *Dpc,
1425 __in_opt PVOID DeferredContext,
1426 __in_opt PVOID SystemArgument1,
1427 __in_opt PVOID SystemArgument2
1428)
1429{
1430 RT_NOREF(Dpc, SystemArgument1, SystemArgument2);
1431 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext;
1432 Assert(!pDevExt->fVSyncInVBlank);
1433 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 1);
1434
1435 BOOLEAN bDummy;
1436 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1437 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1438 vboxWddmSlVSyncIrqCb,
1439 pDevExt,
1440 0, /* IN ULONG MessageNumber */
1441 &bDummy);
1442 if (!NT_SUCCESS(Status))
1443 WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status));
1444
1445 LARGE_INTEGER VSyncTime;
1446 KeQuerySystemTime(&VSyncTime);
1447 ASMAtomicWriteU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart, VSyncTime.QuadPart);
1448
1449 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 0);
1450}
1451
1452NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt)
1453{
1454 pDevExt->bVSyncTimerEnabled = FALSE;
1455 pDevExt->fVSyncInVBlank = 0;
1456 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1457 KeInitializeTimer(&pDevExt->VSyncTimer);
1458 KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt);
1459 return STATUS_SUCCESS;
1460}
1461
1462NTSTATUS VBoxWddmSlTerm(PVBOXMP_DEVEXT pDevExt)
1463{
1464 KeCancelTimer(&pDevExt->VSyncTimer);
1465 return STATUS_SUCCESS;
1466}
1467
1468void vboxWddmDiInitDefault(DXGK_DISPLAY_INFORMATION *pInfo, PHYSICAL_ADDRESS PhAddr, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
1469{
1470 pInfo->Width = 1024;
1471 pInfo->Height = 768;
1472 pInfo->Pitch = pInfo->Width * 4;
1473 pInfo->ColorFormat = D3DDDIFMT_A8R8G8B8;
1474 pInfo->PhysicAddress = PhAddr;
1475 pInfo->TargetId = VidPnSourceId;
1476 pInfo->AcpiId = 0;
1477}
1478
1479void vboxWddmDiToAllocData(PVBOXMP_DEVEXT pDevExt, const DXGK_DISPLAY_INFORMATION *pInfo, PVBOXWDDM_ALLOC_DATA pAllocData)
1480{
1481 pAllocData->SurfDesc.width = pInfo->Width;
1482 pAllocData->SurfDesc.height = pInfo->Height;
1483 pAllocData->SurfDesc.format = pInfo->ColorFormat;
1484 pAllocData->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pInfo->ColorFormat);
1485 pAllocData->SurfDesc.pitch = pInfo->Pitch;
1486 pAllocData->SurfDesc.depth = 1;
1487 pAllocData->SurfDesc.slicePitch = pInfo->Pitch;
1488 pAllocData->SurfDesc.cbSize = pInfo->Pitch * pInfo->Height;
1489 pAllocData->SurfDesc.VidPnSourceId = pInfo->TargetId;
1490 pAllocData->SurfDesc.RefreshRate.Numerator = g_RefreshRate * 1000;
1491 pAllocData->SurfDesc.RefreshRate.Denominator = 1000;
1492
1493 /* the address here is not a VRAM offset! so convert it to offset */
1494 vboxWddmAddrSetVram(&pAllocData->Addr, 1,
1495 vboxWddmVramAddrToOffset(pDevExt, pInfo->PhysicAddress));
1496}
1497
1498void vboxWddmDmSetupDefaultVramLocation(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID ModifiedVidPnSourceId,
1499 VBOXWDDM_SOURCE *paSources)
1500{
1501 PVBOXWDDM_SOURCE pSource = &paSources[ModifiedVidPnSourceId];
1502 AssertRelease(g_VBoxDisplayOnly);
1503 ULONG offVram = vboxWddmVramCpuVisibleSegmentSize(pDevExt);
1504 offVram /= VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1505 offVram &= ~PAGE_OFFSET_MASK;
1506 offVram *= ModifiedVidPnSourceId;
1507
1508 if (vboxWddmAddrSetVram(&pSource->AllocData.Addr, 1, offVram))
1509 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
1510}
1511
1512char const *vboxWddmAllocTypeString(PVBOXWDDM_ALLOCATION pAlloc)
1513{
1514 switch (pAlloc->enmType)
1515 {
1516 case VBOXWDDM_ALLOC_TYPE_UNEFINED: return "UNEFINED";
1517 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE: return "SHAREDPRIMARYSURFACE";
1518 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE: return "SHADOWSURFACE";
1519 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE: return "STAGINGSURFACE";
1520 case VBOXWDDM_ALLOC_TYPE_STD_GDISURFACE: return "GDISURFACE";
1521 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC: return "UMD_RC_GENERIC";
1522 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER: return "UMD_HGSMI_BUFFER";
1523 default: break;
1524 }
1525 AssertFailed();
1526 return "UNKNOWN";
1527}
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