VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/wddm/shared/VBoxDispKmt.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1/* $Id: VBoxDispKmt.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxVideo Display D3D User Mode Dll.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "../VBoxDispD3DBase.h"
29#include <VBoxDispKmt.h>
30
31#include <iprt/assert.h>
32#include <iprt/log.h>
33
34
35/**
36 * Loads a system DLL.
37 *
38 * @returns Module handle or NULL
39 * @param pszName The DLL name.
40 */
41static HMODULE loadSystemDll(const char *pszName)
42{
43 char szPath[MAX_PATH];
44 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
45 size_t cbName = strlen(pszName) + 1;
46 if (cchPath + 1 + cbName > sizeof(szPath))
47 return NULL;
48 szPath[cchPath] = '\\';
49 memcpy(&szPath[cchPath + 1], pszName, cbName);
50 return LoadLibraryA(szPath);
51}
52
53HRESULT vboxDispKmtCallbacksInit(PVBOXDISPKMT_CALLBACKS pCallbacks)
54{
55 HRESULT hr = S_OK;
56
57 memset(pCallbacks, 0, sizeof (*pCallbacks));
58
59 pCallbacks->hGdi32 = loadSystemDll("gdi32.dll");
60 if (pCallbacks->hGdi32 != NULL)
61 {
62 bool bSupported = true;
63 bool bSupportedWin8 = true;
64 pCallbacks->pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(pCallbacks->hGdi32, "D3DKMTOpenAdapterFromHdc");
65 LogFunc(("pfnD3DKMTOpenAdapterFromHdc = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTOpenAdapterFromHdc)));
66 bSupported &= !!(pCallbacks->pfnD3DKMTOpenAdapterFromHdc);
67
68 pCallbacks->pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(pCallbacks->hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
69 LogFunc(("pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTOpenAdapterFromGdiDisplayName)));
70 bSupported &= !!(pCallbacks->pfnD3DKMTOpenAdapterFromGdiDisplayName);
71
72 pCallbacks->pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(pCallbacks->hGdi32, "D3DKMTCloseAdapter");
73 LogFunc(("pfnD3DKMTCloseAdapter = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTCloseAdapter)));
74 bSupported &= !!(pCallbacks->pfnD3DKMTCloseAdapter);
75
76 pCallbacks->pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(pCallbacks->hGdi32, "D3DKMTEscape");
77 LogFunc(("pfnD3DKMTEscape = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTEscape)));
78 bSupported &= !!(pCallbacks->pfnD3DKMTEscape);
79
80 pCallbacks->pfnD3DKMTQueryAdapterInfo = (PFND3DKMT_QUERYADAPTERINFO)GetProcAddress(pCallbacks->hGdi32, "D3DKMTQueryAdapterInfo");
81 LogFunc(("pfnD3DKMTQueryAdapterInfo = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTQueryAdapterInfo)));
82 bSupported &= !!(pCallbacks->pfnD3DKMTQueryAdapterInfo);
83
84 pCallbacks->pfnD3DKMTCreateDevice = (PFND3DKMT_CREATEDEVICE)GetProcAddress(pCallbacks->hGdi32, "D3DKMTCreateDevice");
85 LogFunc(("pfnD3DKMTCreateDevice = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTCreateDevice)));
86 bSupported &= !!(pCallbacks->pfnD3DKMTCreateDevice);
87
88 pCallbacks->pfnD3DKMTDestroyDevice = (PFND3DKMT_DESTROYDEVICE)GetProcAddress(pCallbacks->hGdi32, "D3DKMTDestroyDevice");
89 LogFunc(("pfnD3DKMTDestroyDevice = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTDestroyDevice)));
90 bSupported &= !!(pCallbacks->pfnD3DKMTDestroyDevice);
91
92 pCallbacks->pfnD3DKMTCreateContext = (PFND3DKMT_CREATECONTEXT)GetProcAddress(pCallbacks->hGdi32, "D3DKMTCreateContext");
93 LogFunc(("pfnD3DKMTCreateContext = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTCreateContext)));
94 bSupported &= !!(pCallbacks->pfnD3DKMTCreateContext);
95
96 pCallbacks->pfnD3DKMTDestroyContext = (PFND3DKMT_DESTROYCONTEXT)GetProcAddress(pCallbacks->hGdi32, "D3DKMTDestroyContext");
97 LogFunc(("pfnD3DKMTDestroyContext = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTDestroyContext)));
98 bSupported &= !!(pCallbacks->pfnD3DKMTDestroyContext);
99
100 pCallbacks->pfnD3DKMTRender = (PFND3DKMT_RENDER)GetProcAddress(pCallbacks->hGdi32, "D3DKMTRender");
101 LogFunc(("pfnD3DKMTRender = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTRender)));
102 bSupported &= !!(pCallbacks->pfnD3DKMTRender);
103
104 pCallbacks->pfnD3DKMTCreateAllocation = (PFND3DKMT_CREATEALLOCATION)GetProcAddress(pCallbacks->hGdi32, "D3DKMTCreateAllocation");
105 LogFunc(("pfnD3DKMTCreateAllocation = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTCreateAllocation)));
106 bSupported &= !!(pCallbacks->pfnD3DKMTCreateAllocation);
107
108 pCallbacks->pfnD3DKMTDestroyAllocation = (PFND3DKMT_DESTROYALLOCATION)GetProcAddress(pCallbacks->hGdi32, "D3DKMTDestroyAllocation");
109 LogFunc(("pfnD3DKMTDestroyAllocation = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTDestroyAllocation)));
110 bSupported &= !!(pCallbacks->pfnD3DKMTDestroyAllocation);
111
112 pCallbacks->pfnD3DKMTLock = (PFND3DKMT_LOCK)GetProcAddress(pCallbacks->hGdi32, "D3DKMTLock");
113 LogFunc(("pfnD3DKMTLock = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTLock)));
114 bSupported &= !!(pCallbacks->pfnD3DKMTLock);
115
116 pCallbacks->pfnD3DKMTUnlock = (PFND3DKMT_UNLOCK)GetProcAddress(pCallbacks->hGdi32, "D3DKMTUnlock");
117 LogFunc(("pfnD3DKMTUnlock = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTUnlock)));
118 bSupported &= !!(pCallbacks->pfnD3DKMTUnlock);
119
120 pCallbacks->pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(pCallbacks->hGdi32, "D3DKMTInvalidateActiveVidPn");
121 LogFunc(("pfnD3DKMTInvalidateActiveVidPn = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTInvalidateActiveVidPn)));
122 bSupported &= !!(pCallbacks->pfnD3DKMTInvalidateActiveVidPn);
123
124 pCallbacks->pfnD3DKMTPollDisplayChildren = (PFND3DKMT_POLLDISPLAYCHILDREN)GetProcAddress(pCallbacks->hGdi32, "D3DKMTPollDisplayChildren");
125 LogFunc(("pfnD3DKMTPollDisplayChildren = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTPollDisplayChildren)));
126 bSupported &= !!(pCallbacks->pfnD3DKMTPollDisplayChildren);
127
128 pCallbacks->pfnD3DKMTEnumAdapters = (PFND3DKMT_ENUMADAPTERS)GetProcAddress(pCallbacks->hGdi32, "D3DKMTEnumAdapters");
129 LogFunc(("pfnD3DKMTEnumAdapters = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTEnumAdapters)));
130 /* this present starting win8 release preview only, so keep going if it is not available,
131 * i.e. do not clear the bSupported on its absence */
132 bSupportedWin8 &= !!(pCallbacks->pfnD3DKMTEnumAdapters);
133
134 pCallbacks->pfnD3DKMTOpenAdapterFromLuid = (PFND3DKMT_OPENADAPTERFROMLUID)GetProcAddress(pCallbacks->hGdi32, "D3DKMTOpenAdapterFromLuid");
135 LogFunc(("pfnD3DKMTOpenAdapterFromLuid = %p\n", RT_CB_LOG_CAST(pCallbacks->pfnD3DKMTOpenAdapterFromLuid)));
136 /* this present starting win8 release preview only, so keep going if it is not available,
137 * i.e. do not clear the bSupported on its absence */
138 bSupportedWin8 &= !!(pCallbacks->pfnD3DKMTOpenAdapterFromLuid);
139
140 /*Assert(bSupported);*/
141 if (bSupported)
142 {
143 if (bSupportedWin8)
144 pCallbacks->enmVersion = VBOXDISPKMT_CALLBACKS_VERSION_WIN8;
145 else
146 pCallbacks->enmVersion = VBOXDISPKMT_CALLBACKS_VERSION_VISTA_WIN7;
147 return S_OK;
148 }
149 else
150 {
151 LogFunc(("one of pfnD3DKMT function pointers failed to initialize\n"));
152 hr = E_NOINTERFACE;
153 }
154
155 FreeLibrary(pCallbacks->hGdi32);
156 }
157 else
158 {
159 DWORD winEr = GetLastError();
160 hr = HRESULT_FROM_WIN32(winEr);
161 Assert(0);
162 Assert(hr != S_OK);
163 Assert(hr != S_FALSE);
164 if (hr == S_OK || hr == S_FALSE)
165 hr = E_FAIL;
166 }
167
168 return hr;
169}
170
171HRESULT vboxDispKmtCallbacksTerm(PVBOXDISPKMT_CALLBACKS pCallbacks)
172{
173 FreeLibrary(pCallbacks->hGdi32);
174#ifdef DEBUG_misha
175 memset(pCallbacks, 0, sizeof (*pCallbacks));
176#endif
177 return S_OK;
178}
179
180HRESULT vboxDispKmtAdpHdcCreate(HDC *phDc)
181{
182 HRESULT hr = E_FAIL;
183 DISPLAY_DEVICE DDev;
184 memset(&DDev, 0, sizeof (DDev));
185 DDev.cb = sizeof (DDev);
186
187 *phDc = NULL;
188
189 for (int i = 0; ; ++i)
190 {
191 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
192 &DDev, 0 /* DWORD dwFlags*/))
193 {
194 if (DDev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
195 {
196 HDC hDc = CreateDC(NULL, DDev.DeviceName, NULL, NULL);
197 if (hDc)
198 {
199 *phDc = hDc;
200 return S_OK;
201 }
202 else
203 {
204 DWORD winEr = GetLastError();
205 Assert(0);
206 hr = HRESULT_FROM_WIN32(winEr);
207 Assert(FAILED(hr));
208 break;
209 }
210 }
211 }
212 else
213 {
214 DWORD winEr = GetLastError();
215// BP_WARN();
216 hr = HRESULT_FROM_WIN32(winEr);
217#ifdef DEBUG_misha
218 Assert(FAILED(hr));
219#endif
220 if (!FAILED(hr))
221 {
222 hr = E_FAIL;
223 }
224 break;
225 }
226 }
227
228 return hr;
229}
230
231static HRESULT vboxDispKmtOpenAdapterViaHdc(const VBOXDISPKMT_CALLBACKS *pCallbacks, PVBOXDISPKMT_ADAPTER pAdapter)
232{
233 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
234 HRESULT hr = vboxDispKmtAdpHdcCreate(&OpenAdapterData.hDc);
235 if (!SUCCEEDED(hr))
236 return hr;
237
238 Assert(OpenAdapterData.hDc);
239 NTSTATUS Status = pCallbacks->pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
240 if (NT_SUCCESS(Status))
241 {
242 pAdapter->hAdapter = OpenAdapterData.hAdapter;
243 pAdapter->hDc = OpenAdapterData.hDc;
244 pAdapter->pCallbacks = pCallbacks;
245 memset(&pAdapter->Luid, 0, sizeof (pAdapter->Luid));
246 return S_OK;
247 }
248 else
249 {
250 LogFunc(("pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
251 hr = E_FAIL;
252 }
253
254 DeleteDC(OpenAdapterData.hDc);
255
256 return hr;
257}
258
259static HRESULT vboxDispKmtOpenAdapterViaLuid(const VBOXDISPKMT_CALLBACKS *pCallbacks, PVBOXDISPKMT_ADAPTER pAdapter)
260{
261 if (pCallbacks->enmVersion < VBOXDISPKMT_CALLBACKS_VERSION_WIN8)
262 return E_NOTIMPL;
263
264 D3DKMT_ENUMADAPTERS EnumAdapters = {0};
265 EnumAdapters.NumAdapters = RT_ELEMENTS(EnumAdapters.Adapters);
266
267 NTSTATUS Status = pCallbacks->pfnD3DKMTEnumAdapters(&EnumAdapters);
268#ifdef DEBUG_misha
269 Assert(!Status);
270#endif
271 if (!NT_SUCCESS(Status))
272 return E_FAIL;
273
274 Assert(EnumAdapters.NumAdapters);
275
276 /* try the same twice: if we fail to open the adapter containing present sources,
277 * try to open any adapter */
278 for (ULONG f = 0; f < 2; ++f)
279 {
280 for (ULONG i = 0; i < EnumAdapters.NumAdapters; ++i)
281 {
282 if (f || EnumAdapters.Adapters[i].NumOfSources)
283 {
284 D3DKMT_OPENADAPTERFROMLUID OpenAdapterData = {{0}};
285 OpenAdapterData.AdapterLuid = EnumAdapters.Adapters[i].AdapterLuid;
286 Status = pCallbacks->pfnD3DKMTOpenAdapterFromLuid(&OpenAdapterData);
287#ifdef DEBUG_misha
288 Assert(!Status);
289#endif
290 if (NT_SUCCESS(Status))
291 {
292 pAdapter->hAdapter = OpenAdapterData.hAdapter;
293 pAdapter->hDc = NULL;
294 pAdapter->Luid = EnumAdapters.Adapters[i].AdapterLuid;
295 pAdapter->pCallbacks = pCallbacks;
296 return S_OK;
297 }
298 }
299 }
300 }
301
302#ifdef DEBUG_misha
303 Assert(0);
304#endif
305 return E_FAIL;
306}
307
308HRESULT vboxDispKmtOpenAdapter(const VBOXDISPKMT_CALLBACKS *pCallbacks, PVBOXDISPKMT_ADAPTER pAdapter)
309{
310 HRESULT hr = vboxDispKmtOpenAdapterViaHdc(pCallbacks, pAdapter);
311 if (SUCCEEDED(hr))
312 return S_OK;
313
314 hr = vboxDispKmtOpenAdapterViaLuid(pCallbacks, pAdapter);
315 if (SUCCEEDED(hr))
316 return S_OK;
317
318 return hr;
319}
320
321HRESULT vboxDispKmtCloseAdapter(PVBOXDISPKMT_ADAPTER pAdapter)
322{
323 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
324 ClosaAdapterData.hAdapter = pAdapter->hAdapter;
325 NTSTATUS Status = pAdapter->pCallbacks->pfnD3DKMTCloseAdapter(&ClosaAdapterData);
326 Assert(!Status);
327 if (!Status)
328 {
329 DeleteDC(pAdapter->hDc);
330#ifdef DEBUG_misha
331 memset(pAdapter, 0, sizeof (*pAdapter));
332#endif
333 return S_OK;
334 }
335
336 LogFunc(("pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
337
338 return E_FAIL;
339}
340
341HRESULT vboxDispKmtCreateDevice(PVBOXDISPKMT_ADAPTER pAdapter, PVBOXDISPKMT_DEVICE pDevice)
342{
343 D3DKMT_CREATEDEVICE CreateDeviceData = {0};
344 CreateDeviceData.hAdapter = pAdapter->hAdapter;
345 NTSTATUS Status = pAdapter->pCallbacks->pfnD3DKMTCreateDevice(&CreateDeviceData);
346 Assert(!Status);
347 if (!Status)
348 {
349 pDevice->pAdapter = pAdapter;
350 pDevice->hDevice = CreateDeviceData.hDevice;
351 pDevice->pCommandBuffer = CreateDeviceData.pCommandBuffer;
352 pDevice->CommandBufferSize = CreateDeviceData.CommandBufferSize;
353 pDevice->pAllocationList = CreateDeviceData.pAllocationList;
354 pDevice->AllocationListSize = CreateDeviceData.AllocationListSize;
355 pDevice->pPatchLocationList = CreateDeviceData.pPatchLocationList;
356 pDevice->PatchLocationListSize = CreateDeviceData.PatchLocationListSize;
357
358 return S_OK;
359 }
360
361 return E_FAIL;
362}
363
364HRESULT vboxDispKmtDestroyDevice(PVBOXDISPKMT_DEVICE pDevice)
365{
366 D3DKMT_DESTROYDEVICE DestroyDeviceData = {0};
367 DestroyDeviceData.hDevice = pDevice->hDevice;
368 NTSTATUS Status = pDevice->pAdapter->pCallbacks->pfnD3DKMTDestroyDevice(&DestroyDeviceData);
369 Assert(!Status);
370 if (!Status)
371 {
372#ifdef DEBUG_misha
373 memset(pDevice, 0, sizeof (*pDevice));
374#endif
375 return S_OK;
376 }
377 return E_FAIL;
378}
379
380/// @todo Used for resize and seamless. Drop crVersion* params.
381HRESULT vboxDispKmtCreateContext(PVBOXDISPKMT_DEVICE pDevice, PVBOXDISPKMT_CONTEXT pContext,
382 VBOXWDDM_CONTEXT_TYPE enmType,
383 HANDLE hEvent, uint64_t u64UmInfo)
384{
385 VBOXWDDM_CREATECONTEXT_INFO Info = {0};
386 Info.u32IfVersion = 9;
387 Info.enmType = enmType;
388 Info.u.vbox.crVersionMajor = 0; /* Not used */
389 Info.u.vbox.crVersionMinor = 0; /* Not used */
390 Info.u.vbox.hUmEvent = (uintptr_t)hEvent;
391 Info.u.vbox.u64UmInfo = u64UmInfo;
392 D3DKMT_CREATECONTEXT ContextData = {0};
393 ContextData.hDevice = pDevice->hDevice;
394 ContextData.NodeOrdinal = VBOXWDDM_NODE_ID_3D_KMT;
395 ContextData.EngineAffinity = VBOXWDDM_ENGINE_ID_3D_KMT;
396 ContextData.pPrivateDriverData = &Info;
397 ContextData.PrivateDriverDataSize = sizeof (Info);
398 ContextData.ClientHint = D3DKMT_CLIENTHINT_DX9;
399 NTSTATUS Status = pDevice->pAdapter->pCallbacks->pfnD3DKMTCreateContext(&ContextData);
400 Assert(!Status);
401 if (!Status)
402 {
403 pContext->pDevice = pDevice;
404 pContext->hContext = ContextData.hContext;
405 pContext->pCommandBuffer = ContextData.pCommandBuffer;
406 pContext->CommandBufferSize = ContextData.CommandBufferSize;
407 pContext->pAllocationList = ContextData.pAllocationList;
408 pContext->AllocationListSize = ContextData.AllocationListSize;
409 pContext->pPatchLocationList = ContextData.pPatchLocationList;
410 pContext->PatchLocationListSize = ContextData.PatchLocationListSize;
411 return S_OK;
412 }
413 return E_FAIL;
414}
415
416HRESULT vboxDispKmtDestroyContext(PVBOXDISPKMT_CONTEXT pContext)
417{
418 D3DKMT_DESTROYCONTEXT DestroyContextData = {0};
419 DestroyContextData.hContext = pContext->hContext;
420 NTSTATUS Status = pContext->pDevice->pAdapter->pCallbacks->pfnD3DKMTDestroyContext(&DestroyContextData);
421 Assert(!Status);
422 if (!Status)
423 {
424#ifdef DEBUG_misha
425 memset(pContext, 0, sizeof (*pContext));
426#endif
427 return S_OK;
428 }
429 return E_FAIL;
430}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use