summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/3D/win/VBoxGL
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/3D/win/VBoxGL')
-rw-r--r--src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp1396
-rw-r--r--src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.h58
-rw-r--r--src/VBox/Additions/3D/win/VBoxGL/Makefile.kmk87
-rw-r--r--src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c580
-rw-r--r--src/VBox/Additions/3D/win/VBoxGL/VBoxGL.rc66
5 files changed, 2187 insertions, 0 deletions
diff --git a/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp b/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp
new file mode 100644
index 00000000..39da970c
--- /dev/null
+++ b/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp
@@ -0,0 +1,1396 @@
+/* $Id: GaDrvEnvKMT.cpp $ */
+/** @file
+ * VirtualBox Windows Guest Mesa3D - Gallium driver interface to the WDDM miniport driver using Kernel Mode Thunks.
+ */
+
+/*
+ * Copyright (C) 2016-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "GaDrvEnvKMT.h"
+
+#include <UmHlpInternal.h>
+
+#include "svga3d_reg.h"
+
+#include <common/wddm/VBoxMPIf.h>
+
+#include <iprt/assertcompile.h>
+#include <iprt/param.h> /* For PAGE_SIZE */
+
+AssertCompile(sizeof(HANDLE) >= sizeof(D3DKMT_HANDLE));
+
+
+/*
+ * AVL configuration.
+ */
+#define KAVL_FN(a) RTAvlU32##a
+#define KAVL_MAX_STACK 27 /* Up to 2^24 nodes. */
+#define KAVL_CHECK_FOR_EQUAL_INSERT 1 /* No duplicate keys! */
+#define KAVLNODECORE AVLU32NODECORE
+#define PKAVLNODECORE PAVLU32NODECORE
+#define PPKAVLNODECORE PPAVLU32NODECORE
+#define KAVLKEY AVLU32KEY
+#define PKAVLKEY PAVLU32KEY
+#define KAVLENUMDATA AVLU32ENUMDATA
+#define PKAVLENUMDATA PAVLU32ENUMDATA
+#define PKAVLCALLBACK PAVLU32CALLBACK
+
+
+/*
+ * AVL Compare macros
+ */
+#define KAVL_G(key1, key2) ( (key1) > (key2) )
+#define KAVL_E(key1, key2) ( (key1) == (key2) )
+#define KAVL_NE(key1, key2) ( (key1) != (key2) )
+
+
+#include <iprt/avl.h>
+
+/*
+ * Include the code.
+ */
+#define SSToDS(ptr) ptr
+#define KMAX RT_MAX
+#define kASSERT(_e) do { } while (0)
+#include "avl_Base.cpp.h"
+#include "avl_Get.cpp.h"
+//#include "avl_GetBestFit.cpp.h"
+//#include "avl_RemoveBestFit.cpp.h"
+//#include "avl_DoWithAll.cpp.h"
+#include "avl_Destroy.cpp.h"
+
+
+typedef struct GaKmtCallbacks
+{
+ D3DKMT_HANDLE hAdapter;
+ D3DKMT_HANDLE hDevice;
+ D3DKMTFUNCTIONS const *d3dkmt;
+ LUID AdapterLuid;
+} GaKmtCallbacks;
+
+class GaDrvEnvKmt
+{
+ public:
+ GaDrvEnvKmt();
+ ~GaDrvEnvKmt();
+
+ HRESULT Init(void);
+
+ const WDDMGalliumDriverEnv *Env();
+
+ /*
+ * KMT specific helpers.
+ */
+ bool drvEnvKmtRenderCompose(uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ ULONGLONG PresentHistoryToken);
+ D3DKMT_HANDLE drvEnvKmtContextHandle(uint32_t u32Cid);
+ D3DKMT_HANDLE drvEnvKmtSurfaceHandle(uint32_t u32Sid);
+
+ GaKmtCallbacks mKmtCallbacks;
+
+ private:
+
+ VBOXGAHWINFO mHWInfo;
+
+ /* Map to convert context id (cid) to WDDM context information (GAWDDMCONTEXTINFO).
+ * Key is the 32 bit context id.
+ */
+ AVLU32TREE mContextTree;
+
+ /* Map to convert surface id (sid) to WDDM surface information (GAWDDMSURFACEINFO).
+ * Key is the 32 bit surface id.
+ */
+ AVLU32TREE mSurfaceTree;
+
+ WDDMGalliumDriverEnv mEnv;
+
+ static DECLCALLBACK(uint32_t) gaEnvContextCreate(void *pvEnv,
+ boolean extended,
+ boolean vgpu10);
+ static DECLCALLBACK(void) gaEnvContextDestroy(void *pvEnv,
+ uint32_t u32Cid);
+ static DECLCALLBACK(int) gaEnvSurfaceDefine(void *pvEnv,
+ GASURFCREATE *pCreateParms,
+ GASURFSIZE *paSizes,
+ uint32_t cSizes,
+ uint32_t *pu32Sid);
+ static DECLCALLBACK(void) gaEnvSurfaceDestroy(void *pvEnv,
+ uint32_t u32Sid);
+ static DECLCALLBACK(int) gaEnvRender(void *pvEnv,
+ uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ GAFENCEQUERY *pFenceQuery);
+ static DECLCALLBACK(void) gaEnvFenceUnref(void *pvEnv,
+ uint32_t u32FenceHandle);
+ static DECLCALLBACK(int) gaEnvFenceQuery(void *pvEnv,
+ uint32_t u32FenceHandle,
+ GAFENCEQUERY *pFenceQuery);
+ static DECLCALLBACK(int) gaEnvFenceWait(void *pvEnv,
+ uint32_t u32FenceHandle,
+ uint32_t u32TimeoutUS);
+ static DECLCALLBACK(int) gaEnvRegionCreate(void *pvEnv,
+ uint32_t u32RegionSize,
+ uint32_t *pu32GmrId,
+ void **ppvMap);
+ static DECLCALLBACK(void) gaEnvRegionDestroy(void *pvEnv,
+ uint32_t u32GmrId,
+ void *pvMap);
+
+ /* VGPU10 */
+ static DECLCALLBACK(int) gaEnvGBSurfaceDefine(void *pvEnv,
+ SVGAGBSURFCREATE *pCreateParms);
+
+ /*
+ * Internal.
+ */
+ bool doRender(uint32_t u32Cid, void *pvCommands, uint32_t cbCommands,
+ GAFENCEQUERY *pFenceQuery, ULONGLONG PresentHistoryToken, bool fPresentRedirected);
+};
+
+typedef struct GAWDDMCONTEXTINFO
+{
+ AVLU32NODECORE Core;
+ D3DKMT_HANDLE hContext;
+ VOID *pCommandBuffer;
+ UINT CommandBufferSize;
+ D3DDDI_ALLOCATIONLIST *pAllocationList;
+ UINT AllocationListSize;
+ D3DDDI_PATCHLOCATIONLIST *pPatchLocationList;
+ UINT PatchLocationListSize;
+} GAWDDMCONTEXTINFO;
+
+typedef struct GAWDDMSURFACEINFO
+{
+ AVLU32NODECORE Core;
+ D3DKMT_HANDLE hAllocation;
+} GAWDDMSURFACEINFO;
+
+
+/// @todo vboxDdi helpers must return a boof success indicator
+static bool
+vboxDdiQueryAdapterInfo(GaKmtCallbacks *pKmtCallbacks,
+ D3DKMT_HANDLE hAdapter,
+ VBOXWDDM_QAI *pAdapterInfo,
+ uint32_t cbAdapterInfo)
+{
+ D3DKMT_QUERYADAPTERINFO QAI;
+ memset(&QAI, 0, sizeof(QAI));
+ QAI.hAdapter = hAdapter;
+ QAI.Type = KMTQAITYPE_UMDRIVERPRIVATE;
+ QAI.pPrivateDriverData = pAdapterInfo;
+ QAI.PrivateDriverDataSize = cbAdapterInfo;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTQueryAdapterInfo(&QAI);
+ return Status == STATUS_SUCCESS;
+}
+
+static void
+vboxDdiDeviceDestroy(GaKmtCallbacks *pKmtCallbacks,
+ D3DKMT_HANDLE hDevice)
+{
+ if (hDevice)
+ {
+ D3DKMT_DESTROYDEVICE DestroyDeviceData;
+ memset(&DestroyDeviceData, 0, sizeof(DestroyDeviceData));
+ DestroyDeviceData.hDevice = hDevice;
+ pKmtCallbacks->d3dkmt->pfnD3DKMTDestroyDevice(&DestroyDeviceData);
+ }
+}
+
+static bool
+vboxDdiDeviceCreate(GaKmtCallbacks *pKmtCallbacks,
+ D3DKMT_HANDLE *phDevice)
+{
+ D3DKMT_CREATEDEVICE CreateDeviceData;
+ memset(&CreateDeviceData, 0, sizeof(CreateDeviceData));
+ CreateDeviceData.hAdapter = pKmtCallbacks->hAdapter;
+ // CreateDeviceData.Flags = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTCreateDevice(&CreateDeviceData);
+ if (Status == STATUS_SUCCESS)
+ {
+ *phDevice = CreateDeviceData.hDevice;
+ return true;
+ }
+ return false;
+}
+
+static bool
+vboxDdiContextGetId(GaKmtCallbacks *pKmtCallbacks,
+ D3DKMT_HANDLE hContext,
+ uint32_t *pu32Cid)
+{
+ VBOXDISPIFESCAPE_GAGETCID data;
+ memset(&data, 0, sizeof(data));
+ data.EscapeHdr.escapeCode = VBOXESC_GAGETCID;
+ // data.EscapeHdr.cmdSpecific = 0;
+ // data.u32Cid = 0;
+
+ /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
+ * have also set hDevice to a non-NULL value...
+ */
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ EscapeData.hContext = hContext;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ *pu32Cid = data.u32Cid;
+ return true;
+ }
+ return false;
+}
+
+static void
+vboxDdiContextDestroy(GaKmtCallbacks *pKmtCallbacks,
+ GAWDDMCONTEXTINFO *pContextInfo)
+{
+ if (pContextInfo->hContext)
+ {
+ D3DKMT_DESTROYCONTEXT DestroyContextData;
+ memset(&DestroyContextData, 0, sizeof(DestroyContextData));
+ DestroyContextData.hContext = pContextInfo->hContext;
+ pKmtCallbacks->d3dkmt->pfnD3DKMTDestroyContext(&DestroyContextData);
+ }
+}
+
+static bool
+vboxDdiContextCreate(GaKmtCallbacks *pKmtCallbacks,
+ void *pvPrivateData, uint32_t cbPrivateData,
+ GAWDDMCONTEXTINFO *pContextInfo)
+{
+ D3DKMT_CREATECONTEXT CreateContextData;
+ memset(&CreateContextData, 0, sizeof(CreateContextData));
+ CreateContextData.hDevice = pKmtCallbacks->hDevice;
+ // CreateContextData.NodeOrdinal = 0;
+ // CreateContextData.EngineAffinity = 0;
+ // CreateContextData.Flags.Value = 0;
+ CreateContextData.pPrivateDriverData = pvPrivateData;
+ CreateContextData.PrivateDriverDataSize = cbPrivateData;
+ CreateContextData.ClientHint = D3DKMT_CLIENTHINT_OPENGL;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTCreateContext(&CreateContextData);
+ if (Status == STATUS_SUCCESS)
+ {
+ /* Query cid. */
+ uint32_t u32Cid = 0;
+ bool fSuccess = vboxDdiContextGetId(pKmtCallbacks, CreateContextData.hContext, &u32Cid);
+ if (fSuccess)
+ {
+ pContextInfo->Core.Key = u32Cid;
+ pContextInfo->hContext = CreateContextData.hContext;
+ pContextInfo->pCommandBuffer = CreateContextData.pCommandBuffer;
+ pContextInfo->CommandBufferSize = CreateContextData.CommandBufferSize;
+ pContextInfo->pAllocationList = CreateContextData.pAllocationList;
+ pContextInfo->AllocationListSize = CreateContextData.AllocationListSize;
+ pContextInfo->pPatchLocationList = CreateContextData.pPatchLocationList;
+ pContextInfo->PatchLocationListSize = CreateContextData.PatchLocationListSize;
+
+ return true;
+ }
+
+ vboxDdiContextDestroy(pKmtCallbacks, pContextInfo);
+ }
+
+ return false;
+}
+
+/* static */ DECLCALLBACK(void)
+GaDrvEnvKmt::gaEnvContextDestroy(void *pvEnv,
+ uint32_t u32Cid)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Remove(&pThis->mContextTree, u32Cid);
+ if (pContextInfo)
+ {
+ vboxDdiContextDestroy(&pThis->mKmtCallbacks, pContextInfo);
+ memset(pContextInfo, 0, sizeof(*pContextInfo));
+ free(pContextInfo);
+ }
+}
+
+D3DKMT_HANDLE GaDrvEnvKmt::drvEnvKmtContextHandle(uint32_t u32Cid)
+{
+ GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&mContextTree, u32Cid);
+ Assert(pContextInfo);
+ return pContextInfo ? pContextInfo->hContext : 0;
+}
+
+/* static */ DECLCALLBACK(uint32_t)
+GaDrvEnvKmt::gaEnvContextCreate(void *pvEnv,
+ boolean extended,
+ boolean vgpu10)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ GAWDDMCONTEXTINFO *pContextInfo;
+ pContextInfo = (GAWDDMCONTEXTINFO *)malloc(sizeof(GAWDDMCONTEXTINFO));
+ if (!pContextInfo)
+ return (uint32_t)-1;
+
+ VBOXWDDM_CREATECONTEXT_INFO privateData;
+ memset(&privateData, 0, sizeof(privateData));
+ privateData.u32IfVersion = 9;
+ privateData.enmType = VBOXWDDM_CONTEXT_TYPE_GA_3D;
+ privateData.u.vmsvga.u32Flags = extended? VBOXWDDM_F_GA_CONTEXT_EXTENDED: 0;
+ privateData.u.vmsvga.u32Flags |= vgpu10? VBOXWDDM_F_GA_CONTEXT_VGPU10: 0;
+
+ bool fSuccess = vboxDdiContextCreate(&pThis->mKmtCallbacks,
+ &privateData, sizeof(privateData), pContextInfo);
+ if (fSuccess)
+ {
+ if (RTAvlU32Insert(&pThis->mContextTree, &pContextInfo->Core))
+ {
+ return pContextInfo->Core.Key;
+ }
+
+ vboxDdiContextDestroy(&pThis->mKmtCallbacks,
+ pContextInfo);
+ }
+
+ Assert(0);
+ free(pContextInfo);
+ return (uint32_t)-1;
+}
+
+static D3DDDIFORMAT svgaToD3DDDIFormat(SVGA3dSurfaceFormat format)
+{
+ /* The returning D3DDDIFMT_ value is used only to compute bpp, pitch, etc,
+ * so there is not need for an exact match.
+ */
+ switch (format)
+ {
+ case SVGA3D_X8R8G8B8: return D3DDDIFMT_X8R8G8B8;
+ case SVGA3D_A8R8G8B8: return D3DDDIFMT_A8R8G8B8;
+ case SVGA3D_ALPHA8: return D3DDDIFMT_A8;
+ case SVGA3D_A4R4G4B4: return D3DDDIFMT_A4R4G4B4;
+ case SVGA3D_LUMINANCE8: return D3DDDIFMT_L8;
+ case SVGA3D_A1R5G5B5: return D3DDDIFMT_A1R5G5B5;
+ case SVGA3D_LUMINANCE8_ALPHA8: return D3DDDIFMT_A8L8;
+ case SVGA3D_R5G6B5: return D3DDDIFMT_R5G6B5;
+ case SVGA3D_ARGB_S10E5: return D3DDDIFMT_A16B16G16R16F;
+ case SVGA3D_ARGB_S23E8: return D3DDDIFMT_A32B32G32R32F;
+ case SVGA3D_A8_UNORM: return D3DDDIFMT_A8;
+ case SVGA3D_B5G5R5A1_UNORM: return D3DDDIFMT_A1R5G5B5;
+
+ case SVGA3D_B8G8R8X8_TYPELESS:
+ case SVGA3D_B8G8R8X8_UNORM: return D3DDDIFMT_X8R8G8B8;
+ case SVGA3D_R16_FLOAT: return D3DDDIFMT_R16F;
+ case SVGA3D_R16G16_FLOAT: return D3DDDIFMT_G16R16F;
+ case SVGA3D_R16G16B16A16_FLOAT: return D3DDDIFMT_A16B16G16R16F;
+ case SVGA3D_R32_FLOAT: return D3DDDIFMT_R32F;
+ case SVGA3D_R32G32_FLOAT: return D3DDDIFMT_G32R32F;
+ case SVGA3D_R32G32B32A32_FLOAT: return D3DDDIFMT_A32B32G32R32F;
+ case SVGA3D_R8_TYPELESS:
+ case SVGA3D_R8_SINT:
+ case SVGA3D_R8_UINT:
+ case SVGA3D_R8_SNORM:
+ case SVGA3D_R8_UNORM: return D3DDDIFMT_L8;
+ case SVGA3D_R8G8_TYPELESS:
+ case SVGA3D_R8G8_SINT:
+ case SVGA3D_R8G8_UINT:
+ case SVGA3D_R8G8_SNORM:
+ case SVGA3D_R8G8_UNORM: return D3DDDIFMT_A8L8;
+ case SVGA3D_R8G8B8A8_TYPELESS:
+ case SVGA3D_R8G8B8A8_SINT:
+ case SVGA3D_R8G8B8A8_UINT:
+ case SVGA3D_R8G8B8A8_SNORM:
+ case SVGA3D_R8G8B8A8_UNORM: return D3DDDIFMT_A8R8G8B8;
+ case SVGA3D_R16_TYPELESS:
+ case SVGA3D_R16_SINT:
+ case SVGA3D_R16_UINT:
+ case SVGA3D_R16_SNORM:
+ case SVGA3D_R16_UNORM: return D3DDDIFMT_L16;
+ case SVGA3D_R16G16_TYPELESS:
+ case SVGA3D_R16G16_SINT:
+ case SVGA3D_R16G16_UINT:
+ case SVGA3D_R16G16_SNORM:
+ case SVGA3D_R16G16_UNORM: return D3DDDIFMT_G16R16;
+ case SVGA3D_R16G16B16A16_TYPELESS:
+ case SVGA3D_R16G16B16A16_SINT:
+ case SVGA3D_R16G16B16A16_UINT:
+ case SVGA3D_R16G16B16A16_SNORM:
+ case SVGA3D_R16G16B16A16_UNORM: return D3DDDIFMT_A16B16G16R16;
+ case SVGA3D_R32_TYPELESS:
+ case SVGA3D_R32_SINT:
+ case SVGA3D_R32_UINT: return D3DDDIFMT_R32F; /* Same size in bytes. */
+ case SVGA3D_R32G32_TYPELESS:
+ case SVGA3D_R32G32_SINT:
+ case SVGA3D_R32G32_UINT: return D3DDDIFMT_G32R32F; /* Same size in bytes. */
+ case SVGA3D_R32G32B32A32_TYPELESS:
+ case SVGA3D_R32G32B32A32_SINT:
+ case SVGA3D_R32G32B32A32_UINT: return D3DDDIFMT_A32B32G32R32F; /* Same size in bytes. */
+ case SVGA3D_R10G10B10A2_TYPELESS:
+ case SVGA3D_R10G10B10A2_UINT:
+ case SVGA3D_R10G10B10A2_UNORM: return D3DDDIFMT_A2B10G10R10;
+ case SVGA3D_B5G6R5_UNORM: return D3DDDIFMT_R5G6B5;
+ case SVGA3D_R11G11B10_FLOAT: return D3DDDIFMT_R32F;
+ case SVGA3D_B8G8R8A8_UNORM: return D3DDDIFMT_A8R8G8B8;
+ default: break;
+ }
+
+ VBoxDispMpLoggerLogF("WDDM: EnvKMT: unsupported surface format %d\n", format);
+ Assert(0);
+ return D3DDDIFMT_UNKNOWN;
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvSurfaceDefine(void *pvEnv,
+ GASURFCREATE *pCreateParms,
+ GASURFSIZE *paSizes,
+ uint32_t cSizes,
+ uint32_t *pu32Sid)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ D3DKMT_ESCAPE EscapeData;
+ VBOXDISPIFESCAPE_GASURFACEDEFINE *pData;
+ uint32_t cbAlloc;
+ uint8_t *pu8Req;
+ uint32_t cbReq;
+
+ /* Size of the SVGA request data */
+ cbReq = sizeof(GASURFCREATE) + cSizes * sizeof(GASURFSIZE);
+ /* How much to allocate for WDDM escape data. */
+ cbAlloc = sizeof(VBOXDISPIFESCAPE_GASURFACEDEFINE)
+ + cbReq;
+
+ pData = (VBOXDISPIFESCAPE_GASURFACEDEFINE *)malloc(cbAlloc);
+ if (!pData)
+ return -1;
+
+ pData->EscapeHdr.escapeCode = VBOXESC_GASURFACEDEFINE;
+ // pData->EscapeHdr.cmdSpecific = 0;
+ // pData->u32Sid = 0;
+ pData->cbReq = cbReq;
+ pData->cSizes = cSizes;
+
+ pu8Req = (uint8_t *)&pData[1];
+ memcpy(pu8Req, pCreateParms, sizeof(GASURFCREATE));
+ memcpy(&pu8Req[sizeof(GASURFCREATE)], paSizes, cSizes * sizeof(GASURFSIZE));
+
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
+ EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = pData;
+ EscapeData.PrivateDriverDataSize = cbAlloc;
+ // EscapeData.hContext = 0;
+
+ NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ /* Create a kernel mode allocation for render targets,
+ * because we will need kernel mode handles for Present.
+ */
+ if (pCreateParms->flags & SVGA3D_SURFACE_HINT_RENDERTARGET)
+ {
+ /* First check if the format is supported. */
+ D3DDDIFORMAT const ddiFormat = svgaToD3DDDIFormat((SVGA3dSurfaceFormat)pCreateParms->format);
+ if (ddiFormat != D3DDDIFMT_UNKNOWN)
+ {
+ GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)malloc(sizeof(GAWDDMSURFACEINFO));
+ if (pSurfaceInfo)
+ {
+ memset(pSurfaceInfo, 0, sizeof(GAWDDMSURFACEINFO));
+
+ VBOXWDDM_ALLOCINFO wddmAllocInfo;
+ memset(&wddmAllocInfo, 0, sizeof(wddmAllocInfo));
+
+ wddmAllocInfo.enmType = VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC;
+ wddmAllocInfo.fFlags.RenderTarget = 1;
+ wddmAllocInfo.hSharedHandle = 0;
+ wddmAllocInfo.hostID = pData->u32Sid;
+ wddmAllocInfo.SurfDesc.slicePitch = 0;
+ wddmAllocInfo.SurfDesc.depth = paSizes[0].cDepth;
+ wddmAllocInfo.SurfDesc.width = paSizes[0].cWidth;
+ wddmAllocInfo.SurfDesc.height = paSizes[0].cHeight;
+ wddmAllocInfo.SurfDesc.format = ddiFormat;
+ wddmAllocInfo.SurfDesc.VidPnSourceId = 0;
+ wddmAllocInfo.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.pitch = vboxWddmCalcPitch(wddmAllocInfo.SurfDesc.width,
+ wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.cbSize = vboxWddmCalcSize(wddmAllocInfo.SurfDesc.pitch,
+ wddmAllocInfo.SurfDesc.height,
+ wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.d3dWidth = vboxWddmCalcWidthForPitch(wddmAllocInfo.SurfDesc.pitch,
+ wddmAllocInfo.SurfDesc.format);
+
+ D3DDDI_ALLOCATIONINFO AllocationInfo;
+ memset(&AllocationInfo, 0, sizeof(AllocationInfo));
+ // AllocationInfo.hAllocation = NULL;
+ // AllocationInfo.pSystemMem = NULL;
+ AllocationInfo.pPrivateDriverData = &wddmAllocInfo;
+ AllocationInfo.PrivateDriverDataSize = sizeof(wddmAllocInfo);
+
+ D3DKMT_CREATEALLOCATION CreateAllocation;
+ memset(&CreateAllocation, 0, sizeof(CreateAllocation));
+ CreateAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
+ CreateAllocation.NumAllocations = 1;
+ CreateAllocation.pAllocationInfo = &AllocationInfo;
+
+ Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTCreateAllocation(&CreateAllocation);
+ if (Status == STATUS_SUCCESS)
+ {
+ pSurfaceInfo->Core.Key = pData->u32Sid;
+ pSurfaceInfo->hAllocation = AllocationInfo.hAllocation;
+ if (!RTAvlU32Insert(&pThis->mSurfaceTree, &pSurfaceInfo->Core))
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ free(pSurfaceInfo);
+ }
+ }
+ else
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+ else
+ {
+ /* Unsupported render target format. */
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ gaEnvSurfaceDestroy(pvEnv, pData->u32Sid);
+ }
+ }
+
+ if (Status == STATUS_SUCCESS)
+ {
+ *pu32Sid = pData->u32Sid;
+ free(pData);
+ return 0;
+ }
+
+ Assert(0);
+ free(pData);
+ return -1;
+}
+
+/* static */ DECLCALLBACK(void)
+GaDrvEnvKmt::gaEnvSurfaceDestroy(void *pvEnv,
+ uint32_t u32Sid)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ VBOXDISPIFESCAPE_GASURFACEDESTROY data;
+ memset(&data, 0, sizeof(data));
+ data.EscapeHdr.escapeCode = VBOXESC_GASURFACEDESTROY;
+ // data.EscapeHdr.cmdSpecific = 0;
+ data.u32Sid = u32Sid;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
+ EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ // EscapeData.hContext = 0;
+
+ NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ Assert(Status == STATUS_SUCCESS);
+
+ /* Try to remove from sid -> hAllocation map. */
+ GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)RTAvlU32Remove(&pThis->mSurfaceTree, u32Sid);
+ if (pSurfaceInfo)
+ {
+ D3DKMT_DESTROYALLOCATION DestroyAllocation;
+ memset(&DestroyAllocation, 0, sizeof(DestroyAllocation));
+ DestroyAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
+ // DestroyAllocation.hResource = 0;
+ DestroyAllocation.phAllocationList = &pSurfaceInfo->hAllocation;
+ DestroyAllocation.AllocationCount = 1;
+
+ Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTDestroyAllocation(&DestroyAllocation);
+ Assert(Status == STATUS_SUCCESS);
+
+ free(pSurfaceInfo);
+ }
+}
+
+D3DKMT_HANDLE GaDrvEnvKmt::drvEnvKmtSurfaceHandle(uint32_t u32Sid)
+{
+ GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)RTAvlU32Get(&mSurfaceTree, u32Sid);
+ return pSurfaceInfo ? pSurfaceInfo->hAllocation : 0;
+}
+
+static bool
+vboxDdiFenceCreate(GaKmtCallbacks *pKmtCallbacks,
+ GAWDDMCONTEXTINFO *pContextInfo,
+ uint32_t *pu32FenceHandle)
+{
+ VBOXDISPIFESCAPE_GAFENCECREATE fenceCreate;
+ memset(&fenceCreate, 0, sizeof(fenceCreate));
+ fenceCreate.EscapeHdr.escapeCode = VBOXESC_GAFENCECREATE;
+ // fenceCreate.EscapeHdr.cmdSpecific = 0;
+
+ /* If the user-mode display driver sets hContext to a non-NULL value, the driver must
+ * have also set hDevice to a non-NULL value...
+ */
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &fenceCreate;
+ EscapeData.PrivateDriverDataSize = sizeof(fenceCreate);
+ EscapeData.hContext = pContextInfo->hContext;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ *pu32FenceHandle = fenceCreate.u32FenceHandle;
+ return true;
+ }
+
+ Assert(0);
+ return false;
+}
+
+static bool
+vboxDdiFenceQuery(GaKmtCallbacks *pKmtCallbacks,
+ uint32_t u32FenceHandle,
+ GAFENCEQUERY *pFenceQuery)
+{
+ VBOXDISPIFESCAPE_GAFENCEQUERY fenceQuery;
+ memset(&fenceQuery, 0, sizeof(fenceQuery));
+ fenceQuery.EscapeHdr.escapeCode = VBOXESC_GAFENCEQUERY;
+ // fenceQuery.EscapeHdr.cmdSpecific = 0;
+ fenceQuery.u32FenceHandle = u32FenceHandle;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &fenceQuery;
+ EscapeData.PrivateDriverDataSize = sizeof(fenceQuery);
+ EscapeData.hContext = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ pFenceQuery->u32FenceHandle = fenceQuery.u32FenceHandle;
+ pFenceQuery->u32SubmittedSeqNo = fenceQuery.u32SubmittedSeqNo;
+ pFenceQuery->u32ProcessedSeqNo = fenceQuery.u32ProcessedSeqNo;
+ pFenceQuery->u32FenceStatus = fenceQuery.u32FenceStatus;
+ return true;
+ }
+
+ Assert(0);
+ return false;
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvFenceQuery(void *pvEnv,
+ uint32_t u32FenceHandle,
+ GAFENCEQUERY *pFenceQuery)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ if (!pThis->mKmtCallbacks.hDevice)
+ {
+ pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
+ return 0;
+ }
+
+ bool fSuccess = vboxDdiFenceQuery(&pThis->mKmtCallbacks, u32FenceHandle, pFenceQuery);
+ return fSuccess ? 0: -1;
+}
+
+static bool
+vboxDdiFenceWait(GaKmtCallbacks *pKmtCallbacks,
+ uint32_t u32FenceHandle,
+ uint32_t u32TimeoutUS)
+{
+ VBOXDISPIFESCAPE_GAFENCEWAIT fenceWait;
+ memset(&fenceWait, 0, sizeof(fenceWait));
+ fenceWait.EscapeHdr.escapeCode = VBOXESC_GAFENCEWAIT;
+ // pFenceWait->EscapeHdr.cmdSpecific = 0;
+ fenceWait.u32FenceHandle = u32FenceHandle;
+ fenceWait.u32TimeoutUS = u32TimeoutUS;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &fenceWait;
+ EscapeData.PrivateDriverDataSize = sizeof(fenceWait);
+ EscapeData.hContext = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ Assert(Status == STATUS_SUCCESS);
+ return Status == STATUS_SUCCESS;
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvFenceWait(void *pvEnv,
+ uint32_t u32FenceHandle,
+ uint32_t u32TimeoutUS)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ if (!pThis->mKmtCallbacks.hDevice)
+ return 0;
+
+ bool fSuccess = vboxDdiFenceWait(&pThis->mKmtCallbacks, u32FenceHandle, u32TimeoutUS);
+ return fSuccess ? 0 : -1;
+}
+
+static bool
+vboxDdiFenceUnref(GaKmtCallbacks *pKmtCallbacks,
+ uint32_t u32FenceHandle)
+{
+ VBOXDISPIFESCAPE_GAFENCEUNREF fenceUnref;
+ memset(&fenceUnref, 0, sizeof(fenceUnref));
+ fenceUnref.EscapeHdr.escapeCode = VBOXESC_GAFENCEUNREF;
+ // pFenceUnref->EscapeHdr.cmdSpecific = 0;
+ fenceUnref.u32FenceHandle = u32FenceHandle;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &fenceUnref;
+ EscapeData.PrivateDriverDataSize = sizeof(fenceUnref);
+ EscapeData.hContext = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ Assert(Status == STATUS_SUCCESS);
+ return Status == STATUS_SUCCESS;
+}
+
+/* static */ DECLCALLBACK(void)
+GaDrvEnvKmt::gaEnvFenceUnref(void *pvEnv,
+ uint32_t u32FenceHandle)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ if (!pThis->mKmtCallbacks.hDevice)
+ return;
+
+ vboxDdiFenceUnref(&pThis->mKmtCallbacks, u32FenceHandle);
+}
+
+/** Calculate how many commands will fit in the buffer.
+ *
+ * @param pu8Commands Command buffer.
+ * @param cbCommands Size of command buffer.
+ * @param cbAvail Available buffer size..
+ * @param pu32Length Size of commands which will fit in cbAvail bytes.
+ */
+static bool
+vboxCalcCommandLength(const uint8_t *pu8Commands, uint32_t cbCommands, uint32_t cbAvail, uint32_t *pu32Length)
+{
+ uint32_t u32Length = 0;
+ const uint8_t *pu8Src = pu8Commands;
+ const uint8_t *pu8SrcEnd = pu8Commands + cbCommands;
+
+ while (pu8SrcEnd > pu8Src)
+ {
+ const uint32_t cbSrcLeft = pu8SrcEnd - pu8Src;
+ if (cbSrcLeft < sizeof(uint32_t))
+ {
+ return false;
+ }
+
+ /* Get the command id and command length. */
+ const uint32_t u32CmdId = *(uint32_t *)pu8Src;
+ uint32_t cbCmd = 0;
+
+ if (SVGA_3D_CMD_BASE <= u32CmdId && u32CmdId < SVGA_3D_CMD_MAX)
+ {
+ if (cbSrcLeft < sizeof(SVGA3dCmdHeader))
+ {
+ return false;
+ }
+
+ const SVGA3dCmdHeader *pHeader = (SVGA3dCmdHeader *)pu8Src;
+ cbCmd = sizeof(SVGA3dCmdHeader) + pHeader->size;
+ if (cbCmd % sizeof(uint32_t) != 0)
+ {
+ return false;
+ }
+ if (cbSrcLeft < cbCmd)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ /* It is not expected that any of common SVGA commands will be in the command buffer
+ * because the SVGA gallium driver does not use them.
+ */
+ return false;
+ }
+
+ if (u32Length + cbCmd > cbAvail)
+ {
+ if (u32Length == 0)
+ {
+ /* No commands fit into the buffer. */
+ return false;
+ }
+ break;
+ }
+
+ pu8Src += cbCmd;
+ u32Length += cbCmd;
+ }
+
+ *pu32Length = u32Length;
+ return true;
+}
+
+static bool
+vboxDdiRender(GaKmtCallbacks *pKmtCallbacks,
+ GAWDDMCONTEXTINFO *pContextInfo, uint32_t u32FenceHandle, void *pvCommands, uint32_t cbCommands,
+ ULONGLONG PresentHistoryToken, bool fPresentRedirected)
+{
+ uint32_t cbLeft;
+ const uint8_t *pu8Src;
+
+ cbLeft = cbCommands;
+ pu8Src = (uint8_t *)pvCommands;
+ /* Even when cbCommands is 0, submit the fence. The following code deals with this. */
+ do
+ {
+ /* Actually available space. */
+ const uint32_t cbAvail = pContextInfo->CommandBufferSize;
+ if (cbAvail <= sizeof(u32FenceHandle))
+ {
+ return false;
+ }
+
+ /* How many bytes of command data still to copy. */
+ uint32_t cbCommandChunk = cbLeft;
+
+ /* How many bytes still to copy. */
+ uint32_t cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
+
+ /* Copy the buffer identifier. */
+ if (cbToCopy <= cbAvail)
+ {
+ /* Command buffer is big enough. */
+ *(uint32_t *)pContextInfo->pCommandBuffer = u32FenceHandle;
+ }
+ else
+ {
+ /* Split. Write zero as buffer identifier. */
+ *(uint32_t *)pContextInfo->pCommandBuffer = 0;
+
+ /* Get how much commands data will fit in the buffer. */
+ if (!vboxCalcCommandLength(pu8Src, cbCommandChunk, cbAvail - sizeof(u32FenceHandle), &cbCommandChunk))
+ {
+ return false;
+ }
+
+ cbToCopy = sizeof(u32FenceHandle) + cbCommandChunk;
+ }
+
+ if (cbCommandChunk)
+ {
+ /* Copy the command data. */
+ memcpy((uint8_t *)pContextInfo->pCommandBuffer + sizeof(u32FenceHandle), pu8Src, cbCommandChunk);
+ }
+
+ /* Advance the command position. */
+ pu8Src += cbCommandChunk;
+ cbLeft -= cbCommandChunk;
+
+ D3DKMT_RENDER RenderData;
+ memset(&RenderData, 0, sizeof(RenderData));
+ RenderData.hContext = pContextInfo->hContext;
+ // RenderData.CommandOffset = 0;
+ RenderData.CommandLength = cbToCopy;
+ // RenderData.AllocationCount = 0;
+ // RenderData.PatchLocationCount = 0;
+ RenderData.PresentHistoryToken = PresentHistoryToken;
+ RenderData.Flags.PresentRedirected = fPresentRedirected;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTRender(&RenderData);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status != STATUS_SUCCESS)
+ {
+ return false;
+ }
+
+ pContextInfo->pCommandBuffer = RenderData.pNewCommandBuffer;
+ pContextInfo->CommandBufferSize = RenderData.NewCommandBufferSize;
+ pContextInfo->pAllocationList = RenderData.pNewAllocationList;
+ pContextInfo->AllocationListSize = RenderData.NewAllocationListSize;
+ pContextInfo->pPatchLocationList = RenderData.pNewPatchLocationList;
+ pContextInfo->PatchLocationListSize = RenderData.NewPatchLocationListSize;
+ } while (cbLeft);
+
+ return true;
+}
+
+bool GaDrvEnvKmt::doRender(uint32_t u32Cid, void *pvCommands, uint32_t cbCommands,
+ GAFENCEQUERY *pFenceQuery, ULONGLONG PresentHistoryToken, bool fPresentRedirected)
+{
+ uint32_t u32FenceHandle;
+ GAWDDMCONTEXTINFO *pContextInfo = (GAWDDMCONTEXTINFO *)RTAvlU32Get(&mContextTree, u32Cid);
+ if (!pContextInfo)
+ return false;
+
+ bool fSuccess = true;
+ u32FenceHandle = 0;
+ if (pFenceQuery)
+ {
+ fSuccess = vboxDdiFenceCreate(&mKmtCallbacks, pContextInfo, &u32FenceHandle);
+ }
+
+ if (fSuccess)
+ {
+ fSuccess = vboxDdiRender(&mKmtCallbacks, pContextInfo, u32FenceHandle,
+ pvCommands, cbCommands, PresentHistoryToken, fPresentRedirected);
+ if (fSuccess)
+ {
+ if (pFenceQuery)
+ {
+ if (!vboxDdiFenceQuery(&mKmtCallbacks, u32FenceHandle, pFenceQuery))
+ {
+ pFenceQuery->u32FenceStatus = GA_FENCE_STATUS_NULL;
+ }
+ }
+ }
+ }
+ return fSuccess;
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvRender(void *pvEnv,
+ uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ GAFENCEQUERY *pFenceQuery)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+ return pThis->doRender(u32Cid, pvCommands, cbCommands, pFenceQuery, 0, false) ? 1 : 0;
+}
+
+bool GaDrvEnvKmt::drvEnvKmtRenderCompose(uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ ULONGLONG PresentHistoryToken)
+{
+ return doRender(u32Cid, pvCommands, cbCommands, NULL, PresentHistoryToken, true);
+}
+
+
+static bool
+vboxDdiRegionCreate(GaKmtCallbacks *pKmtCallbacks,
+ uint32_t u32RegionSize,
+ uint32_t *pu32GmrId,
+ void **ppvMap)
+{
+ VBOXDISPIFESCAPE_GAREGION data;
+ memset(&data, 0, sizeof(data));
+ data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
+ // data.EscapeHdr.cmdSpecific = 0;
+ data.u32Command = GA_REGION_CMD_CREATE;
+ data.u32NumPages = (u32RegionSize + PAGE_SIZE - 1) / PAGE_SIZE;
+ // data.u32GmrId = 0;
+ // data.u64UserAddress = 0;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ // EscapeData.hContext = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ *pu32GmrId = data.u32GmrId;
+ *ppvMap = (void *)(uintptr_t)data.u64UserAddress;
+ return true;
+ }
+
+ Assert(0);
+ return false;
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvRegionCreate(void *pvEnv,
+ uint32_t u32RegionSize,
+ uint32_t *pu32GmrId,
+ void **ppvMap)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ if (pThis->mKmtCallbacks.hDevice)
+ {
+ /* That is a real device */
+ bool fSuccess = vboxDdiRegionCreate(&pThis->mKmtCallbacks, u32RegionSize, pu32GmrId, ppvMap);
+ return fSuccess ? 0: -1;
+ }
+
+ /* That is a fake device, created when WDDM adapter is initialized. */
+ *ppvMap = malloc(u32RegionSize);
+ if (*ppvMap)
+ {
+ *pu32GmrId = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+static bool
+vboxDdiRegionDestroy(GaKmtCallbacks *pKmtCallbacks,
+ uint32_t u32GmrId)
+{
+ VBOXDISPIFESCAPE_GAREGION data;
+ memset(&data, 0, sizeof(data));
+ data.EscapeHdr.escapeCode = VBOXESC_GAREGION;
+ // data.EscapeHdr.cmdSpecific = 0;
+ data.u32Command = GA_REGION_CMD_DESTROY;
+ // data.u32NumPages = 0;
+ data.u32GmrId = u32GmrId;
+ // data.u64UserAddress = 0;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pKmtCallbacks->hAdapter;
+ EscapeData.hDevice = pKmtCallbacks->hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1; /* Sync with submitted commands. */
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ // EscapeData.hContext = 0;
+
+ NTSTATUS Status = pKmtCallbacks->d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ Assert(Status == STATUS_SUCCESS);
+ return Status == STATUS_SUCCESS;
+}
+
+/* static */ DECLCALLBACK(void)
+GaDrvEnvKmt::gaEnvRegionDestroy(void *pvEnv,
+ uint32_t u32GmrId,
+ void *pvMap)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ if (pThis->mKmtCallbacks.hDevice)
+ {
+ vboxDdiRegionDestroy(&pThis->mKmtCallbacks, u32GmrId);
+ }
+ else
+ {
+ free(pvMap);
+ }
+}
+
+/* static */ DECLCALLBACK(int)
+GaDrvEnvKmt::gaEnvGBSurfaceDefine(void *pvEnv,
+ SVGAGBSURFCREATE *pCreateParms)
+{
+ GaDrvEnvKmt *pThis = (GaDrvEnvKmt *)pvEnv;
+
+ VBOXDISPIFESCAPE_SVGAGBSURFACEDEFINE data;
+ data.EscapeHdr.escapeCode = VBOXESC_SVGAGBSURFACEDEFINE;
+ data.EscapeHdr.u32CmdSpecific = 0;
+ data.CreateParms = *pCreateParms;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = pThis->mKmtCallbacks.hAdapter;
+ EscapeData.hDevice = pThis->mKmtCallbacks.hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ // EscapeData.hContext = 0;
+
+ NTSTATUS Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ {
+ pCreateParms->gmrid = data.CreateParms.gmrid;
+ pCreateParms->cbGB = data.CreateParms.cbGB;
+ pCreateParms->u64UserAddress = data.CreateParms.u64UserAddress;
+ pCreateParms->u32Sid = data.CreateParms.u32Sid;
+
+ /* Create a kernel mode allocation for render targets,
+ * because we will need kernel mode handles for Present.
+ */
+ if (pCreateParms->s.flags & SVGA3D_SURFACE_HINT_RENDERTARGET)
+ {
+ /* First check if the format is supported. */
+ D3DDDIFORMAT const ddiFormat = svgaToD3DDDIFormat((SVGA3dSurfaceFormat)pCreateParms->s.format);
+ if (ddiFormat != D3DDDIFMT_UNKNOWN)
+ {
+ GAWDDMSURFACEINFO *pSurfaceInfo = (GAWDDMSURFACEINFO *)malloc(sizeof(GAWDDMSURFACEINFO));
+ if (pSurfaceInfo)
+ {
+ memset(pSurfaceInfo, 0, sizeof(GAWDDMSURFACEINFO));
+
+ VBOXWDDM_ALLOCINFO wddmAllocInfo;
+ memset(&wddmAllocInfo, 0, sizeof(wddmAllocInfo));
+
+ wddmAllocInfo.enmType = VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC;
+ wddmAllocInfo.fFlags.RenderTarget = 1;
+ wddmAllocInfo.hSharedHandle = 0;
+ wddmAllocInfo.hostID = pCreateParms->u32Sid;
+ wddmAllocInfo.SurfDesc.slicePitch = 0;
+ wddmAllocInfo.SurfDesc.depth = pCreateParms->s.size.depth;
+ wddmAllocInfo.SurfDesc.width = pCreateParms->s.size.width;
+ wddmAllocInfo.SurfDesc.height = pCreateParms->s.size.height;
+ wddmAllocInfo.SurfDesc.format = ddiFormat;
+ wddmAllocInfo.SurfDesc.VidPnSourceId = 0;
+ wddmAllocInfo.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.pitch = vboxWddmCalcPitch(wddmAllocInfo.SurfDesc.width,
+ wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.cbSize = vboxWddmCalcSize(wddmAllocInfo.SurfDesc.pitch,
+ wddmAllocInfo.SurfDesc.height,
+ wddmAllocInfo.SurfDesc.format);
+ wddmAllocInfo.SurfDesc.d3dWidth = vboxWddmCalcWidthForPitch(wddmAllocInfo.SurfDesc.pitch,
+ wddmAllocInfo.SurfDesc.format);
+
+ D3DDDI_ALLOCATIONINFO AllocationInfo;
+ memset(&AllocationInfo, 0, sizeof(AllocationInfo));
+ // AllocationInfo.hAllocation = NULL;
+ // AllocationInfo.pSystemMem = NULL;
+ AllocationInfo.pPrivateDriverData = &wddmAllocInfo;
+ AllocationInfo.PrivateDriverDataSize = sizeof(wddmAllocInfo);
+
+ D3DKMT_CREATEALLOCATION CreateAllocation;
+ memset(&CreateAllocation, 0, sizeof(CreateAllocation));
+ CreateAllocation.hDevice = pThis->mKmtCallbacks.hDevice;
+ CreateAllocation.NumAllocations = 1;
+ CreateAllocation.pAllocationInfo = &AllocationInfo;
+
+ Status = pThis->mKmtCallbacks.d3dkmt->pfnD3DKMTCreateAllocation(&CreateAllocation);
+ if (Status == STATUS_SUCCESS)
+ {
+ pSurfaceInfo->Core.Key = pCreateParms->u32Sid;
+ pSurfaceInfo->hAllocation = AllocationInfo.hAllocation;
+ if (!RTAvlU32Insert(&pThis->mSurfaceTree, &pSurfaceInfo->Core))
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ free(pSurfaceInfo);
+ }
+ }
+ else
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+ else
+ {
+ /* Unsupported render target format. */
+ Assert(0);
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ gaEnvSurfaceDestroy(pvEnv, pCreateParms->u32Sid);
+ }
+ }
+
+ if (Status == STATUS_SUCCESS)
+ return 0;
+
+ Assert(0);
+ return -1;
+}
+
+GaDrvEnvKmt::GaDrvEnvKmt()
+ :
+ mContextTree(0),
+ mSurfaceTree(0)
+{
+ RT_ZERO(mKmtCallbacks);
+ RT_ZERO(mHWInfo);
+ RT_ZERO(mEnv);
+}
+
+GaDrvEnvKmt::~GaDrvEnvKmt()
+{
+}
+
+HRESULT GaDrvEnvKmt::Init(void)
+{
+ mKmtCallbacks.d3dkmt = D3DKMTFunctions();
+
+ /* Figure out which adapter to use. */
+ NTSTATUS Status = vboxDispKmtOpenAdapter2(&mKmtCallbacks.hAdapter, &mKmtCallbacks.AdapterLuid);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ VBOXWDDM_QAI adapterInfo;
+ bool fSuccess = vboxDdiQueryAdapterInfo(&mKmtCallbacks, mKmtCallbacks.hAdapter, &adapterInfo, sizeof(adapterInfo));
+ Assert(fSuccess);
+ if (fSuccess)
+ {
+ fSuccess = vboxDdiDeviceCreate(&mKmtCallbacks, &mKmtCallbacks.hDevice);
+ Assert(fSuccess);
+ if (fSuccess)
+ {
+ mHWInfo = adapterInfo.u.vmsvga.HWInfo;
+
+ /*
+ * Success.
+ */
+ return S_OK;
+ }
+
+ vboxDdiDeviceDestroy(&mKmtCallbacks, mKmtCallbacks.hDevice);
+ }
+
+ vboxDispKmtCloseAdapter(mKmtCallbacks.hAdapter);
+ }
+
+ return E_FAIL;
+}
+
+const WDDMGalliumDriverEnv *GaDrvEnvKmt::Env()
+{
+ if (mEnv.cb == 0)
+ {
+ mEnv.cb = sizeof(WDDMGalliumDriverEnv);
+ mEnv.pHWInfo = &mHWInfo;
+ mEnv.pvEnv = this;
+ mEnv.pfnContextCreate = gaEnvContextCreate;
+ mEnv.pfnContextDestroy = gaEnvContextDestroy;
+ mEnv.pfnSurfaceDefine = gaEnvSurfaceDefine;
+ mEnv.pfnSurfaceDestroy = gaEnvSurfaceDestroy;
+ mEnv.pfnRender = gaEnvRender;
+ mEnv.pfnFenceUnref = gaEnvFenceUnref;
+ mEnv.pfnFenceQuery = gaEnvFenceQuery;
+ mEnv.pfnFenceWait = gaEnvFenceWait;
+ mEnv.pfnRegionCreate = gaEnvRegionCreate;
+ mEnv.pfnRegionDestroy = gaEnvRegionDestroy;
+ /* VGPU10 */
+ mEnv.pfnGBSurfaceDefine = gaEnvGBSurfaceDefine;
+ }
+
+ return &mEnv;
+}
+
+RT_C_DECLS_BEGIN
+
+const WDDMGalliumDriverEnv *GaDrvEnvKmtCreate(void)
+{
+ GaDrvEnvKmt *p = new GaDrvEnvKmt();
+ if (p)
+ {
+ HRESULT hr = p->Init();
+ if (hr != S_OK)
+ {
+ delete p;
+ p = NULL;
+ }
+ }
+ return p ? p->Env() : NULL;
+}
+
+void GaDrvEnvKmtDelete(const WDDMGalliumDriverEnv *pEnv)
+{
+ if (pEnv)
+ {
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ delete p;
+ }
+}
+
+D3DKMT_HANDLE GaDrvEnvKmtContextHandle(const WDDMGalliumDriverEnv *pEnv, uint32_t u32Cid)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ return p->drvEnvKmtContextHandle(u32Cid);
+}
+
+D3DKMT_HANDLE GaDrvEnvKmtSurfaceHandle(const WDDMGalliumDriverEnv *pEnv, uint32_t u32Sid)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ return p->drvEnvKmtSurfaceHandle(u32Sid);
+}
+
+void GaDrvEnvKmtAdapterLUID(const WDDMGalliumDriverEnv *pEnv, LUID *pAdapterLuid)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ *pAdapterLuid = p->mKmtCallbacks.AdapterLuid;
+}
+
+D3DKMT_HANDLE GaDrvEnvKmtAdapterHandle(const WDDMGalliumDriverEnv *pEnv)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ return p->mKmtCallbacks.hAdapter;
+}
+
+D3DKMT_HANDLE GaDrvEnvKmtDeviceHandle(const WDDMGalliumDriverEnv *pEnv)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ return p->mKmtCallbacks.hDevice;
+}
+
+void GaDrvEnvKmtRenderCompose(const WDDMGalliumDriverEnv *pEnv,
+ uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ ULONGLONG PresentHistoryToken)
+{
+ GaDrvEnvKmt *p = (GaDrvEnvKmt *)pEnv->pvEnv;
+ p->drvEnvKmtRenderCompose(u32Cid, pvCommands, cbCommands, PresentHistoryToken);
+}
+
+RT_C_DECLS_END
diff --git a/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.h b/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.h
new file mode 100644
index 00000000..44cad791
--- /dev/null
+++ b/src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.h
@@ -0,0 +1,58 @@
+/* $Id: GaDrvEnvKMT.h $ */
+/** @file
+ * VirtualBox Windows Guest Mesa3D - Gallium driver interface to the WDDM miniport driver.
+ */
+
+/*
+ * Copyright (C) 2016-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef GA_INCLUDED_SRC_3D_win_VBoxGL_GaDrvEnvKMT_h
+#define GA_INCLUDED_SRC_3D_win_VBoxGL_GaDrvEnvKMT_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBoxGaDriver.h>
+#include <VBoxWddmUmHlp.h>
+
+RT_C_DECLS_BEGIN
+
+const WDDMGalliumDriverEnv *GaDrvEnvKmtCreate(void);
+void GaDrvEnvKmtDelete(const WDDMGalliumDriverEnv *pEnv);
+
+D3DKMT_HANDLE GaDrvEnvKmtContextHandle(const WDDMGalliumDriverEnv *pEnv,
+ uint32_t u32Cid);
+D3DKMT_HANDLE GaDrvEnvKmtSurfaceHandle(const WDDMGalliumDriverEnv *pEnv,
+ uint32_t u32Sid);
+void GaDrvEnvKmtAdapterLUID(const WDDMGalliumDriverEnv *pEnv,
+ LUID *pAdapterLuid);
+D3DKMT_HANDLE GaDrvEnvKmtAdapterHandle(const WDDMGalliumDriverEnv *pEnv);
+D3DKMT_HANDLE GaDrvEnvKmtDeviceHandle(const WDDMGalliumDriverEnv *pEnv);
+void GaDrvEnvKmtRenderCompose(const WDDMGalliumDriverEnv *pEnv,
+ uint32_t u32Cid,
+ void *pvCommands,
+ uint32_t cbCommands,
+ ULONGLONG PresentHistoryToken);
+
+RT_C_DECLS_END
+
+#endif /* !GA_INCLUDED_SRC_3D_win_VBoxGL_GaDrvEnvKMT_h */
diff --git a/src/VBox/Additions/3D/win/VBoxGL/Makefile.kmk b/src/VBox/Additions/3D/win/VBoxGL/Makefile.kmk
new file mode 100644
index 00000000..0a330258
--- /dev/null
+++ b/src/VBox/Additions/3D/win/VBoxGL/Makefile.kmk
@@ -0,0 +1,87 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxGL OpenGL state tracker.
+#
+
+#
+# Copyright (C) 2018-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+DLLS += VBoxGL
+DLLS.amd64 += VBoxGL-x86
+
+VBoxGL_TEMPLATE = VBoxMesa3DGuestR3DllMinVista
+VBoxGL_DEFS = VBOXGL
+# -wd4005: '__useHeader' : redefinition
+VBOXGL_DISABLED_WARNINGS := -wd4005
+# -wd4204: nonstandard extension used: non-constant aggregate initializer
+# -wd4267: 'initializing': conversion from 'size_t' to 'unsigned int', possible loss of data
+# -wd4459: stw_device.h(102): warning C4459: declaration of 'stw_dev' hides global declaration
+# -wd4668: c99_compat.h(99): warning C4668: '__STDC_VERSION__' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
+VBOXGL_DISABLED_WARNINGS += -wd4204 -wd4267 -wd4459 -wd4668
+VBoxGL_CFLAGS = $(VBOXGL_DISABLED_WARNINGS)
+VBoxGL_CXXFLAGS = $(VBOXGL_DISABLED_WARNINGS)
+VBoxGL_INCS = \
+ $(VBOX_PATH_3D)/win/include \
+ $(VBOX_PATH_MESA)/include/GL \
+ $(VBOX_PATH_MESA)/src/gallium/frontends/wgl \
+ $(VBOX_PATH_MESA)/src/gallium/winsys/sw \
+ $(VBOX_PATH_MESA)/src/gallium/drivers \
+ $(PATH_ROOT)/src/VBox/Additions/WINNT/Graphics/Video \
+ $(PATH_ROOT)/src/VBox/Runtime/common/table \
+ $(VBOX_PATH_VMSVGA_INC) \
+ $(VBOX_GRAPHICS_INCS)
+VBoxGL_SOURCES = \
+ $(VBOX_PATH_MESA)/src/gallium/targets/libgl-gdi/opengl32.def \
+ VBoxGL.rc
+VBoxGL_SOURCES += \
+ GaDrvEnvKMT.cpp \
+ VBoxGL.c
+VBoxGL_LIBS = \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxWddmUmHlp$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaGalliumAuxLib$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaWglLib$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaUtilLib$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaLib$(VBOX_SUFF_LIB)
+
+if defined(VBOX_SIGNING_MODE) && defined(VBOX_SIGN_ADDITIONS)
+ VBoxGL_INSTTYPE = none
+ VBoxGL_DEBUG_INSTTYPE = both
+endif
+
+#
+# VBoxGL-x86 - x86 version of VBoxGL built for amd64 build
+#
+VBoxGL-x86_EXTENDS = VBoxGL
+VBoxGL-x86_BLD_TRG_ARCH = x86
+VBoxGL-x86_LIBS = \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxWddmUmHlp-x86$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaGalliumAuxLib-x86$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaWglLib-x86$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaUtilLib-x86$(VBOX_SUFF_LIB) \
+ $(VBOX_PATH_ADDITIONS_LIB)/VBoxMesaLib-x86$(VBOX_SUFF_LIB)
+VBoxGL-x86_DEFS = $(VBoxGL_DEFS) VBOX_WOW64
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c b/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c
new file mode 100644
index 00000000..01b6cf89
--- /dev/null
+++ b/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c
@@ -0,0 +1,580 @@
+/* $Id: VBoxGL.c $ */
+/** @file
+ * VirtualBox Windows Guest Mesa3D - OpenGL driver.
+ */
+
+/*
+ * Copyright (C) 2018-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "GaDrvEnvKMT.h"
+
+#include "stw_winsys.h"
+#include "stw_device.h"
+#include "stw_context.h"
+
+#include "pipe/p_state.h"
+#include "svga3d_reg.h"
+
+#include <iprt/asm.h>
+
+#include <common/wddm/VBoxMPIf.h>
+
+#include <Psapi.h>
+
+static const char *g_pszSvgaDll =
+#ifdef VBOX_WOW64
+ "VBoxSVGA-x86.dll"
+#else
+ "VBoxSVGA.dll"
+#endif
+;
+
+static struct GaDrvFunctions
+{
+ PFNGaDrvScreenCreate pfnGaDrvScreenCreate;
+ PFNGaDrvScreenDestroy pfnGaDrvScreenDestroy;
+ PFNGaDrvGetWDDMEnv pfnGaDrvGetWDDMEnv;
+ PFNGaDrvGetContextId pfnGaDrvGetContextId;
+ PFNGaDrvGetSurfaceId pfnGaDrvGetSurfaceId;
+ PFNGaDrvContextFlush pfnGaDrvContextFlush;
+} g_drvfuncs;
+
+
+static HMODULE gaDrvLoadSVGA(struct GaDrvFunctions *pDrvFuncs)
+{
+ struct VBOXWDDMDLLPROC aDrvProcs[] =
+ {
+ { "GaDrvScreenCreate", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenCreate },
+ { "GaDrvScreenDestroy", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenDestroy },
+ { "GaDrvGetWDDMEnv", (FARPROC *)&pDrvFuncs->pfnGaDrvGetWDDMEnv },
+ { "GaDrvGetContextId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetContextId },
+ { "GaDrvGetSurfaceId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetSurfaceId },
+ { "GaDrvContextFlush", (FARPROC *)&pDrvFuncs->pfnGaDrvContextFlush },
+ { NULL, NULL }
+ };
+
+ HMODULE hmod = VBoxWddmLoadSystemDll(g_pszSvgaDll);
+ if (hmod)
+ {
+ VBoxWddmLoadAdresses(hmod, aDrvProcs);
+ }
+ return hmod;
+}
+
+struct stw_shared_surface
+{
+ D3DKMT_HANDLE hResource;
+ D3DKMT_HANDLE hSurface;
+ uint32_t u32Sid;
+};
+
+static NTSTATUS vboxKmtPresent(D3DKMT_HANDLE hContext, HWND hwnd, D3DKMT_HANDLE hSource, LONG lWidth, LONG lHeight)
+{
+ RECT r;
+ r.left = 0;
+ r.top = 0;
+ r.right = lWidth;
+ r.bottom = lHeight;
+
+ D3DKMT_PRESENT PresentData;
+ memset(&PresentData, 0, sizeof(PresentData));
+ PresentData.hContext = hContext;
+ PresentData.hWindow = hwnd;
+ PresentData.hSource = hSource;
+ PresentData.hDestination = 0;
+ PresentData.Flags.Blt = 1;
+ PresentData.Flags.SrcRectValid = 1;
+ PresentData.Flags.DstRectValid = 1;
+ PresentData.SrcRect = r;
+ PresentData.SubRectCnt = 1;
+ PresentData.pSrcSubRects = &r;
+ PresentData.DstRect = r;
+
+ D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
+ NTSTATUS Status = d3dkmt->pfnD3DKMTPresent(&PresentData);
+ return Status;
+}
+
+NTSTATUS vboxKmtOpenSharedSurface(D3DKMT_HANDLE hAdapter, D3DKMT_HANDLE hDevice, D3DKMT_HANDLE hSharedSurface, struct stw_shared_surface *pSurf)
+{
+ D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
+
+ D3DKMT_QUERYRESOURCEINFO QueryResourceInfoData;
+ memset(&QueryResourceInfoData, 0, sizeof(QueryResourceInfoData));
+ QueryResourceInfoData.hDevice = hDevice;
+ QueryResourceInfoData.hGlobalShare = hSharedSurface;
+
+ NTSTATUS Status = d3dkmt->pfnD3DKMTQueryResourceInfo(&QueryResourceInfoData);
+ if (Status == STATUS_SUCCESS)
+ {
+ D3DDDI_OPENALLOCATIONINFO OpenAllocationInfoData;
+ memset(&OpenAllocationInfoData, 0, sizeof(OpenAllocationInfoData));
+
+ D3DKMT_OPENRESOURCE OpenResourceData;
+ memset(&OpenResourceData, 0, sizeof(OpenResourceData));
+ OpenResourceData.hDevice = hDevice;
+ OpenResourceData.hGlobalShare = hSharedSurface;
+ OpenResourceData.NumAllocations = 1;
+ OpenResourceData.pOpenAllocationInfo = &OpenAllocationInfoData;
+ if (QueryResourceInfoData.PrivateRuntimeDataSize)
+ {
+ OpenResourceData.pPrivateRuntimeData = malloc(QueryResourceInfoData.PrivateRuntimeDataSize);
+ if (OpenResourceData.pPrivateRuntimeData == NULL)
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ OpenResourceData.PrivateRuntimeDataSize = QueryResourceInfoData.PrivateRuntimeDataSize;
+ }
+ if (QueryResourceInfoData.ResourcePrivateDriverDataSize)
+ {
+ OpenResourceData.pResourcePrivateDriverData = malloc(QueryResourceInfoData.ResourcePrivateDriverDataSize);
+ if (OpenResourceData.pResourcePrivateDriverData == NULL)
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ OpenResourceData.ResourcePrivateDriverDataSize = QueryResourceInfoData.ResourcePrivateDriverDataSize;
+ }
+ if (QueryResourceInfoData.TotalPrivateDriverDataSize)
+ {
+ OpenResourceData.pTotalPrivateDriverDataBuffer = malloc(QueryResourceInfoData.TotalPrivateDriverDataSize);
+ if (OpenResourceData.pTotalPrivateDriverDataBuffer == NULL)
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ OpenResourceData.TotalPrivateDriverDataBufferSize = QueryResourceInfoData.TotalPrivateDriverDataSize;
+ }
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = d3dkmt->pfnD3DKMTOpenResource(&OpenResourceData);
+ if (Status == STATUS_SUCCESS)
+ {
+ if (OpenAllocationInfoData.PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO))
+ {
+ VBOXWDDM_ALLOCINFO *pVBoxAllocInfo = (VBOXWDDM_ALLOCINFO *)OpenAllocationInfoData.pPrivateDriverData;
+ pSurf->hResource = OpenResourceData.hResource;
+ pSurf->hSurface = OpenAllocationInfoData.hAllocation;
+ pSurf->u32Sid = pVBoxAllocInfo->hostID;
+ }
+ else if (OpenAllocationInfoData.PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC))
+ {
+ //VBOXDXALLOCATIONDESC *pAllocDesc = (VBOXDXALLOCATIONDESC *)OpenAllocationInfoData.PrivateDriverDataSize;
+ pSurf->hResource = OpenResourceData.hResource;
+ pSurf->hSurface = OpenAllocationInfoData.hAllocation;
+
+ VBOXDISPIFESCAPE_SVGAGETSID data;
+ memset(&data, 0, sizeof(data));
+ data.EscapeHdr.escapeCode = VBOXESC_SVGAGETSID;
+ data.hAllocation = OpenAllocationInfoData.hAllocation;
+ // data.u32Sid = 0;
+
+ D3DKMT_ESCAPE EscapeData;
+ memset(&EscapeData, 0, sizeof(EscapeData));
+ EscapeData.hAdapter = hAdapter;
+ EscapeData.hDevice = hDevice;
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ // EscapeData.Flags.HardwareAccess = 0;
+ EscapeData.pPrivateDriverData = &data;
+ EscapeData.PrivateDriverDataSize = sizeof(data);
+ // EscapeData.hContext = 0;
+ Status = d3dkmt->pfnD3DKMTEscape(&EscapeData);
+ if (Status == STATUS_SUCCESS)
+ pSurf->u32Sid = data.u32Sid;
+ else
+ Assert(0);
+ }
+ else
+ Assert(0);
+ }
+ }
+
+ if (OpenResourceData.pPrivateRuntimeData != NULL)
+ {
+ free(OpenResourceData.pPrivateRuntimeData);
+ }
+ if (OpenResourceData.pResourcePrivateDriverData != NULL)
+ {
+ free(OpenResourceData.pResourcePrivateDriverData);
+ }
+ if (OpenResourceData.pTotalPrivateDriverDataBuffer != NULL)
+ {
+ free(OpenResourceData.pTotalPrivateDriverDataBuffer);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS vboxKmtCloseSharedSurface(D3DKMT_HANDLE hDevice, struct stw_shared_surface *pSurf)
+{
+ D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
+
+ D3DKMT_DESTROYALLOCATION DestroyAllocationData;
+ memset(&DestroyAllocationData, 0, sizeof(DestroyAllocationData));
+ DestroyAllocationData.hDevice = hDevice;
+ DestroyAllocationData.hResource = pSurf->hResource;
+ /* "If the OpenGL ICD sets the handle in the hResource member to a non-NULL value,
+ * the ICD must set phAllocationList to NULL." and
+ * "the AllocationCount member is ignored by the OpenGL runtime."
+ */
+ // DestroyAllocationData.phAllocationList = NULL;
+ // DestroyAllocationData.AllocationCount = 0;
+
+ NTSTATUS Status = d3dkmt->pfnD3DKMTDestroyAllocation(&DestroyAllocationData);
+ Assert(Status == STATUS_SUCCESS);
+ return Status;
+}
+
+
+static struct pipe_screen *
+wddm_screen_create(HDC hDC)
+{
+ RT_NOREF(hDC); /** @todo Use it? */
+ struct pipe_screen *screen = NULL;
+
+ if (gaDrvLoadSVGA(&g_drvfuncs))
+ {
+ WDDMGalliumDriverEnv const *pEnv = GaDrvEnvKmtCreate();
+ if (pEnv)
+ {
+ /// @todo pEnv to include destructor callback, to be called from winsys screen destructor?
+ screen = g_drvfuncs.pfnGaDrvScreenCreate(pEnv);
+ }
+ }
+
+ return screen;
+}
+
+static void
+wddm_present(struct pipe_screen *screen,
+ struct pipe_context *context,
+ struct pipe_resource *res,
+ HDC hDC)
+{
+ RT_NOREF(context);
+ struct stw_context *ctx = stw_current_context();
+ struct pipe_context *pipe = ctx->st->pipe;
+
+ const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
+ if (pEnv)
+ {
+ /* Get context and kernel-mode handle of the resource. */
+ uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
+ D3DKMT_HANDLE hContext = GaDrvEnvKmtContextHandle(pEnv, u32Cid);
+
+ uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
+ D3DKMT_HANDLE hSource = GaDrvEnvKmtSurfaceHandle(pEnv, u32SourceSid);
+
+ HWND hwnd = WindowFromDC(hDC);
+
+ vboxKmtPresent(hContext, hwnd, hSource, res->width0, res->height0);
+ }
+}
+
+static boolean
+wddm_get_adapter_luid(struct pipe_screen *screen,
+ HDC hDC,
+ LUID *pAdapterLuid)
+{
+ RT_NOREF(hDC); /** @todo Use it? */
+ const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
+ if (pEnv)
+ {
+ GaDrvEnvKmtAdapterLUID(pEnv, pAdapterLuid);
+ return true;
+ }
+
+ return false;
+}
+
+static struct stw_shared_surface *
+wddm_shared_surface_open(struct pipe_screen *screen,
+ HANDLE hSharedSurface)
+{
+ struct stw_shared_surface *surface = NULL;
+
+ const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
+ if (pEnv)
+ {
+ surface = (struct stw_shared_surface *)malloc(sizeof(struct stw_shared_surface));
+ if (surface)
+ {
+ D3DKMT_HANDLE hAdapter = GaDrvEnvKmtAdapterHandle(pEnv);
+ D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
+ NTSTATUS Status = vboxKmtOpenSharedSurface(hAdapter, hDevice, (D3DKMT_HANDLE)(uintptr_t)hSharedSurface, surface);
+ if (Status != STATUS_SUCCESS)
+ {
+ free(surface);
+ surface = NULL;
+ }
+ }
+ }
+ return surface;
+}
+
+static void
+wddm_shared_surface_close(struct pipe_screen *screen,
+ struct stw_shared_surface *surface)
+{
+ const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
+ if (pEnv)
+ {
+ D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
+ vboxKmtCloseSharedSurface(hDevice, surface);
+ }
+ free(surface);
+}
+
+static void
+wddm_compose(struct pipe_screen *screen,
+ struct pipe_resource *res,
+ struct stw_shared_surface *dest,
+ LPCRECT pRect,
+ ULONGLONG PresentHistoryToken)
+{
+ struct stw_context *ctx = stw_current_context();
+ struct pipe_context *pipe = ctx->st->pipe;
+
+ /* The ICD asked to present something, make sure that any outstanding commends are submitted. */
+ g_drvfuncs.pfnGaDrvContextFlush(pipe);
+
+ uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
+
+ /* Generate SVGA_3D_CMD_SURFACE_COPY command for these resources. */
+ struct
+ {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdSurfaceCopy surfaceCopy;
+ SVGA3dCopyBox box;
+ } command;
+
+ command.header.id = SVGA_3D_CMD_SURFACE_COPY;
+ command.header.size = sizeof(command) - sizeof(SVGA3dCmdHeader);
+
+ command.surfaceCopy.src.sid = u32SourceSid;
+ command.surfaceCopy.src.face = 0;
+ command.surfaceCopy.src.mipmap = 0;
+ command.surfaceCopy.dest.sid = dest->u32Sid;
+ command.surfaceCopy.dest.face = 0;
+ command.surfaceCopy.dest.mipmap = 0;
+
+ command.box.x = pRect->left;
+ command.box.y = pRect->top;
+ command.box.z = 0;
+ command.box.w = pRect->right - pRect->left;
+ command.box.h = pRect->bottom - pRect->top;
+ command.box.d = 1;
+ command.box.srcx = 0;
+ command.box.srcy = 0;
+ command.box.srcz = 0;
+
+ const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
+ if (pEnv)
+ {
+ uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
+ GaDrvEnvKmtRenderCompose(pEnv, u32Cid, &command, sizeof(command), PresentHistoryToken);
+ }
+}
+
+static unsigned
+wddm_get_pfd_flags(struct pipe_screen *screen)
+{
+ (void)screen;
+ return stw_pfd_gdi_support | stw_pfd_double_buffer;
+}
+
+static const char *
+wddm_get_name(void)
+{
+ return "VBoxGL";
+}
+
+static const struct stw_winsys stw_winsys = {
+ wddm_screen_create,
+ wddm_present,
+ wddm_get_adapter_luid,
+ wddm_shared_surface_open,
+ wddm_shared_surface_close,
+ wddm_compose,
+ wddm_get_pfd_flags,
+ NULL, /* create_framebuffer */
+ wddm_get_name,
+};
+
+#ifdef DEBUG
+typedef BOOL WINAPI FNGetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
+typedef FNGetModuleInformation *PFNGetModuleInformation;
+
+static PFNGetModuleInformation g_pfnGetModuleInformation = NULL;
+static HMODULE g_hModPsapi = NULL;
+static PVOID g_VBoxWDbgVEHandler = NULL;
+
+static bool vboxVDbgIsAddressInModule(PVOID pv, const char *pszModuleName)
+{
+ HMODULE hMod = GetModuleHandleA(pszModuleName);
+ if (!hMod)
+ return false;
+
+ if (!g_pfnGetModuleInformation)
+ return false;
+
+ HANDLE hProcess = GetCurrentProcess();
+ MODULEINFO ModuleInfo = {0};
+ if (!g_pfnGetModuleInformation(hProcess, hMod, &ModuleInfo, sizeof(ModuleInfo)))
+ return false;
+
+ return (uintptr_t)ModuleInfo.lpBaseOfDll <= (uintptr_t)pv
+ && (uintptr_t)pv < (uintptr_t)ModuleInfo.lpBaseOfDll + ModuleInfo.SizeOfImage;
+}
+
+static bool vboxVDbgIsExceptionIgnored(PEXCEPTION_RECORD pExceptionRecord)
+{
+ /* Module (dll) names for GetModuleHandle.
+ * Exceptions originated from these modules will be ignored.
+ */
+ static const char *apszIgnoredModuleNames[] =
+ {
+ NULL
+ };
+
+ int i = 0;
+ while (apszIgnoredModuleNames[i])
+ {
+ if (vboxVDbgIsAddressInModule(pExceptionRecord->ExceptionAddress, apszIgnoredModuleNames[i]))
+ return true;
+
+ ++i;
+ }
+
+ return false;
+}
+
+static LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo) RT_NOTHROW_DEF
+{
+ static volatile bool g_fAllowIgnore = true; /* Might be changed in kernel debugger. */
+
+ PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
+ /* PCONTEXT pContextRecord = pExceptionInfo->ContextRecord; */
+
+ switch (pExceptionRecord->ExceptionCode)
+ {
+ default:
+ break;
+ case EXCEPTION_BREAKPOINT:
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_STACK_OVERFLOW:
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ if (g_fAllowIgnore && vboxVDbgIsExceptionIgnored(pExceptionRecord))
+ break;
+ ASMBreakpoint();
+ break;
+ case 0x40010006: /* OutputDebugStringA? */
+ case 0x4001000a: /* OutputDebugStringW? */
+ break;
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+static void vboxVDbgVEHandlerRegister(void)
+{
+ Assert(!g_VBoxWDbgVEHandler);
+ g_VBoxWDbgVEHandler = AddVectoredExceptionHandler(1, vboxVDbgVectoredHandler);
+ Assert(g_VBoxWDbgVEHandler);
+
+ g_hModPsapi = GetModuleHandleA("Psapi.dll"); /* Usually already loaded. */
+ if (g_hModPsapi)
+ g_pfnGetModuleInformation = (PFNGetModuleInformation)GetProcAddress(g_hModPsapi, "GetModuleInformation");
+}
+
+static void vboxVDbgVEHandlerUnregister(void)
+{
+ Assert(g_VBoxWDbgVEHandler);
+ ULONG uResult = RemoveVectoredExceptionHandler(g_VBoxWDbgVEHandler);
+ Assert(uResult); RT_NOREF(uResult);
+ g_VBoxWDbgVEHandler = NULL;
+
+ g_hModPsapi = NULL;
+ g_pfnGetModuleInformation = NULL;
+}
+#endif /* DEBUG */
+
+BOOL WINAPI DllMain(HINSTANCE hDLLInst,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ RT_NOREF2(hDLLInst, lpvReserved);
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+#ifdef DEBUG
+ vboxVDbgVEHandlerRegister();
+#endif
+ D3DKMTLoad();
+ stw_init(&stw_winsys);
+ stw_init_thread();
+ break;
+
+ case DLL_PROCESS_DETACH:
+#ifdef DEBUG
+ vboxVDbgVEHandlerUnregister();
+#endif
+ break;
+
+ case DLL_THREAD_ATTACH:
+ stw_init_thread();
+ break;
+
+ case DLL_THREAD_DETACH:
+ stw_cleanup_thread();
+ break;
+
+ default:
+ if (lpvReserved == NULL)
+ {
+ // We're being unloaded from the process.
+ stw_cleanup_thread();
+ stw_cleanup();
+ }
+ else
+ {
+ // Process itself is terminating, and all threads and modules are
+ // being detached.
+ //
+ // The order threads (including llvmpipe rasterizer threads) are
+ // destroyed can not be relied up, so it's not safe to cleanup.
+ //
+ // However global destructors (e.g., LLVM's) will still be called, and
+ // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
+ // still try to invoke DrvDeleteContext to destroys all outstanding,
+ // so set stw_dev to NULL to return immediately if that happens.
+ stw_dev = NULL;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.rc b/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.rc
new file mode 100644
index 00000000..6c96f47e
--- /dev/null
+++ b/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.rc
@@ -0,0 +1,66 @@
+/* $Id: VBoxGL.rc $ */
+/** @file
+ * VBoxGL - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2018-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "VirtualBox OpenGL Mesa State Tracker\0"
+ VALUE "InternalName", "VBoxGL\0"
+#ifdef VBOX_WOW64
+ VALUE "OriginalFilename", "VBoxGL-x86.DLL\0"
+#else
+ VALUE "OriginalFilename", "VBoxGL.DLL\0"
+#endif
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_GA_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END