VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/wddm/gallium/GaDrvEnvWddm.cpp

Last change on this file was 98103, checked in by vboxsync, 16 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: 26.3 KB
Line 
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
38typedef 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
50static HRESULT
51vboxDdiContextGetId(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
81static void
82vboxDdiContextDestroy(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
94static HRESULT
95vboxDdiContextCreate(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)
136GaDrvEnvWddm::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
150HANDLE 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)
157GaDrvEnvWddm::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)
195GaDrvEnvWddm::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)
252GaDrvEnvWddm::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
279static HRESULT
280vboxDdiFenceCreate(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
311static HRESULT
312vboxDdiFenceQuery(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)
343GaDrvEnvWddm::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
362static HRESULT
363vboxDdiFenceWait(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)
389GaDrvEnvWddm::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
402static HRESULT
403vboxDdiFenceUnref(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)
427GaDrvEnvWddm::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 */
445static HRESULT
446vboxCalcCommandLength(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
498static HRESULT
499vboxDdiRender(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)
570GaDrvEnvWddm::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
606static HRESULT
607vboxDdiRegionCreate(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)
640GaDrvEnvWddm::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
671static HRESULT
672vboxDdiRegionDestroy(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)
698GaDrvEnvWddm::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)
716GaDrvEnvWddm::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
749GaDrvEnvWddm::GaDrvEnvWddm()
750 :
751 mContextTree(0)
752{
753 RT_ZERO(mWddmCallbacks);
754 RT_ZERO(mHWInfo);
755 RT_ZERO(mEnv);
756}
757
758GaDrvEnvWddm::~GaDrvEnvWddm()
759{
760}
761
762HRESULT 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
777const 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}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use