VirtualBox

source: vbox/trunk/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp@ 99534

Last change on this file since 99534 was 99534, checked in by vboxsync, 13 months ago

Additions/3D/win/VBoxGL: more formats; sync region destruction. bugref:9845

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.2 KB
Line 
1/* $Id: GaDrvEnvKMT.cpp 99534 2023-04-26 16:19:45Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Mesa3D - Gallium driver interface to the WDDM miniport driver using Kernel Mode Thunks.
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 "GaDrvEnvKMT.h"
29
30#include <UmHlpInternal.h>
31
32#include "svga3d_reg.h"
33
34#include <common/wddm/VBoxMPIf.h>
35
36#include <iprt/assertcompile.h>
37#include <iprt/param.h> /* For PAGE_SIZE */
38
39AssertCompile(sizeof(HANDLE) >= sizeof(D3DKMT_HANDLE));
40
41
42/*
43 * AVL configuration.
44 */
45#define KAVL_FN(a) RTAvlU32##a
46#define KAVL_MAX_STACK 27 /* Up to 2^24 nodes. */
47#define KAVL_CHECK_FOR_EQUAL_INSERT 1 /* No duplicate keys! */
48#define KAVLNODECORE AVLU32NODECORE
49#define PKAVLNODECORE PAVLU32NODECORE
50#define PPKAVLNODECORE PPAVLU32NODECORE
51#define KAVLKEY AVLU32KEY
52#define PKAVLKEY PAVLU32KEY
53#define KAVLENUMDATA AVLU32ENUMDATA
54#define PKAVLENUMDATA PAVLU32ENUMDATA
55#define PKAVLCALLBACK PAVLU32CALLBACK
56
57
58/*
59 * AVL Compare macros
60 */
61#define KAVL_G(key1, key2) ( (key1) > (key2) )
62#define KAVL_E(key1, key2) ( (key1) == (key2) )
63#define KAVL_NE(key1, key2) ( (key1) != (key2) )
64
65
66#include <iprt/avl.h>
67
68/*
69 * Include the code.
70 */
71#define SSToDS(ptr) ptr
72#define KMAX RT_MAX
73#define kASSERT(_e) do { } while (0)
74#include "avl_Base.cpp.h"
75#include "avl_Get.cpp.h"
76//#include "avl_GetBestFit.cpp.h"
77//#include "avl_RemoveBestFit.cpp.h"
78//#include "avl_DoWithAll.cpp.h"
79#include "avl_Destroy.cpp.h"
80
81
82typedef struct GaKmtCallbacks
83{
84 D3DKMT_HANDLE hAdapter;
85 D3DKMT_HANDLE hDevice;
86 D3DKMTFUNCTIONS const *d3dkmt;
87 LUID AdapterLuid;
88} GaKmtCallbacks;
89
90class GaDrvEnvKmt
91{
92 public:
93 GaDrvEnvKmt();
94 ~GaDrvEnvKmt();
95
96 HRESULT Init(void);
97
98 const WDDMGalliumDriverEnv *Env();
99
100 /*
101 * KMT specific helpers.
102 */
103 bool drvEnvKmtRenderCompose(uint32_t u32Cid,
104 void *pvCommands,
105 uint32_t cbCommands,
106 ULONGLONG PresentHistoryToken);
107 D3DKMT_HANDLE drvEnvKmtContextHandle(uint32_t u32Cid);
108 D3DKMT_HANDLE drvEnvKmtSurfaceHandle(uint32_t u32Sid);
109
110 GaKmtCallbacks mKmtCallbacks;
111
112 private:
113
114 VBOXGAHWINFO mHWInfo;
115
116 /* Map to convert context id (cid) to WDDM context information (GAWDDMCONTEXTINFO).
117 * Key is the 32 bit context id.
118 */
119 AVLU32TREE mContextTree;
120
121 /* Map to convert surface id (sid) to WDDM surface information (GAWDDMSURFACEINFO).
122 * Key is the 32 bit surface id.
123 */
124 AVLU32TREE mSurfaceTree;
125
126 WDDMGalliumDriverEnv mEnv;
127
128 static DECLCALLBACK(uint32_t) gaEnvContextCreate(void *pvEnv,
129 boolean extended,
130 boolean vgpu10);
131 static DECLCALLBACK(void) gaEnvContextDestroy(void *pvEnv,
132 uint32_t u32Cid);
133 static DECLCALLBACK(int) gaEnvSurfaceDefine(void *pvEnv,
134 GASURFCREATE *pCreateParms,
135 GASURFSIZE *paSizes,
136 uint32_t cSizes,
137 uint32_t *pu32Sid);
138 static DECLCALLBACK(void) gaEnvSurfaceDestroy(void *pvEnv,
139 uint32_t u32Sid);
140 static DECLCALLBACK(int) gaEnvRender(void *pvEnv,
141 uint32_t u32Cid,
142 void *pvCommands,
143 uint32_t cbCommands,
144 GAFENCEQUERY *pFenceQuery);
145 static DECLCALLBACK(void) gaEnvFenceUnref(void *pvEnv,
146 uint32_t u32FenceHandle);
147 static DECLCALLBACK(int) gaEnvFenceQuery(void *pvEnv,
148 uint32_t u32FenceHandle,
149 GAFENCEQUERY *pFenceQuery);
150 static DECLCALLBACK(int) gaEnvFenceWait(void *pvEnv,
151 uint32_t u32FenceHandle,
152 uint32_t u32TimeoutUS);
153 static DECLCALLBACK(int) gaEnvRegionCreate(void *pvEnv,
154 uint32_t u32RegionSize,
155 uint32_t *pu32GmrId,
156 void **ppvMap);
157 static DECLCALLBACK(void) gaEnvRegionDestroy(void *pvEnv,
158 uint32_t u32GmrId,
159 void *pvMap);
160
161 /* VGPU10 */
162 static DECLCALLBACK(int) gaEnvGBSurfaceDefine(void *pvEnv,
163 SVGAGBSURFCREATE *pCreateParms);
164
165 /*
166 * Internal.
167 */
168 bool doRender(uint32_t u32Cid, void *pvCommands, uint32_t cbCommands,
169 GAFENCEQUERY *pFenceQuery, ULONGLONG PresentHistoryToken, bool fPresentRedirected);
170};
171
172typedef struct GAWDDMCONTEXTINFO
173{
174 AVLU32NODECORE Core;
175 D3DKMT_HANDLE hContext;
176 VOID *pCommandBuffer;
177 UINT CommandBufferSize;
178 D3DDDI_ALLOCATIONLIST *pAllocationList;
179 UINT AllocationListSize;
180 D3DDDI_PATCHLOCATIONLIST *pPatchLocationList;
181 UINT PatchLocationListSize;
182} GAWDDMCONTEXTINFO;
183
184typedef struct GAWDDMSURFACEINFO
185{
186 AVLU32NODECORE Core;
187 D3DKMT_HANDLE hAllocation;
188} GAWDDMSURFACEINFO;
189
190
191/// @todo vboxDdi helpers must return a boof success indicator
192static bool
193vboxDdiQueryAdapterInfo(GaKmtCallbacks *pKmtCallbacks,
194 D3DKMT_HANDLE hAdapter,
195 VBOXWDDM_QAI *pAdapterInfo,
196 uint32_t cbAdapterInfo)
197{
198 D3DKMT_QUERYADAPTERINFO QAI;
199 memset(&QAI, 0, sizeof(QAI));
200 QAI.hAdapter = hAdapter;
201 QAI.Type = KMTQAITYPE_UMDRIVERPRIVATE;
202 QAI.pPrivateDriverData = pAdapterInfo;
203 QAI.PrivateDriverDataSize = cbAdapterInfo;
204
205 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTQueryAdapterInfo(&QAI);
206 return Status == STATUS_SUCCESS;
207}
208
209static void
210vboxDdiDeviceDestroy(GaKmtCallbacks *pKmtCallbacks,
211 D3DKMT_HANDLE hDevice)
212{
213 if (hDevice)
214 {
215 D3DKMT_DESTROYDEVICE DestroyDeviceData;
216 memset(&DestroyDeviceData, 0, sizeof(DestroyDeviceData));
217 DestroyDeviceData.hDevice = hDevice;
218 pKmtCallbacks->d3dkmt->pfnD3DKMTDestroyDevice(&DestroyDeviceData);
219 }
220}
221
222static bool
223vboxDdiDeviceCreate(GaKmtCallbacks *pKmtCallbacks,
224 D3DKMT_HANDLE *phDevice)
225{
226 D3DKMT_CREATEDEVICE CreateDeviceData;
227 memset(&CreateDeviceData, 0, sizeof(CreateDeviceData));
228 CreateDeviceData.hAdapter = pKmtCallbacks->hAdapter;
229 // CreateDeviceData.Flags = 0;
230
231 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTCreateDevice(&CreateDeviceData);
232 if (Status == STATUS_SUCCESS)
233 {
234 *phDevice = CreateDeviceData.hDevice;
235 return true;
236 }
237 return false;
238}
239
240static bool
241vboxDdiContextGetId(GaKmtCallbacks *pKmtCallbacks,
242 D3DKMT_HANDLE hContext,
243 uint32_t *pu32Cid)
244{
245 VBOXDISPIFESCAPE_GAGETCID data;
246 memset(&data, 0, sizeof(data));
247 data.EscapeHdr.escapeCode = VBOXESC_GAGETCID;
248 // data.EscapeHdr.cmdSpecific = 0;
249 // data.u32Cid = 0;
250
251 /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
252 * have also set hDevice to a non-NULL value...
253 */
254 D3DKMT_ESCAPE EscapeData;
255 memset(&EscapeData, 0, sizeof(EscapeData));
256 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
257 EscapeData.hDevice = pKmtCallbacks->hDevice;
258 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
259 // EscapeData.Flags.HardwareAccess = 0;
260 EscapeData.pPrivateDriverData = &data;
261 EscapeData.PrivateDriverDataSize = sizeof(data);
262 EscapeData.hContext = hContext;
263
264 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
265 if (Status == STATUS_SUCCESS)
266 {
267 *pu32Cid = data.u32Cid;
268 return true;
269 }
270 return false;
271}
272
273static void
274vboxDdiContextDestroy(GaKmtCallbacks *pKmtCallbacks,
275 GAWDDMCONTEXTINFO *pContextInfo)
276{
277 if (pContextInfo->hContext)
278 {
279 D3DKMT_DESTROYCONTEXT DestroyContextData;
280 memset(&DestroyContextData, 0, sizeof(DestroyContextData));
281 DestroyContextData.hContext = pContextInfo->hContext;
282 pKmtCallbacks->d3dkmt->pfnD3DKMTDestroyContext(&DestroyContextData);
283 }
284}
285
286static bool
287vboxDdiContextCreate(GaKmtCallbacks *pKmtCallbacks,
288 void *pvPrivateData, uint32_t cbPrivateData,
289 GAWDDMCONTEXTINFO *pContextInfo)
290{
291 D3DKMT_CREATECONTEXT CreateContextData;
292 memset(&CreateContextData, 0, sizeof(CreateContextData));
293 CreateContextData.hDevice = pKmtCallbacks->hDevice;
294 // CreateContextData.NodeOrdinal = 0;
295 // CreateContextData.EngineAffinity = 0;
296 // CreateContextData.Flags.Value = 0;
297 CreateContextData.pPrivateDriverData = pvPrivateData;
298 CreateContextData.PrivateDriverDataSize = cbPrivateData;
299 CreateContextData.ClientHint = D3DKMT_CLIENTHINT_OPENGL;
300
301 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTCreateContext(&CreateContextData);
302 if (Status == STATUS_SUCCESS)
303 {
304 /* Query cid. */
305 uint32_t u32Cid = 0;
306 bool fSuccess = vboxDdiContextGetId(pKmtCallbacks, CreateContextData.hContext, &u32Cid);
307 if (fSuccess)
308 {
309 pContextInfo->Core.Key = u32Cid;
310 pContextInfo->hContext = CreateContextData.hContext;
311 pContextInfo->pCommandBuffer = CreateContextData.pCommandBuffer;
312 pContextInfo->CommandBufferSize = CreateContextData.CommandBufferSize;
313 pContextInfo->pAllocationList = CreateContextData.pAllocationList;
314 pContextInfo->AllocationListSize = CreateContextData.AllocationListSize;
315 pContextInfo->pPatchLocationList = CreateContextData.pPatchLocationList;
316 pContextInfo->PatchLocationListSize = CreateContextData.PatchLocationListSize;
317
318 return true;
319 }
320
321 vboxDdiContextDestroy(pKmtCallbacks, pContextInfo);
322 }
323
324 return false;
325}
326
327/* static */ DECLCALLBACK(void)
328GaDrvEnvKmt::gaEnvContextDestroy(void *pvEnv,
329 uint32_t u32Cid)
330{
331 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
332
333 GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Remove(&pThis->mContextTree, u32Cid);
334 if (pContextInfo)
335 {
336 vboxDdiContextDestroy(&pThis->mKmtCallbacks, pContextInfo);
337 memset(pContextInfo, 0, sizeof(*pContextInfo));
338 free(pContextInfo);
339 }
340}
341
342D3DKMT_HANDLE GaDrvEnvKmt::drvEnvKmtContextHandle(uint32_t u32Cid)
343{
344 GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&mContextTree, u32Cid);
345 Assert(pContextInfo);
346 return pContextInfo ? pContextInfo->hContext : 0;
347}
348
349/* static */ DECLCALLBACK(uint32_t)
350GaDrvEnvKmt::gaEnvContextCreate(void *pvEnv,
351 boolean extended,
352 boolean vgpu10)
353{
354 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
355
356 GAWDDMCONTEXTINFO *pContextInfo;
357 pContextInfo = (GAWDDMCONTEXTINFO *)malloc(sizeof(GAWDDMCONTEXTINFO));
358 if (!pContextInfo)
359 return (uint32_t)-1;
360
361 VBOXWDDM_CREATECONTEXT_INFO privateData;
362 memset(&privateData, 0, sizeof(privateData));
363 privateData.u32IfVersion = 9;
364 privateData.enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
365 privateData.u.vmsvga.u32Flags = extended? VBOXWDDM_F_GA_CONTEXT_EXTENDED: 0;
366 privateData.u.vmsvga.u32Flags |= vgpu10? VBOXWDDM_F_GA_CONTEXT_VGPU10: 0;
367
368 bool fSuccess = vboxDdiContextCreate(&pThis->mKmtCallbacks,
369 &privateData, sizeof(privateData), pContextInfo);
370 if (fSuccess)
371 {
372 if (RTAvlU32Insert(&pThis->mContextTree, &pContextInfo->Core))
373 {
374 return pContextInfo->Core.Key;
375 }
376
377 vboxDdiContextDestroy(&pThis->mKmtCallbacks,
378 pContextInfo);
379 }
380
381 Assert(0);
382 free(pContextInfo);
383 return (uint32_t)-1;
384}
385
386static D3DDDIFORMAT svgaToD3DDDIFormat(SVGA3dSurfaceFormat format)
387{
388 /* The returning D3DDDIFMT_ value is used only to compute bpp, pitch, etc,
389 * so there is not need for an exact match.
390 */
391 switch (format)
392 {
393 case SVGA3D_X8R8G8B8: return D3DDDIFMT_X8R8G8B8;
394 case SVGA3D_A8R8G8B8: return D3DDDIFMT_A8R8G8B8;
395 case SVGA3D_ALPHA8: return D3DDDIFMT_A8;
396 case SVGA3D_R8G8B8A8_UNORM: return D3DDDIFMT_A8B8G8R8;
397 case SVGA3D_A4R4G4B4: return D3DDDIFMT_A4R4G4B4;
398 case SVGA3D_LUMINANCE8: return D3DDDIFMT_L8;
399 case SVGA3D_A1R5G5B5: return D3DDDIFMT_A1R5G5B5;
400 case SVGA3D_LUMINANCE8_ALPHA8: return D3DDDIFMT_A8L8;
401 case SVGA3D_R5G6B5: return D3DDDIFMT_R5G6B5;
402 case SVGA3D_ARGB_S10E5: return D3DDDIFMT_A16B16G16R16F;
403 case SVGA3D_ARGB_S23E8: return D3DDDIFMT_A32B32G32R32F;
404 case SVGA3D_B8G8R8A8_UNORM: return D3DDDIFMT_A8R8G8B8;
405 case SVGA3D_B8G8R8X8_UNORM: return D3DDDIFMT_X8R8G8B8;
406 case SVGA3D_R8_UNORM: /* R8->A8 conversion is not correct, but it does not matter here,
407 * because the D3DDDIFMT_ value is used only to compute bpp, pitch, etc. */
408 case SVGA3D_A8_UNORM: return D3DDDIFMT_A8;
409 case SVGA3D_B5G5R5A1_UNORM: return D3DDDIFMT_A1R5G5B5;
410
411 case SVGA3D_R8G8_UNORM: return D3DDDIFMT_A8L8;
412 case SVGA3D_R16_FLOAT: return D3DDDIFMT_R16F;
413 case SVGA3D_R16G16_FLOAT: return D3DDDIFMT_G16R16F;
414 case SVGA3D_R16G16B16A16_FLOAT: return D3DDDIFMT_A16B16G16R16F;
415 case SVGA3D_R32G32B32A32_FLOAT: return D3DDDIFMT_A32B32G32R32F;
416 case SVGA3D_R8G8B8A8_TYPELESS: return D3DDDIFMT_A8R8G8B8;
417 case SVGA3D_R16_UINT: return D3DDDIFMT_L16;
418 default: break;
419 }
420
421 VBoxDispMpLoggerLogF("WDDM: EnvKMT: unsupported surface format %d\n", format);
422 Assert(0);
423 return D3DDDIFMT_UNKNOWN;
424}
425
426/* static */ DECLCALLBACK(int)
427GaDrvEnvKmt::gaEnvSurfaceDefine(void *pvEnv,
428 GASURFCREATE *pCreateParms,
429 GASURFSIZE *paSizes,
430 uint32_t cSizes,
431 uint32_t *pu32Sid)
432{
433 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
434
435 D3DKMT_ESCAPE EscapeData;
436 VBOXDISPIFESCAPE_GASURFACEDEFINE *pData;
437 uint32_t cbAlloc;
438 uint8_t *pu8Req;
439 uint32_t cbReq;
440
441 /* Size of the SVGA request data */
442 cbReq = sizeof(GASURFCREATE) + cSizes * sizeof(GASURFSIZE);
443 /* How much to allocate for WDDM escape data. */
444 cbAlloc = sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE)
445 + cbReq;
446
447 pData = (VBOXDISPIFESCAPE_GASURFACEDEFINE *)malloc(cbAlloc);
448 if (!pData)
449 return -1;
450
451 pData->EscapeHdr.escapeCode = VBOXESC_GASURFACEDEFINE;
452 // pData->EscapeHdr.cmdSpecific = 0;
453 // pData->u32Sid = 0;
454 pData->cbReq = cbReq;
455 pData->cSizes = cSizes;
456
457 pu8Req = (uint8_t *)&pData[1];
458 memcpy(pu8Req, pCreateParms, sizeof(GASURFCREATE));
459 memcpy(&pu8Req[sizeof(GASURFCREATE)], paSizes, cSizes * sizeof(GASURFSIZE));
460
461 memset(&EscapeData, 0, sizeof(EscapeData));
462 EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
463 EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
464 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
465 EscapeData.Flags.HardwareAccess = 1;
466 EscapeData.pPrivateDriverData = pData;
467 EscapeData.PrivateDriverDataSize = cbAlloc;
468 // EscapeData.hContext = 0;
469
470 NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
471 if (Status == STATUS_SUCCESS)
472 {
473 /* Create a kernel mode allocation for render targets,
474 * because we will need kernel mode handles for Present.
475 */
476 if (pCreateParms->flags & SVGA3D_SURFACE_HINT_RENDERTARGET)
477 {
478 /* First check if the format is supported. */
479 D3DDDIFORMAT const ddiFormat = svgaToD3DDDIFormat((SVGA3dSurfaceFormat)pCreateParms->format);
480 if (ddiFormat != D3DDDIFMT_UNKNOWN)
481 {
482 GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)malloc(sizeof(GAWDDMSURFACEINFO));
483 if (pSurfaceInfo)
484 {
485 memset(pSurfaceInfo, 0, sizeof(GAWDDMSURFACEINFO));
486
487 VBOXWDDM_ALLOCINFO wddmAllocInfo;
488 memset(&wddmAllocInfo, 0, sizeof(wddmAllocInfo));
489
490 wddmAllocInfo.enmType = VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC;
491 wddmAllocInfo.fFlags.RenderTarget = 1;
492 wddmAllocInfo.hSharedHandle = 0;
493 wddmAllocInfo.hostID = pData->u32Sid;
494 wddmAllocInfo.SurfDesc.slicePitch = 0;
495 wddmAllocInfo.SurfDesc.depth = paSizes[0].cDepth;
496 wddmAllocInfo.SurfDesc.width = paSizes[0].cWidth;
497 wddmAllocInfo.SurfDesc.height = paSizes[0].cHeight;
498 wddmAllocInfo.SurfDesc.format = ddiFormat;
499 wddmAllocInfo.SurfDesc.VidPnSourceId = 0;
500 wddmAllocInfo.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(wddmAllocInfo.SurfDesc.format);
501 wddmAllocInfo.SurfDesc.pitch = vboxWddmCalcPitch(wddmAllocInfo.SurfDesc.width,
502 wddmAllocInfo.SurfDesc.format);
503 wddmAllocInfo.SurfDesc.cbSize = vboxWddmCalcSize(wddmAllocInfo.SurfDesc.pitch,
504 wddmAllocInfo.SurfDesc.height,
505 wddmAllocInfo.SurfDesc.format);
506 wddmAllocInfo.SurfDesc.d3dWidth = vboxWddmCalcWidthForPitch(wddmAllocInfo.SurfDesc.pitch,
507 wddmAllocInfo.SurfDesc.format);
508
509 D3DDDI_ALLOCATIONINFO AllocationInfo;
510 memset(&AllocationInfo, 0, sizeof(AllocationInfo));
511 // AllocationInfo.hAllocation = NULL;
512 // AllocationInfo.pSystemMem = NULL;
513 AllocationInfo.pPrivateDriverData = &wddmAllocInfo;
514 AllocationInfo.PrivateDriverDataSize = sizeof(wddmAllocInfo);
515
516 D3DKMT_CREATEALLOCATION CreateAllocation;
517 memset(&CreateAllocation, 0, sizeof(CreateAllocation));
518 CreateAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
519 CreateAllocation.NumAllocations = 1;
520 CreateAllocation.pAllocationInfo = &AllocationInfo;
521
522 Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTCreateAllocation(&CreateAllocation);
523 if (Status == STATUS_SUCCESS)
524 {
525 pSurfaceInfo->Core.Key = pData->u32Sid;
526 pSurfaceInfo->hAllocation = AllocationInfo.hAllocation;
527 if (!RTAvlU32Insert(&pThis->mSurfaceTree, &pSurfaceInfo->Core))
528 {
529 Status = STATUS_NOT_SUPPORTED;
530 }
531 }
532
533 if (Status != STATUS_SUCCESS)
534 {
535 free(pSurfaceInfo);
536 }
537 }
538 else
539 {
540 Status = STATUS_NOT_SUPPORTED;
541 }
542 }
543 else
544 {
545 /* Unsupported render target format. */
546 Status = STATUS_NOT_SUPPORTED;
547 }
548 }
549
550 if (Status != STATUS_SUCCESS)
551 {
552 gaEnvSurfaceDestroy(pvEnv, pData->u32Sid);
553 }
554 }
555
556 if (Status == STATUS_SUCCESS)
557 {
558 *pu32Sid = pData->u32Sid;
559 free(pData);
560 return 0;
561 }
562
563 Assert(0);
564 free(pData);
565 return -1;
566}
567
568/* static */ DECLCALLBACK(void)
569GaDrvEnvKmt::gaEnvSurfaceDestroy(void *pvEnv,
570 uint32_t u32Sid)
571{
572 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
573
574 VBOXDISPIFESCAPE_GASURFACEDESTROY data;
575 memset(&data, 0, sizeof(data));
576 data.EscapeHdr.escapeCode = VBOXESC_GASURFACEDESTROY;
577 // data.EscapeHdr.cmdSpecific = 0;
578 data.u32Sid = u32Sid;
579
580 D3DKMT_ESCAPE EscapeData;
581 memset(&EscapeData, 0, sizeof(EscapeData));
582 EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
583 EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
584 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
585 EscapeData.Flags.HardwareAccess = 1;
586 EscapeData.pPrivateDriverData = &data;
587 EscapeData.PrivateDriverDataSize = sizeof(data);
588 // EscapeData.hContext = 0;
589
590 NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
591 Assert(Status == STATUS_SUCCESS);
592
593 /* Try to remove from sid -> hAllocation map. */
594 GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)RTAvlU32Remove(&pThis->mSurfaceTree, u32Sid);
595 if (pSurfaceInfo)
596 {
597 D3DKMT_DESTROYALLOCATION DestroyAllocation;
598 memset(&DestroyAllocation, 0, sizeof(DestroyAllocation));
599 DestroyAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
600 // DestroyAllocation.hResource = 0;
601 DestroyAllocation.phAllocationList = &pSurfaceInfo->hAllocation;
602 DestroyAllocation.AllocationCount = 1;
603
604 Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTDestroyAllocation(&DestroyAllocation);
605 Assert(Status == STATUS_SUCCESS);
606
607 free(pSurfaceInfo);
608 }
609}
610
611D3DKMT_HANDLE GaDrvEnvKmt::drvEnvKmtSurfaceHandle(uint32_t u32Sid)
612{
613 GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)RTAvlU32Get(&mSurfaceTree, u32Sid);
614 return pSurfaceInfo ? pSurfaceInfo->hAllocation : 0;
615}
616
617static bool
618vboxDdiFenceCreate(GaKmtCallbacks *pKmtCallbacks,
619 GAWDDMCONTEXTINFO *pContextInfo,
620 uint32_t *pu32FenceHandle)
621{
622 VBOXDISPIFESCAPE_GAFENCECREATE fenceCreate;
623 memset(&fenceCreate, 0, sizeof(fenceCreate));
624 fenceCreate.EscapeHdr.escapeCode = VBOXESC_GAFENCECREATE;
625 // fenceCreate.EscapeHdr.cmdSpecific = 0;
626
627 /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
628 * have also set hDevice to a non-NULL value...
629 */
630 D3DKMT_ESCAPE EscapeData;
631 memset(&EscapeData, 0, sizeof(EscapeData));
632 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
633 EscapeData.hDevice = pKmtCallbacks->hDevice;
634 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
635 // EscapeData.Flags.HardwareAccess = 0;
636 EscapeData.pPrivateDriverData = &fenceCreate;
637 EscapeData.PrivateDriverDataSize = sizeof(fenceCreate);
638 EscapeData.hContext = pContextInfo->hContext;
639
640 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
641 if (Status == STATUS_SUCCESS)
642 {
643 *pu32FenceHandle = fenceCreate.u32FenceHandle;
644 return true;
645 }
646
647 Assert(0);
648 return false;
649}
650
651static bool
652vboxDdiFenceQuery(GaKmtCallbacks *pKmtCallbacks,
653 uint32_t u32FenceHandle,
654 GAFENCEQUERY *pFenceQuery)
655{
656 VBOXDISPIFESCAPE_GAFENCEQUERY fenceQuery;
657 memset(&fenceQuery, 0, sizeof(fenceQuery));
658 fenceQuery.EscapeHdr.escapeCode = VBOXESC_GAFENCEQUERY;
659 // fenceQuery.EscapeHdr.cmdSpecific = 0;
660 fenceQuery.u32FenceHandle = u32FenceHandle;
661
662 D3DKMT_ESCAPE EscapeData;
663 memset(&EscapeData, 0, sizeof(EscapeData));
664 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
665 EscapeData.hDevice = pKmtCallbacks->hDevice;
666 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
667 // EscapeData.Flags.HardwareAccess = 0;
668 EscapeData.pPrivateDriverData = &fenceQuery;
669 EscapeData.PrivateDriverDataSize = sizeof(fenceQuery);
670 EscapeData.hContext = 0;
671
672 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
673 if (Status == STATUS_SUCCESS)
674 {
675 pFenceQuery->u32FenceHandle = fenceQuery.u32FenceHandle;
676 pFenceQuery->u32SubmittedSeqNo = fenceQuery.u32SubmittedSeqNo;
677 pFenceQuery->u32ProcessedSeqNo = fenceQuery.u32ProcessedSeqNo;
678 pFenceQuery->u32FenceStatus = fenceQuery.u32FenceStatus;
679 return true;
680 }
681
682 Assert(0);
683 return false;
684}
685
686/* static */ DECLCALLBACK(int)
687GaDrvEnvKmt::gaEnvFenceQuery(void *pvEnv,
688 uint32_t u32FenceHandle,
689 GAFENCEQUERY *pFenceQuery)
690{
691 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
692
693 if (!pThis->mKmtCallbacks.hDevice)
694 {
695 pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
696 return 0;
697 }
698
699 bool fSuccess = vboxDdiFenceQuery(&pThis->mKmtCallbacks, u32FenceHandle, pFenceQuery);
700 return fSuccess ? 0: -1;
701}
702
703static bool
704vboxDdiFenceWait(GaKmtCallbacks *pKmtCallbacks,
705 uint32_t u32FenceHandle,
706 uint32_t u32TimeoutUS)
707{
708 VBOXDISPIFESCAPE_GAFENCEWAIT fenceWait;
709 memset(&fenceWait, 0, sizeof(fenceWait));
710 fenceWait.EscapeHdr.escapeCode = VBOXESC_GAFENCEWAIT;
711 // pFenceWait->EscapeHdr.cmdSpecific = 0;
712 fenceWait.u32FenceHandle = u32FenceHandle;
713 fenceWait.u32TimeoutUS = u32TimeoutUS;
714
715 D3DKMT_ESCAPE EscapeData;
716 memset(&EscapeData, 0, sizeof(EscapeData));
717 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
718 EscapeData.hDevice = pKmtCallbacks->hDevice;
719 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
720 // EscapeData.Flags.HardwareAccess = 0;
721 EscapeData.pPrivateDriverData = &fenceWait;
722 EscapeData.PrivateDriverDataSize = sizeof(fenceWait);
723 EscapeData.hContext = 0;
724
725 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
726 Assert(Status == STATUS_SUCCESS);
727 return Status == STATUS_SUCCESS;
728}
729
730/* static */ DECLCALLBACK(int)
731GaDrvEnvKmt::gaEnvFenceWait(void *pvEnv,
732 uint32_t u32FenceHandle,
733 uint32_t u32TimeoutUS)
734{
735 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
736
737 if (!pThis->mKmtCallbacks.hDevice)
738 return 0;
739
740 bool fSuccess = vboxDdiFenceWait(&pThis->mKmtCallbacks, u32FenceHandle, u32TimeoutUS);
741 return fSuccess ? 0 : -1;
742}
743
744static bool
745vboxDdiFenceUnref(GaKmtCallbacks *pKmtCallbacks,
746 uint32_t u32FenceHandle)
747{
748 VBOXDISPIFESCAPE_GAFENCEUNREF fenceUnref;
749 memset(&fenceUnref, 0, sizeof(fenceUnref));
750 fenceUnref.EscapeHdr.escapeCode = VBOXESC_GAFENCEUNREF;
751 // pFenceUnref->EscapeHdr.cmdSpecific = 0;
752 fenceUnref.u32FenceHandle = u32FenceHandle;
753
754 D3DKMT_ESCAPE EscapeData;
755 memset(&EscapeData, 0, sizeof(EscapeData));
756 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
757 EscapeData.hDevice = pKmtCallbacks->hDevice;
758 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
759 // EscapeData.Flags.HardwareAccess = 0;
760 EscapeData.pPrivateDriverData = &fenceUnref;
761 EscapeData.PrivateDriverDataSize = sizeof(fenceUnref);
762 EscapeData.hContext = 0;
763
764 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
765 Assert(Status == STATUS_SUCCESS);
766 return Status == STATUS_SUCCESS;
767}
768
769/* static */ DECLCALLBACK(void)
770GaDrvEnvKmt::gaEnvFenceUnref(void *pvEnv,
771 uint32_t u32FenceHandle)
772{
773 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
774
775 if (!pThis->mKmtCallbacks.hDevice)
776 return;
777
778 vboxDdiFenceUnref(&pThis->mKmtCallbacks, u32FenceHandle);
779}
780
781/** Calculate how many commands will fit in the buffer.
782 *
783 * @param pu8Commands Command buffer.
784 * @param cbCommands Size of command buffer.
785 * @param cbAvail Available buffer size..
786 * @param pu32Length Size of commands which will fit in cbAvail bytes.
787 */
788static bool
789vboxCalcCommandLength(const uint8_t *pu8Commands, uint32_t cbCommands, uint32_t cbAvail, uint32_t *pu32Length)
790{
791 uint32_t u32Length = 0;
792 const uint8_t *pu8Src = pu8Commands;
793 const uint8_t *pu8SrcEnd = pu8Commands + cbCommands;
794
795 while (pu8SrcEnd > pu8Src)
796 {
797 const uint32_t cbSrcLeft = pu8SrcEnd - pu8Src;
798 if (cbSrcLeft < sizeof(uint32_t))
799 {
800 return false;
801 }
802
803 /* Get the command id and command length. */
804 const uint32_t u32CmdId = *(uint32_t *)pu8Src;
805 uint32_t cbCmd = 0;
806
807 if (SVGA_3D_CMD_BASE <= u32CmdId && u32CmdId < SVGA_3D_CMD_MAX)
808 {
809 if (cbSrcLeft < sizeof(SVGA3dCmdHeader))
810 {
811 return false;
812 }
813
814 const SVGA3dCmdHeader *pHeader = (SVGA3dCmdHeader *)pu8Src;
815 cbCmd = sizeof(SVGA3dCmdHeader) + pHeader->size;
816 if (cbCmd % sizeof(uint32_t) != 0)
817 {
818 return false;
819 }
820 if (cbSrcLeft < cbCmd)
821 {
822 return false;
823 }
824 }
825 else
826 {
827 /* It is not expected that any of common SVGA commands will be in the command buffer
828 * because the SVGA gallium driver does not use them.
829 */
830 return false;
831 }
832
833 if (u32Length + cbCmd > cbAvail)
834 {
835 if (u32Length == 0)
836 {
837 /* No commands fit into the buffer. */
838 return false;
839 }
840 break;
841 }
842
843 pu8Src += cbCmd;
844 u32Length += cbCmd;
845 }
846
847 *pu32Length = u32Length;
848 return true;
849}
850
851static bool
852vboxDdiRender(GaKmtCallbacks *pKmtCallbacks,
853 GAWDDMCONTEXTINFO *pContextInfo, uint32_t u32FenceHandle, void *pvCommands, uint32_t cbCommands,
854 ULONGLONG PresentHistoryToken, bool fPresentRedirected)
855{
856 uint32_t cbLeft;
857 const uint8_t *pu8Src;
858
859 cbLeft = cbCommands;
860 pu8Src = (uint8_t *)pvCommands;
861 /* Even when cbCommands is 0, submit the fence. The following code deals with this. */
862 do
863 {
864 /* Actually available space. */
865 const uint32_t cbAvail = pContextInfo->CommandBufferSize;
866 if (cbAvail <= sizeof(u32FenceHandle))
867 {
868 return false;
869 }
870
871 /* How many bytes of command data still to copy. */
872 uint32_t cbCommandChunk = cbLeft;
873
874 /* How many bytes still to copy. */
875 uint32_t cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
876
877 /* Copy the buffer identifier. */
878 if (cbToCopy <= cbAvail)
879 {
880 /* Command buffer is big enough. */
881 *(uint32_t *)pContextInfo->pCommandBuffer = u32FenceHandle;
882 }
883 else
884 {
885 /* Split. Write zero as buffer identifier. */
886 *(uint32_t *)pContextInfo->pCommandBuffer = 0;
887
888 /* Get how much commands data will fit in the buffer. */
889 if (!vboxCalcCommandLength(pu8Src, cbCommandChunk, cbAvail - sizeof(u32FenceHandle), &cbCommandChunk))
890 {
891 return false;
892 }
893
894 cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
895 }
896
897 if (cbCommandChunk)
898 {
899 /* Copy the command data. */
900 memcpy((uint8_t *)pContextInfo->pCommandBuffer + sizeof(u32FenceHandle), pu8Src, cbCommandChunk);
901 }
902
903 /* Advance the command position. */
904 pu8Src += cbCommandChunk;
905 cbLeft -= cbCommandChunk;
906
907 D3DKMT_RENDER RenderData;
908 memset(&RenderData, 0, sizeof(RenderData));
909 RenderData.hContext = pContextInfo->hContext;
910 // RenderData.CommandOffset = 0;
911 RenderData.CommandLength = cbToCopy;
912 // RenderData.AllocationCount = 0;
913 // RenderData.PatchLocationCount = 0;
914 RenderData.PresentHistoryToken = PresentHistoryToken;
915 RenderData.Flags.PresentRedirected = fPresentRedirected;
916
917 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTRender(&RenderData);
918 Assert(Status == STATUS_SUCCESS);
919 if (Status != STATUS_SUCCESS)
920 {
921 return false;
922 }
923
924 pContextInfo->pCommandBuffer = RenderData.pNewCommandBuffer;
925 pContextInfo->CommandBufferSize = RenderData.NewCommandBufferSize;
926 pContextInfo->pAllocationList = RenderData.pNewAllocationList;
927 pContextInfo->AllocationListSize = RenderData.NewAllocationListSize;
928 pContextInfo->pPatchLocationList = RenderData.pNewPatchLocationList;
929 pContextInfo->PatchLocationListSize = RenderData.NewPatchLocationListSize;
930 } while (cbLeft);
931
932 return true;
933}
934
935bool GaDrvEnvKmt::doRender(uint32_t u32Cid, void *pvCommands, uint32_t cbCommands,
936 GAFENCEQUERY *pFenceQuery, ULONGLONG PresentHistoryToken, bool fPresentRedirected)
937{
938 uint32_t u32FenceHandle;
939 GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&mContextTree, u32Cid);
940 if (!pContextInfo)
941 return false;
942
943 bool fSuccess = true;
944 u32FenceHandle = 0;
945 if (pFenceQuery)
946 {
947 fSuccess = vboxDdiFenceCreate(&mKmtCallbacks, pContextInfo, &u32FenceHandle);
948 }
949
950 if (fSuccess)
951 {
952 fSuccess = vboxDdiRender(&mKmtCallbacks, pContextInfo, u32FenceHandle,
953 pvCommands, cbCommands, PresentHistoryToken, fPresentRedirected);
954 if (fSuccess)
955 {
956 if (pFenceQuery)
957 {
958 if (!vboxDdiFenceQuery(&mKmtCallbacks, u32FenceHandle, pFenceQuery))
959 {
960 pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
961 }
962 }
963 }
964 }
965 return fSuccess;
966}
967
968/* static */ DECLCALLBACK(int)
969GaDrvEnvKmt::gaEnvRender(void *pvEnv,
970 uint32_t u32Cid,
971 void *pvCommands,
972 uint32_t cbCommands,
973 GAFENCEQUERY *pFenceQuery)
974{
975 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
976 return pThis->doRender(u32Cid, pvCommands, cbCommands, pFenceQuery, 0, false) ? 1 : 0;
977}
978
979bool GaDrvEnvKmt::drvEnvKmtRenderCompose(uint32_t u32Cid,
980 void *pvCommands,
981 uint32_t cbCommands,
982 ULONGLONG PresentHistoryToken)
983{
984 return doRender(u32Cid, pvCommands, cbCommands, NULL, PresentHistoryToken, true);
985}
986
987
988static bool
989vboxDdiRegionCreate(GaKmtCallbacks *pKmtCallbacks,
990 uint32_t u32RegionSize,
991 uint32_t *pu32GmrId,
992 void **ppvMap)
993{
994 VBOXDISPIFESCAPE_GAREGION data;
995 memset(&data, 0, sizeof(data));
996 data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
997 // data.EscapeHdr.cmdSpecific = 0;
998 data.u32Command = GA_REGION_CMD_CREATE;
999 data.u32NumPages = (u32RegionSize + PAGE_SIZE - 1) / PAGE_SIZE;
1000 // data.u32GmrId = 0;
1001 // data.u64UserAddress = 0;
1002
1003 D3DKMT_ESCAPE EscapeData;
1004 memset(&EscapeData, 0, sizeof(EscapeData));
1005 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
1006 EscapeData.hDevice = pKmtCallbacks->hDevice;
1007 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1008 // EscapeData.Flags.HardwareAccess = 0;
1009 EscapeData.pPrivateDriverData = &data;
1010 EscapeData.PrivateDriverDataSize = sizeof(data);
1011 // EscapeData.hContext = 0;
1012
1013 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
1014 if (Status == STATUS_SUCCESS)
1015 {
1016 *pu32GmrId = data.u32GmrId;
1017 *ppvMap = (void *)(uintptr_t)data.u64UserAddress;
1018 return true;
1019 }
1020
1021 Assert(0);
1022 return false;
1023}
1024
1025/* static */ DECLCALLBACK(int)
1026GaDrvEnvKmt::gaEnvRegionCreate(void *pvEnv,
1027 uint32_t u32RegionSize,
1028 uint32_t *pu32GmrId,
1029 void **ppvMap)
1030{
1031 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
1032
1033 if (pThis->mKmtCallbacks.hDevice)
1034 {
1035 /* That is a real device */
1036 bool fSuccess = vboxDdiRegionCreate(&pThis->mKmtCallbacks, u32RegionSize, pu32GmrId, ppvMap);
1037 return fSuccess ? 0: -1;
1038 }
1039
1040 /* That is a fake device, created when WDDM adapter is initialized. */
1041 *ppvMap = malloc(u32RegionSize);
1042 if (*ppvMap)
1043 {
1044 *pu32GmrId = 0;
1045 return 0;
1046 }
1047
1048 return -1;
1049}
1050
1051static bool
1052vboxDdiRegionDestroy(GaKmtCallbacks *pKmtCallbacks,
1053 uint32_t u32GmrId)
1054{
1055 VBOXDISPIFESCAPE_GAREGION data;
1056 memset(&data, 0, sizeof(data));
1057 data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
1058 // data.EscapeHdr.cmdSpecific = 0;
1059 data.u32Command = GA_REGION_CMD_DESTROY;
1060 // data.u32NumPages = 0;
1061 data.u32GmrId = u32GmrId;
1062 // data.u64UserAddress = 0;
1063
1064 D3DKMT_ESCAPE EscapeData;
1065 memset(&EscapeData, 0, sizeof(EscapeData));
1066 EscapeData.hAdapter = pKmtCallbacks->hAdapter;
1067 EscapeData.hDevice = pKmtCallbacks->hDevice;
1068 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1069 EscapeData.Flags.HardwareAccess = 1; /* Sync with submitted commands. */
1070 EscapeData.pPrivateDriverData = &data;
1071 EscapeData.PrivateDriverDataSize = sizeof(data);
1072 // EscapeData.hContext = 0;
1073
1074 NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
1075 Assert(Status == STATUS_SUCCESS);
1076 return Status == STATUS_SUCCESS;
1077}
1078
1079/* static */ DECLCALLBACK(void)
1080GaDrvEnvKmt::gaEnvRegionDestroy(void *pvEnv,
1081 uint32_t u32GmrId,
1082 void *pvMap)
1083{
1084 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
1085
1086 if (pThis->mKmtCallbacks.hDevice)
1087 {
1088 vboxDdiRegionDestroy(&pThis->mKmtCallbacks, u32GmrId);
1089 }
1090 else
1091 {
1092 free(pvMap);
1093 }
1094}
1095
1096/* static */ DECLCALLBACK(int)
1097GaDrvEnvKmt::gaEnvGBSurfaceDefine(void *pvEnv,
1098 SVGAGBSURFCREATE *pCreateParms)
1099{
1100 GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
1101
1102 VBOXDISPIFESCAPE_SVGAGBSURFACEDEFINE data;
1103 data.EscapeHdr.escapeCode = VBOXESC_SVGAGBSURFACEDEFINE;
1104 data.EscapeHdr.u32CmdSpecific = 0;
1105 data.CreateParms = *pCreateParms;
1106
1107 D3DKMT_ESCAPE EscapeData;
1108 memset(&EscapeData, 0, sizeof(EscapeData));
1109 EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
1110 EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
1111 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1112 EscapeData.Flags.HardwareAccess = 1;
1113 EscapeData.pPrivateDriverData = &data;
1114 EscapeData.PrivateDriverDataSize = sizeof(data);
1115 // EscapeData.hContext = 0;
1116
1117 NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
1118 if (Status == STATUS_SUCCESS)
1119 {
1120 pCreateParms->gmrid = data.CreateParms.gmrid;
1121 pCreateParms->cbGB = data.CreateParms.cbGB;
1122 pCreateParms->u64UserAddress = data.CreateParms.u64UserAddress;
1123 pCreateParms->u32Sid = data.CreateParms.u32Sid;
1124
1125 /* Create a kernel mode allocation for render targets,
1126 * because we will need kernel mode handles for Present.
1127 */
1128 if (pCreateParms->s.flags & SVGA3D_SURFACE_HINT_RENDERTARGET)
1129 {
1130 /* First check if the format is supported. */
1131 D3DDDIFORMAT const ddiFormat = svgaToD3DDDIFormat((SVGA3dSurfaceFormat)pCreateParms->s.format);
1132 if (ddiFormat != D3DDDIFMT_UNKNOWN)
1133 {
1134 GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)malloc(sizeof(GAWDDMSURFACEINFO));
1135 if (pSurfaceInfo)
1136 {
1137 memset(pSurfaceInfo, 0, sizeof(GAWDDMSURFACEINFO));
1138
1139 VBOXWDDM_ALLOCINFO wddmAllocInfo;
1140 memset(&wddmAllocInfo, 0, sizeof(wddmAllocInfo));
1141
1142 wddmAllocInfo.enmType = VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC;
1143 wddmAllocInfo.fFlags.RenderTarget = 1;
1144 wddmAllocInfo.hSharedHandle = 0;
1145 wddmAllocInfo.hostID = pCreateParms->u32Sid;
1146 wddmAllocInfo.SurfDesc.slicePitch = 0;
1147 wddmAllocInfo.SurfDesc.depth = pCreateParms->s.size.depth;
1148 wddmAllocInfo.SurfDesc.width = pCreateParms->s.size.width;
1149 wddmAllocInfo.SurfDesc.height = pCreateParms->s.size.height;
1150 wddmAllocInfo.SurfDesc.format = ddiFormat;
1151 wddmAllocInfo.SurfDesc.VidPnSourceId = 0;
1152 wddmAllocInfo.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(wddmAllocInfo.SurfDesc.format);
1153 wddmAllocInfo.SurfDesc.pitch = vboxWddmCalcPitch(wddmAllocInfo.SurfDesc.width,
1154 wddmAllocInfo.SurfDesc.format);
1155 wddmAllocInfo.SurfDesc.cbSize = vboxWddmCalcSize(wddmAllocInfo.SurfDesc.pitch,
1156 wddmAllocInfo.SurfDesc.height,
1157 wddmAllocInfo.SurfDesc.format);
1158 wddmAllocInfo.SurfDesc.d3dWidth = vboxWddmCalcWidthForPitch(wddmAllocInfo.SurfDesc.pitch,
1159 wddmAllocInfo.SurfDesc.format);
1160
1161 D3DDDI_ALLOCATIONINFO AllocationInfo;
1162 memset(&AllocationInfo, 0, sizeof(AllocationInfo));
1163 // AllocationInfo.hAllocation = NULL;
1164 // AllocationInfo.pSystemMem = NULL;
1165 AllocationInfo.pPrivateDriverData = &wddmAllocInfo;
1166 AllocationInfo.PrivateDriverDataSize = sizeof(wddmAllocInfo);
1167
1168 D3DKMT_CREATEALLOCATION CreateAllocation;
1169 memset(&CreateAllocation, 0, sizeof(CreateAllocation));
1170 CreateAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
1171 CreateAllocation.NumAllocations = 1;
1172 CreateAllocation.pAllocationInfo = &AllocationInfo;
1173
1174 Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTCreateAllocation(&CreateAllocation);
1175 if (Status == STATUS_SUCCESS)
1176 {
1177 pSurfaceInfo->Core.Key = pCreateParms->u32Sid;
1178 pSurfaceInfo->hAllocation = AllocationInfo.hAllocation;
1179 if (!RTAvlU32Insert(&pThis->mSurfaceTree, &pSurfaceInfo->Core))
1180 {
1181 Status = STATUS_NOT_SUPPORTED;
1182 }
1183 }
1184
1185 if (Status != STATUS_SUCCESS)
1186 {
1187 free(pSurfaceInfo);
1188 }
1189 }
1190 else
1191 {
1192 Status = STATUS_NOT_SUPPORTED;
1193 }
1194 }
1195 else
1196 {
1197 /* Unsupported render target format. */
1198 Assert(0);
1199 Status = STATUS_NOT_SUPPORTED;
1200 }
1201 }
1202
1203 if (Status != STATUS_SUCCESS)
1204 {
1205 gaEnvSurfaceDestroy(pvEnv, pCreateParms->u32Sid);
1206 }
1207 }
1208
1209 if (Status == STATUS_SUCCESS)
1210 return 0;
1211
1212 Assert(0);
1213 return -1;
1214}
1215
1216GaDrvEnvKmt::GaDrvEnvKmt()
1217 :
1218 mContextTree(0),
1219 mSurfaceTree(0)
1220{
1221 RT_ZERO(mKmtCallbacks);
1222 RT_ZERO(mHWInfo);
1223 RT_ZERO(mEnv);
1224}
1225
1226GaDrvEnvKmt::~GaDrvEnvKmt()
1227{
1228}
1229
1230HRESULT GaDrvEnvKmt::Init(void)
1231{
1232 mKmtCallbacks.d3dkmt = D3DKMTFunctions();
1233
1234 /* Figure out which adapter to use. */
1235 NTSTATUS Status = vboxDispKmtOpenAdapter2(&mKmtCallbacks.hAdapter, &mKmtCallbacks.AdapterLuid);
1236 Assert(Status == STATUS_SUCCESS);
1237 if (Status == STATUS_SUCCESS)
1238 {
1239 VBOXWDDM_QAI adapterInfo;
1240 bool fSuccess = vboxDdiQueryAdapterInfo(&mKmtCallbacks, mKmtCallbacks.hAdapter, &adapterInfo, sizeof(adapterInfo));
1241 Assert(fSuccess);
1242 if (fSuccess)
1243 {
1244 fSuccess = vboxDdiDeviceCreate(&mKmtCallbacks, &mKmtCallbacks.hDevice);
1245 Assert(fSuccess);
1246 if (fSuccess)
1247 {
1248 mHWInfo = adapterInfo.u.vmsvga.HWInfo;
1249
1250 /*
1251 * Success.
1252 */
1253 return S_OK;
1254 }
1255
1256 vboxDdiDeviceDestroy(&mKmtCallbacks, mKmtCallbacks.hDevice);
1257 }
1258
1259 vboxDispKmtCloseAdapter(mKmtCallbacks.hAdapter);
1260 }
1261
1262 return E_FAIL;
1263}
1264
1265const WDDMGalliumDriverEnv *GaDrvEnvKmt::Env()
1266{
1267 if (mEnv.cb == 0)
1268 {
1269 mEnv.cb = sizeof(WDDMGalliumDriverEnv);
1270 mEnv.pHWInfo = &mHWInfo;
1271 mEnv.pvEnv = this;
1272 mEnv.pfnContextCreate = gaEnvContextCreate;
1273 mEnv.pfnContextDestroy = gaEnvContextDestroy;
1274 mEnv.pfnSurfaceDefine = gaEnvSurfaceDefine;
1275 mEnv.pfnSurfaceDestroy = gaEnvSurfaceDestroy;
1276 mEnv.pfnRender = gaEnvRender;
1277 mEnv.pfnFenceUnref = gaEnvFenceUnref;
1278 mEnv.pfnFenceQuery = gaEnvFenceQuery;
1279 mEnv.pfnFenceWait = gaEnvFenceWait;
1280 mEnv.pfnRegionCreate = gaEnvRegionCreate;
1281 mEnv.pfnRegionDestroy = gaEnvRegionDestroy;
1282 /* VGPU10 */
1283 mEnv.pfnGBSurfaceDefine = gaEnvGBSurfaceDefine;
1284 }
1285
1286 return &mEnv;
1287}
1288
1289RT_C_DECLS_BEGIN
1290
1291const WDDMGalliumDriverEnv *GaDrvEnvKmtCreate(void)
1292{
1293 GaDrvEnvKmt *p = new GaDrvEnvKmt();
1294 if (p)
1295 {
1296 HRESULT hr = p->Init();
1297 if (hr != S_OK)
1298 {
1299 delete p;
1300 p = NULL;
1301 }
1302 }
1303 return p ? p->Env() : NULL;
1304}
1305
1306void GaDrvEnvKmtDelete(const WDDMGalliumDriverEnv *pEnv)
1307{
1308 if (pEnv)
1309 {
1310 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1311 delete p;
1312 }
1313}
1314
1315D3DKMT_HANDLE GaDrvEnvKmtContextHandle(const WDDMGalliumDriverEnv *pEnv, uint32_t u32Cid)
1316{
1317 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1318 return p->drvEnvKmtContextHandle(u32Cid);
1319}
1320
1321D3DKMT_HANDLE GaDrvEnvKmtSurfaceHandle(const WDDMGalliumDriverEnv *pEnv, uint32_t u32Sid)
1322{
1323 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1324 return p->drvEnvKmtSurfaceHandle(u32Sid);
1325}
1326
1327void GaDrvEnvKmtAdapterLUID(const WDDMGalliumDriverEnv *pEnv, LUID *pAdapterLuid)
1328{
1329 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1330 *pAdapterLuid = p->mKmtCallbacks.AdapterLuid;
1331}
1332
1333D3DKMT_HANDLE GaDrvEnvKmtAdapterHandle(const WDDMGalliumDriverEnv *pEnv)
1334{
1335 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1336 return p->mKmtCallbacks.hAdapter;
1337}
1338
1339D3DKMT_HANDLE GaDrvEnvKmtDeviceHandle(const WDDMGalliumDriverEnv *pEnv)
1340{
1341 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1342 return p->mKmtCallbacks.hDevice;
1343}
1344
1345void GaDrvEnvKmtRenderCompose(const WDDMGalliumDriverEnv *pEnv,
1346 uint32_t u32Cid,
1347 void *pvCommands,
1348 uint32_t cbCommands,
1349 ULONGLONG PresentHistoryToken)
1350{
1351 GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
1352 p->drvEnvKmtRenderCompose(u32Cid, pvCommands, cbCommands, PresentHistoryToken);
1353}
1354
1355RT_C_DECLS_END
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use