1 | /* $Id: GaDrvEnvWddm.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VirtualBox Windows Guest Mesa3D - Gallium driver interface to the WDDM miniport driver.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2016-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 "GaDrvEnvWddm.h"
|
---|
29 |
|
---|
30 | #include "svga3d_reg.h"
|
---|
31 |
|
---|
32 | #include <common/wddm/VBoxMPIf.h>
|
---|
33 |
|
---|
34 | #include <iprt/alloc.h>
|
---|
35 | #include <iprt/log.h>
|
---|
36 | #include <iprt/param.h>
|
---|
37 |
|
---|
38 | typedef struct GAWDDMCONTEXTINFO
|
---|
39 | {
|
---|
40 | AVLU32NODECORE Core;
|
---|
41 | HANDLE hContext;
|
---|
42 | VOID *pCommandBuffer;
|
---|
43 | UINT CommandBufferSize;
|
---|
44 | D3DDDI_ALLOCATIONLIST *pAllocationList;
|
---|
45 | UINT AllocationListSize;
|
---|
46 | D3DDDI_PATCHLOCATIONLIST *pPatchLocationList;
|
---|
47 | UINT PatchLocationListSize;
|
---|
48 | } GAWDDMCONTEXTINFO;
|
---|
49 |
|
---|
50 | static HRESULT
|
---|
51 | vboxDdiContextGetId(GaWddmCallbacks *pWddmCallbacks,
|
---|
52 | HANDLE hContext,
|
---|
53 | uint32_t *pu32Cid)
|
---|
54 | {
|
---|
55 | HRESULT hr;
|
---|
56 | D3DDDICB_ESCAPE ddiEscape;
|
---|
57 | VBOXDISPIFESCAPE_GAGETCID data;
|
---|
58 |
|
---|
59 | memset(&data, 0, sizeof(data));
|
---|
60 | data.EscapeHdr.escapeCode = VBOXESC_GAGETCID;
|
---|
61 | // data.EscapeHdr.cmdSpecific = 0;
|
---|
62 | // data.u32Cid = 0;
|
---|
63 |
|
---|
64 | /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
|
---|
65 | * have also set hDevice to a non-NULL value...
|
---|
66 | */
|
---|
67 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
68 | ddiEscape.Flags.Value = 0;
|
---|
69 | ddiEscape.pPrivateDriverData = &data;
|
---|
70 | ddiEscape.PrivateDriverDataSize = sizeof(data);
|
---|
71 | ddiEscape.hContext = hContext;
|
---|
72 |
|
---|
73 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
74 | if (SUCCEEDED(hr))
|
---|
75 | {
|
---|
76 | *pu32Cid = data.u32Cid;
|
---|
77 | }
|
---|
78 | return hr;
|
---|
79 | }
|
---|
80 |
|
---|
81 | static void
|
---|
82 | vboxDdiContextDestroy(GaWddmCallbacks *pWddmCallbacks,
|
---|
83 | GAWDDMCONTEXTINFO *pContextInfo)
|
---|
84 | {
|
---|
85 | if (pContextInfo->hContext)
|
---|
86 | {
|
---|
87 | D3DDDICB_DESTROYCONTEXT ddiDestroyContext;
|
---|
88 | memset(&ddiDestroyContext, 0, sizeof(ddiDestroyContext));
|
---|
89 | ddiDestroyContext.hContext = pContextInfo->hContext;
|
---|
90 | pWddmCallbacks->DeviceCallbacks.pfnDestroyContextCb(pWddmCallbacks->hDevice, &ddiDestroyContext);
|
---|
91 | }
|
---|
92 | }
|
---|
93 |
|
---|
94 | static HRESULT
|
---|
95 | vboxDdiContextCreate(GaWddmCallbacks *pWddmCallbacks,
|
---|
96 | void *pvPrivateData, uint32_t cbPrivateData,
|
---|
97 | GAWDDMCONTEXTINFO *pContextInfo)
|
---|
98 | {
|
---|
99 | HRESULT hr;
|
---|
100 | D3DDDICB_CREATECONTEXT ddiCreateContext;
|
---|
101 |
|
---|
102 | memset(&ddiCreateContext, 0, sizeof(ddiCreateContext));
|
---|
103 | // ddiCreateContext.NodeOrdinal = 0;
|
---|
104 | // ddiCreateContext.EngineAffinity = 0;
|
---|
105 | // ddiCreateContext.Flags.Value = 0;
|
---|
106 | ddiCreateContext.pPrivateDriverData = pvPrivateData;
|
---|
107 | ddiCreateContext.PrivateDriverDataSize = cbPrivateData;
|
---|
108 |
|
---|
109 | hr = pWddmCallbacks->DeviceCallbacks.pfnCreateContextCb(pWddmCallbacks->hDevice, &ddiCreateContext);
|
---|
110 | if (hr == S_OK)
|
---|
111 | {
|
---|
112 | /* Query cid. */
|
---|
113 | uint32_t u32Cid = 0;
|
---|
114 | hr = vboxDdiContextGetId(pWddmCallbacks, ddiCreateContext.hContext, &u32Cid);
|
---|
115 | if (SUCCEEDED(hr))
|
---|
116 | {
|
---|
117 | pContextInfo->Core.Key = u32Cid;
|
---|
118 | pContextInfo->hContext = ddiCreateContext.hContext;
|
---|
119 | pContextInfo->pCommandBuffer = ddiCreateContext.pCommandBuffer;
|
---|
120 | pContextInfo->CommandBufferSize = ddiCreateContext.CommandBufferSize;
|
---|
121 | pContextInfo->pAllocationList = ddiCreateContext.pAllocationList;
|
---|
122 | pContextInfo->AllocationListSize = ddiCreateContext.AllocationListSize;
|
---|
123 | pContextInfo->pPatchLocationList = ddiCreateContext.pPatchLocationList;
|
---|
124 | pContextInfo->PatchLocationListSize = ddiCreateContext.PatchLocationListSize;
|
---|
125 | }
|
---|
126 | else
|
---|
127 | {
|
---|
128 | vboxDdiContextDestroy(pWddmCallbacks, pContextInfo);
|
---|
129 | }
|
---|
130 | }
|
---|
131 |
|
---|
132 | return hr;
|
---|
133 | }
|
---|
134 |
|
---|
135 | /* static */ DECLCALLBACK(void)
|
---|
136 | GaDrvEnvWddm::gaEnvWddmContextDestroy(void *pvEnv,
|
---|
137 | uint32_t u32Cid)
|
---|
138 | {
|
---|
139 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
140 |
|
---|
141 | GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Remove(&pThis->mContextTree, u32Cid);
|
---|
142 | if (pContextInfo)
|
---|
143 | {
|
---|
144 | vboxDdiContextDestroy(&pThis->mWddmCallbacks, pContextInfo);
|
---|
145 | memset(pContextInfo, 0, sizeof(*pContextInfo));
|
---|
146 | RTMemFree(pContextInfo);
|
---|
147 | }
|
---|
148 | }
|
---|
149 |
|
---|
150 | HANDLE GaDrvEnvWddm::GaDrvEnvWddmContextHandle(uint32_t u32Cid)
|
---|
151 | {
|
---|
152 | GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&mContextTree, u32Cid);
|
---|
153 | return pContextInfo ? pContextInfo->hContext : NULL;
|
---|
154 | }
|
---|
155 |
|
---|
156 | /* static */ DECLCALLBACK(uint32_t)
|
---|
157 | GaDrvEnvWddm::gaEnvWddmContextCreate(void *pvEnv,
|
---|
158 | boolean extended,
|
---|
159 | boolean vgpu10)
|
---|
160 | {
|
---|
161 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
162 |
|
---|
163 | VBOXWDDM_CREATECONTEXT_INFO privateData;
|
---|
164 | GAWDDMCONTEXTINFO *pContextInfo;
|
---|
165 | HRESULT hr;
|
---|
166 |
|
---|
167 | pContextInfo = (GAWDDMCONTEXTINFO *)RTMemAlloc(sizeof(GAWDDMCONTEXTINFO));
|
---|
168 | if (!pContextInfo)
|
---|
169 | return (uint32_t)-1;
|
---|
170 |
|
---|
171 | memset(&privateData, 0, sizeof(privateData));
|
---|
172 | privateData.u32IfVersion = 9;
|
---|
173 | privateData.enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
|
---|
174 | privateData.u.vmsvga.u32Flags = extended? VBOXWDDM_F_GA_CONTEXT_EXTENDED: 0;
|
---|
175 | privateData.u.vmsvga.u32Flags |= vgpu10? VBOXWDDM_F_GA_CONTEXT_VGPU10: 0;
|
---|
176 |
|
---|
177 | hr = vboxDdiContextCreate(&pThis->mWddmCallbacks,
|
---|
178 | &privateData, sizeof(privateData), pContextInfo);
|
---|
179 | if (SUCCEEDED(hr))
|
---|
180 | {
|
---|
181 | if (RTAvlU32Insert(&pThis->mContextTree, &pContextInfo->Core))
|
---|
182 | {
|
---|
183 | return pContextInfo->Core.Key;
|
---|
184 | }
|
---|
185 |
|
---|
186 | vboxDdiContextDestroy(&pThis->mWddmCallbacks,
|
---|
187 | pContextInfo);
|
---|
188 | }
|
---|
189 |
|
---|
190 | RTMemFree(pContextInfo);
|
---|
191 | return (uint32_t)-1;
|
---|
192 | }
|
---|
193 |
|
---|
194 | /* static */ DECLCALLBACK(int)
|
---|
195 | GaDrvEnvWddm::gaEnvWddmSurfaceDefine(void *pvEnv,
|
---|
196 | GASURFCREATE *pCreateParms,
|
---|
197 | GASURFSIZE *paSizes,
|
---|
198 | uint32_t cSizes,
|
---|
199 | uint32_t *pu32Sid)
|
---|
200 | {
|
---|
201 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
202 |
|
---|
203 | HRESULT hr;
|
---|
204 | D3DDDICB_ESCAPE ddiEscape;
|
---|
205 | VBOXDISPIFESCAPE_GASURFACEDEFINE *pData;
|
---|
206 | uint32_t cbAlloc;
|
---|
207 | uint8_t *pu8Req;
|
---|
208 | uint32_t cbReq;
|
---|
209 |
|
---|
210 | /* Size of the SVGA request data */
|
---|
211 | cbReq = sizeof(GASURFCREATE) + cSizes * sizeof(GASURFSIZE);
|
---|
212 | /* How much to allocate for WDDM escape data. */
|
---|
213 | cbAlloc = sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE)
|
---|
214 | + cbReq;
|
---|
215 |
|
---|
216 | pData = (VBOXDISPIFESCAPE_GASURFACEDEFINE *)RTMemAllocZ(cbAlloc);
|
---|
217 | if (!pData)
|
---|
218 | return -1;
|
---|
219 |
|
---|
220 | pData->EscapeHdr.escapeCode = VBOXESC_GASURFACEDEFINE;
|
---|
221 | // pData->EscapeHdr.cmdSpecific = 0;
|
---|
222 | // pData->u32Sid = 0;
|
---|
223 | pData->cbReq = cbReq;
|
---|
224 | pData->cSizes = cSizes;
|
---|
225 |
|
---|
226 | pu8Req = (uint8_t *)&pData[1];
|
---|
227 | memcpy(pu8Req, pCreateParms, sizeof(GASURFCREATE));
|
---|
228 | memcpy(&pu8Req[sizeof(GASURFCREATE)], paSizes, cSizes * sizeof(GASURFSIZE));
|
---|
229 |
|
---|
230 | ddiEscape.hDevice = 0; // pThis->mWddmCallbacks.hDevice;
|
---|
231 | ddiEscape.Flags.Value = 0;
|
---|
232 | ddiEscape.Flags.HardwareAccess = 1; // Required, otherwise graphics corruption can happen. No idea why.
|
---|
233 | // Eventually we probably have to create allocations for surfaces,
|
---|
234 | // as a WDDM driver should do. Then the Escape hack will be removed.
|
---|
235 | ddiEscape.pPrivateDriverData = pData;
|
---|
236 | ddiEscape.PrivateDriverDataSize = cbAlloc;
|
---|
237 | ddiEscape.hContext = 0;
|
---|
238 |
|
---|
239 | hr = pThis->mWddmCallbacks.DeviceCallbacks.pfnEscapeCb(pThis->mWddmCallbacks.hAdapter, &ddiEscape);
|
---|
240 | if (FAILED(hr))
|
---|
241 | {
|
---|
242 | RTMemFree(pData);
|
---|
243 | return -1;
|
---|
244 | }
|
---|
245 |
|
---|
246 | *pu32Sid = pData->u32Sid;
|
---|
247 | RTMemFree(pData);
|
---|
248 | return 0;
|
---|
249 | }
|
---|
250 |
|
---|
251 | /* static */ DECLCALLBACK(void)
|
---|
252 | GaDrvEnvWddm::gaEnvWddmSurfaceDestroy(void *pvEnv,
|
---|
253 | uint32_t u32Sid)
|
---|
254 | {
|
---|
255 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
256 |
|
---|
257 | HRESULT hr;
|
---|
258 | D3DDDICB_ESCAPE ddiEscape;
|
---|
259 | VBOXDISPIFESCAPE_GASURFACEDESTROY data;
|
---|
260 |
|
---|
261 | memset(&data, 0, sizeof(data));
|
---|
262 | data.EscapeHdr.escapeCode = VBOXESC_GASURFACEDESTROY;
|
---|
263 | // data.EscapeHdr.cmdSpecific = 0;
|
---|
264 | data.u32Sid = u32Sid;
|
---|
265 |
|
---|
266 | ddiEscape.hDevice = 0; // pThis->mWddmCallbacks.hDevice;
|
---|
267 | ddiEscape.Flags.Value = 0;
|
---|
268 | ddiEscape.Flags.HardwareAccess = 1; // Required, otherwise graphics corruption can happen. No idea why.
|
---|
269 | // Eventually we probably have to create allocations for surfaces,
|
---|
270 | // as a WDDM driver should do. Then the Escape hack will be removed.
|
---|
271 | ddiEscape.pPrivateDriverData = &data;
|
---|
272 | ddiEscape.PrivateDriverDataSize = sizeof(data);
|
---|
273 | ddiEscape.hContext = 0;
|
---|
274 |
|
---|
275 | hr = pThis->mWddmCallbacks.DeviceCallbacks.pfnEscapeCb(pThis->mWddmCallbacks.hAdapter, &ddiEscape);
|
---|
276 | Assert(SUCCEEDED(hr));
|
---|
277 | }
|
---|
278 |
|
---|
279 | static HRESULT
|
---|
280 | vboxDdiFenceCreate(GaWddmCallbacks *pWddmCallbacks,
|
---|
281 | GAWDDMCONTEXTINFO *pContextInfo,
|
---|
282 | uint32_t *pu32FenceHandle)
|
---|
283 | {
|
---|
284 | HRESULT hr;
|
---|
285 | D3DDDICB_ESCAPE ddiEscape;
|
---|
286 | VBOXDISPIFESCAPE_GAFENCECREATE fenceCreate;
|
---|
287 |
|
---|
288 | memset(&fenceCreate, 0, sizeof(fenceCreate));
|
---|
289 |
|
---|
290 | fenceCreate.EscapeHdr.escapeCode = VBOXESC_GAFENCECREATE;
|
---|
291 | // fenceCreate.EscapeHdr.cmdSpecific = 0;
|
---|
292 |
|
---|
293 | /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
|
---|
294 | * have also set hDevice to a non-NULL value...
|
---|
295 | */
|
---|
296 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
297 | ddiEscape.Flags.Value = 0;
|
---|
298 | ddiEscape.pPrivateDriverData = &fenceCreate;
|
---|
299 | ddiEscape.PrivateDriverDataSize = sizeof(fenceCreate);
|
---|
300 | ddiEscape.hContext = pContextInfo->hContext;
|
---|
301 |
|
---|
302 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
303 | if (SUCCEEDED(hr))
|
---|
304 | {
|
---|
305 | *pu32FenceHandle = fenceCreate.u32FenceHandle;
|
---|
306 | }
|
---|
307 |
|
---|
308 | return hr;
|
---|
309 | }
|
---|
310 |
|
---|
311 | static HRESULT
|
---|
312 | vboxDdiFenceQuery(GaWddmCallbacks *pWddmCallbacks,
|
---|
313 | uint32_t u32FenceHandle,
|
---|
314 | GAFENCEQUERY *pFenceQuery)
|
---|
315 | {
|
---|
316 | HRESULT hr;
|
---|
317 | D3DDDICB_ESCAPE ddiEscape;
|
---|
318 | VBOXDISPIFESCAPE_GAFENCEQUERY fenceQuery;
|
---|
319 |
|
---|
320 | RT_ZERO(fenceQuery);
|
---|
321 | fenceQuery.EscapeHdr.escapeCode = VBOXESC_GAFENCEQUERY;
|
---|
322 | // fenceQuery.EscapeHdr.cmdSpecific = 0;
|
---|
323 | fenceQuery.u32FenceHandle = u32FenceHandle;
|
---|
324 |
|
---|
325 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
326 | ddiEscape.Flags.Value = 0;
|
---|
327 | ddiEscape.pPrivateDriverData = &fenceQuery;
|
---|
328 | ddiEscape.PrivateDriverDataSize = sizeof(fenceQuery);
|
---|
329 | ddiEscape.hContext = 0;
|
---|
330 |
|
---|
331 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
332 | if (SUCCEEDED(hr))
|
---|
333 | {
|
---|
334 | pFenceQuery->u32FenceHandle = fenceQuery.u32FenceHandle;
|
---|
335 | pFenceQuery->u32SubmittedSeqNo = fenceQuery.u32SubmittedSeqNo;
|
---|
336 | pFenceQuery->u32ProcessedSeqNo = fenceQuery.u32ProcessedSeqNo;
|
---|
337 | pFenceQuery->u32FenceStatus = fenceQuery.u32FenceStatus;
|
---|
338 | }
|
---|
339 | return hr;
|
---|
340 | }
|
---|
341 |
|
---|
342 | /* static */ DECLCALLBACK(int)
|
---|
343 | GaDrvEnvWddm::gaEnvWddmFenceQuery(void *pvEnv,
|
---|
344 | uint32_t u32FenceHandle,
|
---|
345 | GAFENCEQUERY *pFenceQuery)
|
---|
346 | {
|
---|
347 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
348 |
|
---|
349 | if (!pThis->mWddmCallbacks.hDevice)
|
---|
350 | {
|
---|
351 | pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
|
---|
352 | return 0;
|
---|
353 | }
|
---|
354 |
|
---|
355 | HRESULT hr = vboxDdiFenceQuery(&pThis->mWddmCallbacks, u32FenceHandle, pFenceQuery);
|
---|
356 | if (FAILED(hr))
|
---|
357 | return -1;
|
---|
358 |
|
---|
359 | return 0;
|
---|
360 | }
|
---|
361 |
|
---|
362 | static HRESULT
|
---|
363 | vboxDdiFenceWait(GaWddmCallbacks *pWddmCallbacks,
|
---|
364 | uint32_t u32FenceHandle,
|
---|
365 | uint32_t u32TimeoutUS)
|
---|
366 | {
|
---|
367 | HRESULT hr;
|
---|
368 | D3DDDICB_ESCAPE ddiEscape;
|
---|
369 | VBOXDISPIFESCAPE_GAFENCEWAIT fenceWait;
|
---|
370 |
|
---|
371 | memset(&fenceWait, 0, sizeof(fenceWait));
|
---|
372 |
|
---|
373 | fenceWait.EscapeHdr.escapeCode = VBOXESC_GAFENCEWAIT;
|
---|
374 | // pFenceWait->EscapeHdr.cmdSpecific = 0;
|
---|
375 | fenceWait.u32FenceHandle = u32FenceHandle;
|
---|
376 | fenceWait.u32TimeoutUS = u32TimeoutUS;
|
---|
377 |
|
---|
378 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
379 | ddiEscape.Flags.Value = 0;
|
---|
380 | ddiEscape.pPrivateDriverData = &fenceWait;
|
---|
381 | ddiEscape.PrivateDriverDataSize = sizeof(fenceWait);
|
---|
382 | ddiEscape.hContext = 0;
|
---|
383 |
|
---|
384 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
385 | return hr;
|
---|
386 | }
|
---|
387 |
|
---|
388 | /* static */ DECLCALLBACK(int)
|
---|
389 | GaDrvEnvWddm::gaEnvWddmFenceWait(void *pvEnv,
|
---|
390 | uint32_t u32FenceHandle,
|
---|
391 | uint32_t u32TimeoutUS)
|
---|
392 | {
|
---|
393 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
394 |
|
---|
395 | if (!pThis->mWddmCallbacks.hDevice)
|
---|
396 | return 0;
|
---|
397 |
|
---|
398 | HRESULT hr = vboxDdiFenceWait(&pThis->mWddmCallbacks, u32FenceHandle, u32TimeoutUS);
|
---|
399 | return SUCCEEDED(hr) ? 0 : -1;
|
---|
400 | }
|
---|
401 |
|
---|
402 | static HRESULT
|
---|
403 | vboxDdiFenceUnref(GaWddmCallbacks *pWddmCallbacks,
|
---|
404 | uint32_t u32FenceHandle)
|
---|
405 | {
|
---|
406 | HRESULT hr;
|
---|
407 | D3DDDICB_ESCAPE ddiEscape;
|
---|
408 | VBOXDISPIFESCAPE_GAFENCEUNREF fenceUnref;
|
---|
409 |
|
---|
410 | memset(&fenceUnref, 0, sizeof(fenceUnref));
|
---|
411 |
|
---|
412 | fenceUnref.EscapeHdr.escapeCode = VBOXESC_GAFENCEUNREF;
|
---|
413 | // pFenceUnref->EscapeHdr.cmdSpecific = 0;
|
---|
414 | fenceUnref.u32FenceHandle = u32FenceHandle;
|
---|
415 |
|
---|
416 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
417 | ddiEscape.Flags.Value = 0;
|
---|
418 | ddiEscape.pPrivateDriverData = &fenceUnref;
|
---|
419 | ddiEscape.PrivateDriverDataSize = sizeof(fenceUnref);
|
---|
420 | ddiEscape.hContext = 0;
|
---|
421 |
|
---|
422 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
423 | return hr;
|
---|
424 | }
|
---|
425 |
|
---|
426 | /* static */ DECLCALLBACK(void)
|
---|
427 | GaDrvEnvWddm::gaEnvWddmFenceUnref(void *pvEnv,
|
---|
428 | uint32_t u32FenceHandle)
|
---|
429 | {
|
---|
430 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
431 |
|
---|
432 | if (!pThis->mWddmCallbacks.hDevice)
|
---|
433 | return;
|
---|
434 |
|
---|
435 | vboxDdiFenceUnref(&pThis->mWddmCallbacks, u32FenceHandle);
|
---|
436 | }
|
---|
437 |
|
---|
438 | /** Calculate how many commands will fit in the buffer.
|
---|
439 | *
|
---|
440 | * @param pu8Commands Command buffer.
|
---|
441 | * @param cbCommands Size of command buffer.
|
---|
442 | * @param cbAvail Available buffer size..
|
---|
443 | * @param pu32Length Size of commands which will fit in cbAvail bytes.
|
---|
444 | */
|
---|
445 | static HRESULT
|
---|
446 | vboxCalcCommandLength(const uint8_t *pu8Commands, uint32_t cbCommands, uint32_t cbAvail, uint32_t *pu32Length)
|
---|
447 | {
|
---|
448 | HRESULT hr = S_OK;
|
---|
449 |
|
---|
450 | uint32_t u32Length = 0;
|
---|
451 | const uint8_t *pu8Src = pu8Commands;
|
---|
452 | const uint8_t *pu8SrcEnd = pu8Commands + cbCommands;
|
---|
453 |
|
---|
454 | while (pu8SrcEnd > pu8Src)
|
---|
455 | {
|
---|
456 | const uint32_t cbSrcLeft = pu8SrcEnd - pu8Src;
|
---|
457 | AssertBreakStmt(cbSrcLeft >= sizeof(uint32_t), hr = E_INVALIDARG);
|
---|
458 |
|
---|
459 | /* Get the command id and command length. */
|
---|
460 | const uint32_t u32CmdId = *(uint32_t *)pu8Src;
|
---|
461 | uint32_t cbCmd = 0;
|
---|
462 |
|
---|
463 | if (SVGA_3D_CMD_BASE <= u32CmdId && u32CmdId < SVGA_3D_CMD_MAX)
|
---|
464 | {
|
---|
465 | AssertBreakStmt(cbSrcLeft >= sizeof(SVGA3dCmdHeader), hr = E_INVALIDARG);
|
---|
466 |
|
---|
467 | const SVGA3dCmdHeader *pHeader = (SVGA3dCmdHeader *)pu8Src;
|
---|
468 | cbCmd = sizeof(SVGA3dCmdHeader) + pHeader->size;
|
---|
469 | AssertBreakStmt(cbCmd % sizeof(uint32_t) == 0, hr = E_INVALIDARG);
|
---|
470 | AssertBreakStmt(cbSrcLeft >= cbCmd, hr = E_INVALIDARG);
|
---|
471 | }
|
---|
472 | else
|
---|
473 | {
|
---|
474 | /* It is not expected that any of common SVGA commands will be in the command buffer
|
---|
475 | * because the SVGA gallium driver does not use them.
|
---|
476 | */
|
---|
477 | AssertBreakStmt(0, hr = E_INVALIDARG);
|
---|
478 | }
|
---|
479 |
|
---|
480 | if (u32Length + cbCmd > cbAvail)
|
---|
481 | {
|
---|
482 | if (u32Length == 0)
|
---|
483 | {
|
---|
484 | /* No commands fit into the buffer. */
|
---|
485 | hr = E_FAIL;
|
---|
486 | }
|
---|
487 | break;
|
---|
488 | }
|
---|
489 |
|
---|
490 | pu8Src += cbCmd;
|
---|
491 | u32Length += cbCmd;
|
---|
492 | }
|
---|
493 |
|
---|
494 | *pu32Length = u32Length;
|
---|
495 | return hr;
|
---|
496 | }
|
---|
497 |
|
---|
498 | static HRESULT
|
---|
499 | vboxDdiRender(GaWddmCallbacks *pWddmCallbacks,
|
---|
500 | GAWDDMCONTEXTINFO *pContextInfo, uint32_t u32FenceHandle, void *pvCommands, uint32_t cbCommands)
|
---|
501 | {
|
---|
502 | HRESULT hr = S_OK;
|
---|
503 | D3DDDICB_RENDER ddiRender;
|
---|
504 | uint32_t cbLeft;
|
---|
505 | const uint8_t *pu8Src;
|
---|
506 |
|
---|
507 | LogRel(("vboxDdiRender: cbCommands = %d, u32FenceHandle = %d\n", cbCommands, u32FenceHandle));
|
---|
508 |
|
---|
509 | cbLeft = cbCommands;
|
---|
510 | pu8Src = (uint8_t *)pvCommands;
|
---|
511 | /* Even when cbCommands is 0, submit the fence. The following code deals with this. */
|
---|
512 | do
|
---|
513 | {
|
---|
514 | /* Actually available space. */
|
---|
515 | const uint32_t cbAvail = pContextInfo->CommandBufferSize;
|
---|
516 | AssertBreakStmt(cbAvail > sizeof(u32FenceHandle), hr = E_FAIL);
|
---|
517 |
|
---|
518 | /* How many bytes of command data still to copy. */
|
---|
519 | uint32_t cbCommandChunk = cbLeft;
|
---|
520 |
|
---|
521 | /* How many bytes still to copy. */
|
---|
522 | uint32_t cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
|
---|
523 |
|
---|
524 | /* Copy the buffer identifier. */
|
---|
525 | if (cbToCopy <= cbAvail)
|
---|
526 | {
|
---|
527 | /* Command buffer is big enough. */
|
---|
528 | *(uint32_t *)pContextInfo->pCommandBuffer = u32FenceHandle;
|
---|
529 | }
|
---|
530 | else
|
---|
531 | {
|
---|
532 | /* Split. Write zero as buffer identifier. */
|
---|
533 | *(uint32_t *)pContextInfo->pCommandBuffer = 0;
|
---|
534 |
|
---|
535 | /* Get how much commands data will fit in the buffer. */
|
---|
536 | hr = vboxCalcCommandLength(pu8Src, cbCommandChunk, cbAvail - sizeof(u32FenceHandle), &cbCommandChunk);
|
---|
537 | AssertBreak(SUCCEEDED(hr));
|
---|
538 |
|
---|
539 | cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
|
---|
540 | }
|
---|
541 |
|
---|
542 | if (cbCommandChunk)
|
---|
543 | {
|
---|
544 | /* Copy the command data. */
|
---|
545 | memcpy((uint8_t *)pContextInfo->pCommandBuffer + sizeof(u32FenceHandle), pu8Src, cbCommandChunk);
|
---|
546 | }
|
---|
547 |
|
---|
548 | /* Advance the command position. */
|
---|
549 | pu8Src += cbCommandChunk;
|
---|
550 | cbLeft -= cbCommandChunk;
|
---|
551 |
|
---|
552 | memset(&ddiRender, 0, sizeof(ddiRender));
|
---|
553 | ddiRender.CommandLength = cbToCopy;
|
---|
554 | // ddiRender.CommandOffset = 0;
|
---|
555 | // ddiRender.NumAllocations = 0;
|
---|
556 | // ddiRender.NumPatchLocations = 0;
|
---|
557 | ddiRender.hContext = pContextInfo->hContext;
|
---|
558 |
|
---|
559 | hr = pWddmCallbacks->DeviceCallbacks.pfnRenderCb(pWddmCallbacks->hDevice, &ddiRender);
|
---|
560 | AssertBreak(SUCCEEDED(hr));
|
---|
561 |
|
---|
562 | pContextInfo->pCommandBuffer = ddiRender.pNewCommandBuffer;
|
---|
563 | pContextInfo->CommandBufferSize = ddiRender.NewCommandBufferSize;
|
---|
564 | } while (cbLeft);
|
---|
565 |
|
---|
566 | return hr;
|
---|
567 | }
|
---|
568 |
|
---|
569 | /* static */ DECLCALLBACK(int)
|
---|
570 | GaDrvEnvWddm::gaEnvWddmRender(void *pvEnv,
|
---|
571 | uint32_t u32Cid, void *pvCommands, uint32_t cbCommands,
|
---|
572 | GAFENCEQUERY *pFenceQuery)
|
---|
573 | {
|
---|
574 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
575 |
|
---|
576 | HRESULT hr = S_OK;
|
---|
577 | uint32_t u32FenceHandle;
|
---|
578 | GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&pThis->mContextTree, u32Cid);
|
---|
579 | if (!pContextInfo)
|
---|
580 | return -1;
|
---|
581 |
|
---|
582 | u32FenceHandle = 0;
|
---|
583 | if (pFenceQuery)
|
---|
584 | {
|
---|
585 | hr = vboxDdiFenceCreate(&pThis->mWddmCallbacks, pContextInfo, &u32FenceHandle);
|
---|
586 | }
|
---|
587 |
|
---|
588 | if (SUCCEEDED(hr))
|
---|
589 | {
|
---|
590 | hr = vboxDdiRender(&pThis->mWddmCallbacks, pContextInfo, u32FenceHandle, pvCommands, cbCommands);
|
---|
591 | if (SUCCEEDED(hr))
|
---|
592 | {
|
---|
593 | if (pFenceQuery)
|
---|
594 | {
|
---|
595 | HRESULT hr2 = vboxDdiFenceQuery(&pThis->mWddmCallbacks, u32FenceHandle, pFenceQuery);
|
---|
596 | if (hr2 != S_OK)
|
---|
597 | {
|
---|
598 | pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
|
---|
599 | }
|
---|
600 | }
|
---|
601 | }
|
---|
602 | }
|
---|
603 | return SUCCEEDED(hr)? 0: 1;
|
---|
604 | }
|
---|
605 |
|
---|
606 | static HRESULT
|
---|
607 | vboxDdiRegionCreate(GaWddmCallbacks *pWddmCallbacks,
|
---|
608 | uint32_t u32RegionSize,
|
---|
609 | uint32_t *pu32GmrId,
|
---|
610 | void **ppvMap)
|
---|
611 | {
|
---|
612 | HRESULT hr;
|
---|
613 | D3DDDICB_ESCAPE ddiEscape;
|
---|
614 | VBOXDISPIFESCAPE_GAREGION data;
|
---|
615 |
|
---|
616 | memset(&data, 0, sizeof(data));
|
---|
617 | data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
|
---|
618 | // data.EscapeHdr.cmdSpecific = 0;
|
---|
619 | data.u32Command = GA_REGION_CMD_CREATE;
|
---|
620 | data.u32NumPages = (u32RegionSize + PAGE_SIZE - 1) / PAGE_SIZE;
|
---|
621 | // data.u32GmrId = 0;
|
---|
622 | // data.u64UserAddress = 0;
|
---|
623 |
|
---|
624 | ddiEscape.hDevice = pWddmCallbacks->hDevice;
|
---|
625 | ddiEscape.Flags.Value = 0;
|
---|
626 | ddiEscape.pPrivateDriverData = &data;
|
---|
627 | ddiEscape.PrivateDriverDataSize = sizeof(data);
|
---|
628 | ddiEscape.hContext = 0;
|
---|
629 |
|
---|
630 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
631 | if (SUCCEEDED(hr))
|
---|
632 | {
|
---|
633 | *pu32GmrId = data.u32GmrId;
|
---|
634 | *ppvMap = (void *)(uintptr_t)data.u64UserAddress;
|
---|
635 | }
|
---|
636 | return hr;
|
---|
637 | }
|
---|
638 |
|
---|
639 | /* static */ DECLCALLBACK(int)
|
---|
640 | GaDrvEnvWddm::gaEnvWddmRegionCreate(void *pvEnv,
|
---|
641 | uint32_t u32RegionSize,
|
---|
642 | uint32_t *pu32GmrId,
|
---|
643 | void **ppvMap)
|
---|
644 | {
|
---|
645 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
646 |
|
---|
647 | int ret;
|
---|
648 |
|
---|
649 | if (pThis->mWddmCallbacks.hDevice)
|
---|
650 | {
|
---|
651 | /* That is a real device */
|
---|
652 | HRESULT hr = vboxDdiRegionCreate(&pThis->mWddmCallbacks, u32RegionSize, pu32GmrId, ppvMap);
|
---|
653 | ret = SUCCEEDED(hr)? 0: -1;
|
---|
654 | }
|
---|
655 | else
|
---|
656 | {
|
---|
657 | /* That is a fake device, created when WDDM adapter is initialized. */
|
---|
658 | *ppvMap = RTMemAlloc(u32RegionSize);
|
---|
659 | if (*ppvMap != NULL)
|
---|
660 | {
|
---|
661 | *pu32GmrId = 0;
|
---|
662 | ret = 0;
|
---|
663 | }
|
---|
664 | else
|
---|
665 | ret = -1;
|
---|
666 | }
|
---|
667 |
|
---|
668 | return ret;
|
---|
669 | }
|
---|
670 |
|
---|
671 | static HRESULT
|
---|
672 | vboxDdiRegionDestroy(GaWddmCallbacks *pWddmCallbacks,
|
---|
673 | uint32_t u32GmrId)
|
---|
674 | {
|
---|
675 | HRESULT hr;
|
---|
676 | D3DDDICB_ESCAPE ddiEscape;
|
---|
677 | VBOXDISPIFESCAPE_GAREGION data;
|
---|
678 |
|
---|
679 | memset(&data, 0, sizeof(data));
|
---|
680 | data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
|
---|
681 | // data.EscapeHdr.cmdSpecific = 0;
|
---|
682 | data.u32Command = GA_REGION_CMD_DESTROY;
|
---|
683 | // data.u32NumPages = 0;
|
---|
684 | data.u32GmrId = u32GmrId;
|
---|
685 | // data.u64UserAddress = 0;
|
---|
686 |
|
---|
687 | ddiEscape.hDevice = 0;
|
---|
688 | ddiEscape.Flags.Value = 0;
|
---|
689 | ddiEscape.pPrivateDriverData = &data;
|
---|
690 | ddiEscape.PrivateDriverDataSize = sizeof(data);
|
---|
691 | ddiEscape.hContext = 0;
|
---|
692 |
|
---|
693 | hr = pWddmCallbacks->DeviceCallbacks.pfnEscapeCb(pWddmCallbacks->hAdapter, &ddiEscape);
|
---|
694 | return hr;
|
---|
695 | }
|
---|
696 |
|
---|
697 | /* static */ DECLCALLBACK(void)
|
---|
698 | GaDrvEnvWddm::gaEnvWddmRegionDestroy(void *pvEnv,
|
---|
699 | uint32_t u32GmrId,
|
---|
700 | void *pvMap)
|
---|
701 | {
|
---|
702 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
703 |
|
---|
704 | if (pThis->mWddmCallbacks.hDevice)
|
---|
705 | {
|
---|
706 | vboxDdiRegionDestroy(&pThis->mWddmCallbacks, u32GmrId);
|
---|
707 | }
|
---|
708 | else
|
---|
709 | {
|
---|
710 | RTMemFree(pvMap);
|
---|
711 | }
|
---|
712 | }
|
---|
713 |
|
---|
714 |
|
---|
715 | /* static */ DECLCALLBACK(int)
|
---|
716 | GaDrvEnvWddm::gaEnvWddmGBSurfaceDefine(void *pvEnv,
|
---|
717 | SVGAGBSURFCREATE *pCreateParms)
|
---|
718 | {
|
---|
719 | GaDrvEnvWddm *pThis = (GaDrvEnvWddm *)pvEnv;
|
---|
720 |
|
---|
721 | HRESULT hr;
|
---|
722 | D3DDDICB_ESCAPE ddiEscape;
|
---|
723 | VBOXDISPIFESCAPE_SVGAGBSURFACEDEFINE data;
|
---|
724 | data.EscapeHdr.escapeCode = VBOXESC_SVGAGBSURFACEDEFINE;
|
---|
725 | data.EscapeHdr.u32CmdSpecific = 0;
|
---|
726 | data.CreateParms = *pCreateParms;
|
---|
727 |
|
---|
728 | ddiEscape.hDevice = 0; // pThis->mWddmCallbacks.hDevice;
|
---|
729 | ddiEscape.Flags.Value = 0;
|
---|
730 | ddiEscape.Flags.HardwareAccess = 1; // Required, otherwise graphics corruption can happen. No idea why.
|
---|
731 | // Eventually we probably have to create allocations for surfaces,
|
---|
732 | // as a WDDM driver should do. Then the Escape hack will be removed.
|
---|
733 | ddiEscape.pPrivateDriverData = &data;
|
---|
734 | ddiEscape.PrivateDriverDataSize = sizeof(data);
|
---|
735 | ddiEscape.hContext = 0;
|
---|
736 |
|
---|
737 | hr = pThis->mWddmCallbacks.DeviceCallbacks.pfnEscapeCb(pThis->mWddmCallbacks.hAdapter, &ddiEscape);
|
---|
738 | if (FAILED(hr))
|
---|
739 | return -1;
|
---|
740 |
|
---|
741 | pCreateParms->gmrid = data.CreateParms.gmrid;
|
---|
742 | pCreateParms->cbGB = data.CreateParms.cbGB;
|
---|
743 | pCreateParms->u64UserAddress = data.CreateParms.u64UserAddress;
|
---|
744 | pCreateParms->u32Sid = data.CreateParms.u32Sid;
|
---|
745 | return 0;
|
---|
746 | }
|
---|
747 |
|
---|
748 |
|
---|
749 | GaDrvEnvWddm::GaDrvEnvWddm()
|
---|
750 | :
|
---|
751 | mContextTree(0)
|
---|
752 | {
|
---|
753 | RT_ZERO(mWddmCallbacks);
|
---|
754 | RT_ZERO(mHWInfo);
|
---|
755 | RT_ZERO(mEnv);
|
---|
756 | }
|
---|
757 |
|
---|
758 | GaDrvEnvWddm::~GaDrvEnvWddm()
|
---|
759 | {
|
---|
760 | }
|
---|
761 |
|
---|
762 | HRESULT GaDrvEnvWddm::Init(HANDLE hAdapter,
|
---|
763 | HANDLE hDevice,
|
---|
764 | const D3DDDI_DEVICECALLBACKS *pDeviceCallbacks,
|
---|
765 | const VBOXGAHWINFO *pHWInfo)
|
---|
766 | {
|
---|
767 | mWddmCallbacks.hAdapter = hAdapter;
|
---|
768 | mWddmCallbacks.hDevice = hDevice;
|
---|
769 | if (pDeviceCallbacks)
|
---|
770 | {
|
---|
771 | mWddmCallbacks.DeviceCallbacks = *pDeviceCallbacks;
|
---|
772 | }
|
---|
773 | mHWInfo = *pHWInfo;
|
---|
774 | return VINF_SUCCESS;
|
---|
775 | }
|
---|
776 |
|
---|
777 | const WDDMGalliumDriverEnv *GaDrvEnvWddm::Env()
|
---|
778 | {
|
---|
779 | if (mEnv.cb == 0)
|
---|
780 | {
|
---|
781 | mEnv.cb = sizeof(WDDMGalliumDriverEnv);
|
---|
782 | mEnv.pvEnv = this;
|
---|
783 | mEnv.pfnContextCreate = gaEnvWddmContextCreate;
|
---|
784 | mEnv.pfnContextDestroy = gaEnvWddmContextDestroy;
|
---|
785 | mEnv.pfnSurfaceDefine = gaEnvWddmSurfaceDefine;
|
---|
786 | mEnv.pfnSurfaceDestroy = gaEnvWddmSurfaceDestroy;
|
---|
787 | mEnv.pfnRender = gaEnvWddmRender;
|
---|
788 | mEnv.pfnFenceUnref = gaEnvWddmFenceUnref;
|
---|
789 | mEnv.pfnFenceQuery = gaEnvWddmFenceQuery;
|
---|
790 | mEnv.pfnFenceWait = gaEnvWddmFenceWait;
|
---|
791 | mEnv.pfnRegionCreate = gaEnvWddmRegionCreate;
|
---|
792 | mEnv.pfnRegionDestroy = gaEnvWddmRegionDestroy;
|
---|
793 | mEnv.pHWInfo = &mHWInfo;
|
---|
794 | /* VGPU10 */
|
---|
795 | mEnv.pfnGBSurfaceDefine = gaEnvWddmGBSurfaceDefine;
|
---|
796 | }
|
---|
797 |
|
---|
798 | return &mEnv;
|
---|
799 | }
|
---|