diff options
Diffstat (limited to 'src/VBox/Additions/3D/win/VBoxGL')
-rw-r--r-- | src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.cpp | 1396 | ||||
-rw-r--r-- | src/VBox/Additions/3D/win/VBoxGL/GaDrvEnvKMT.h | 58 | ||||
-rw-r--r-- | src/VBox/Additions/3D/win/VBoxGL/Makefile.kmk | 87 | ||||
-rw-r--r-- | src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c | 580 | ||||
-rw-r--r-- | src/VBox/Additions/3D/win/VBoxGL/VBoxGL.rc | 66 |
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 |