diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp')
-rw-r--r-- | src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp | 10277 |
1 files changed, 10277 insertions, 0 deletions
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp new file mode 100644 index 00000000..9802b570 --- /dev/null +++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-dx-dx11.cpp @@ -0,0 +1,10277 @@ +/* $Id: DevVGA-SVGA3d-dx-dx11.cpp $ */ +/** @file + * DevVMWare - VMWare SVGA device + */ + +/* + * Copyright (C) 2020-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 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV_VMSVGA +#include <VBox/AssertGuest.h> +#include <VBox/log.h> +#include <VBox/vmm/pdmdev.h> +#include <VBox/vmm/pgm.h> + +#include <iprt/assert.h> +#include <iprt/avl.h> +#include <iprt/errcore.h> +#include <iprt/mem.h> + +#include <VBoxVideo.h> /* required by DevVGA.h */ +#include <VBoxVideo3D.h> + +/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */ +#include "DevVGA.h" + +#include "DevVGA-SVGA.h" +#include "DevVGA-SVGA3d.h" +#include "DevVGA-SVGA3d-internal.h" +#include "DevVGA-SVGA3d-dx-shader.h" + +/* d3d11_1.h has a structure field named 'Status' but Status is defined as int on Linux host */ +#if defined(Status) +#undef Status +#endif +#include <d3d11_1.h> + + +#ifdef RT_OS_WINDOWS +# define VBOX_D3D11_LIBRARY_NAME "d3d11" +#else +# define VBOX_D3D11_LIBRARY_NAME "VBoxDxVk" +#endif + +/* One ID3D11Device object is used for all VMSVGA contexts. */ +/** @todo This should be the only option because VGPU freely uses surfaces from different VMSVGA contexts + * and synchronization of access to shared surfaces kills performance. + */ +#define DX_FORCE_SINGLE_DEVICE +/* A single staging ID3D11Buffer is used for uploading data to other buffers. */ +#define DX_COMMON_STAGING_BUFFER +/* Always flush after submitting a draw call for debugging. */ +//#define DX_FLUSH_AFTER_DRAW + +/* This is not available on non Windows hosts. */ +#ifndef D3D_RELEASE +# define D3D_RELEASE(a_Ptr) do { if ((a_Ptr)) (a_Ptr)->Release(); (a_Ptr) = NULL; } while (0) +#endif + +/** Fake ID for the backend DX context. The context creates all shared textures. */ +#define DX_CID_BACKEND UINT32_C(0xfffffffe) + +#define D3D_RELEASE_ARRAY(a_Count, a_papArray) do { \ + for (uint32_t i = 0; i < (a_Count); ++i) \ + D3D_RELEASE((a_papArray)[i]); \ +} while (0) + +typedef struct D3D11BLITTER +{ + ID3D11Device1 *pDevice; + ID3D11DeviceContext1 *pImmediateContext; + + ID3D11VertexShader *pVertexShader; + ID3D11PixelShader *pPixelShader; + ID3D11SamplerState *pSamplerState; + ID3D11RasterizerState1 *pRasterizerState; + ID3D11BlendState1 *pBlendState; +} D3D11BLITTER; + +typedef struct DXDEVICE +{ + ID3D11Device1 *pDevice; /* Device. */ + ID3D11DeviceContext1 *pImmediateContext; /* Corresponding context. */ + IDXGIFactory *pDxgiFactory; /* DXGI Factory. */ + D3D_FEATURE_LEVEL FeatureLevel; + +#ifdef DX_COMMON_STAGING_BUFFER + /* Staging buffer for transfer to surface buffers. */ + ID3D11Buffer *pStagingBuffer; /* The staging buffer resource. */ + uint32_t cbStagingBuffer; /* Current size of the staging buffer resource. */ +#endif + + D3D11BLITTER Blitter; /* Blits one texture to another. */ +} DXDEVICE; + +/* Kind of a texture view. */ +typedef enum VMSVGA3DBACKVIEWTYPE +{ + VMSVGA3D_VIEWTYPE_NONE = 0, + VMSVGA3D_VIEWTYPE_RENDERTARGET = 1, + VMSVGA3D_VIEWTYPE_DEPTHSTENCIL = 2, + VMSVGA3D_VIEWTYPE_SHADERRESOURCE = 3, + VMSVGA3D_VIEWTYPE_UNORDEREDACCESS = 4 +} VMSVGA3DBACKVIEWTYPE; + +/* Information about a texture view to track all created views:. + * when a surface is invalidated, then all views must deleted; + * when a view is deleted, then the view must be unlinked from the surface. + */ +typedef struct DXVIEWINFO +{ + uint32_t sid; /* Surface which the view was created for. */ + uint32_t cid; /* DX context which created the view. */ + uint32_t viewId; /* View id assigned by the guest. */ + VMSVGA3DBACKVIEWTYPE enmViewType; +} DXVIEWINFO; + +/* Context Object Table element for a texture view. */ +typedef struct DXVIEW +{ + uint32_t cid; /* DX context which created the view. */ + uint32_t sid; /* Surface which the view was created for. */ + uint32_t viewId; /* View id assigned by the guest. */ + VMSVGA3DBACKVIEWTYPE enmViewType; + + union + { + ID3D11View *pView; /* The view object. */ + ID3D11RenderTargetView *pRenderTargetView; + ID3D11DepthStencilView *pDepthStencilView; + ID3D11ShaderResourceView *pShaderResourceView; + ID3D11UnorderedAccessView *pUnorderedAccessView; + } u; + + RTLISTNODE nodeSurfaceView; /* Views are linked to the surface. */ +} DXVIEW; + +/* What kind of resource has been created for the VMSVGA3D surface. */ +typedef enum VMSVGA3DBACKRESTYPE +{ + VMSVGA3D_RESTYPE_NONE = 0, + VMSVGA3D_RESTYPE_TEXTURE_1D = 1, + VMSVGA3D_RESTYPE_TEXTURE_2D = 2, + VMSVGA3D_RESTYPE_TEXTURE_CUBE = 3, + VMSVGA3D_RESTYPE_TEXTURE_3D = 4, + VMSVGA3D_RESTYPE_BUFFER = 5, +} VMSVGA3DBACKRESTYPE; + +typedef struct VMSVGA3DBACKENDSURFACE +{ + VMSVGA3DBACKRESTYPE enmResType; + DXGI_FORMAT enmDxgiFormat; + union + { + ID3D11Resource *pResource; + ID3D11Texture1D *pTexture1D; + ID3D11Texture2D *pTexture2D; + ID3D11Texture3D *pTexture3D; + ID3D11Buffer *pBuffer; + } u; + + /* For updates from memory. */ + union /** @todo One per format. */ + { + ID3D11Resource *pResource; + ID3D11Texture1D *pTexture1D; + ID3D11Texture2D *pTexture2D; + ID3D11Texture3D *pTexture3D; +#ifndef DX_COMMON_STAGING_BUFFER + ID3D11Buffer *pBuffer; +#endif + } dynamic; + + /* For reading the texture content. */ + union /** @todo One per format. */ + { + ID3D11Resource *pResource; + ID3D11Texture1D *pTexture1D; + ID3D11Texture2D *pTexture2D; + ID3D11Texture3D *pTexture3D; +#ifndef DX_COMMON_STAGING_BUFFER + ID3D11Buffer *pBuffer; +#endif + } staging; + + /* Screen targets are created as shared surfaces. */ + HANDLE SharedHandle; /* The shared handle of this structure. */ + + /* DX context which last rendered to the texture. + * This is only for render targets and screen targets, which can be shared between contexts. + * The backend context (cid == DX_CID_BACKEND) can also be a drawing context. + */ + uint32_t cidDrawing; + + /** AVL tree containing DXSHAREDTEXTURE structures. */ + AVLU32TREE SharedTextureTree; + + /* Render target views, depth stencil views and shader resource views created for this texture or buffer. */ + RTLISTANCHOR listView; /* DXVIEW */ + +} VMSVGA3DBACKENDSURFACE; + +/* "The only resources that can be shared are 2D non-mipmapped textures." */ +typedef struct DXSHAREDTEXTURE +{ + AVLU32NODECORE Core; /* Key is context id which opened this texture. */ + ID3D11Texture2D *pTexture; /* The opened shared texture. */ + uint32_t sid; /* Surface id. */ +} DXSHAREDTEXTURE; + + +typedef struct VMSVGAHWSCREEN +{ + ID3D11Texture2D *pTexture; /* Shared texture for the screen content. Only used as CopyResource target. */ + IDXGIResource *pDxgiResource; /* Interface of the texture. */ + IDXGIKeyedMutex *pDXGIKeyedMutex; /* Synchronization interface for the render device. */ + HANDLE SharedHandle; /* The shared handle of this structure. */ + uint32_t sidScreenTarget; /* The source surface for this screen. */ +} VMSVGAHWSCREEN; + + +typedef struct DXELEMENTLAYOUT +{ + ID3D11InputLayout *pElementLayout; + uint32_t cElementDesc; + D3D11_INPUT_ELEMENT_DESC aElementDesc[32]; +} DXELEMENTLAYOUT; + +typedef struct DXSHADER +{ + SVGA3dShaderType enmShaderType; + union + { + ID3D11DeviceChild *pShader; /* All. */ + ID3D11VertexShader *pVertexShader; /* SVGA3D_SHADERTYPE_VS */ + ID3D11PixelShader *pPixelShader; /* SVGA3D_SHADERTYPE_PS */ + ID3D11GeometryShader *pGeometryShader; /* SVGA3D_SHADERTYPE_GS */ + ID3D11HullShader *pHullShader; /* SVGA3D_SHADERTYPE_HS */ + ID3D11DomainShader *pDomainShader; /* SVGA3D_SHADERTYPE_DS */ + ID3D11ComputeShader *pComputeShader; /* SVGA3D_SHADERTYPE_CS */ + }; + void *pvDXBC; + uint32_t cbDXBC; + + uint32_t soid; /* Stream output declarations for geometry shaders. */ + + DXShaderInfo shaderInfo; +} DXSHADER; + +typedef struct DXQUERY +{ + union + { + ID3D11Query *pQuery; + ID3D11Predicate *pPredicate; + }; +} DXQUERY; + +typedef struct DXSTREAMOUTPUT +{ + UINT cDeclarationEntry; + D3D11_SO_DECLARATION_ENTRY aDeclarationEntry[SVGA3D_MAX_STREAMOUT_DECLS]; +} DXSTREAMOUTPUT; + +typedef struct DXBOUNDVERTEXBUFFER +{ + ID3D11Buffer *pBuffer; + uint32_t stride; + uint32_t offset; +} DXBOUNDVERTEXBUFFER; + +typedef struct DXBOUNDINDEXBUFFER +{ + ID3D11Buffer *pBuffer; + DXGI_FORMAT indexBufferFormat; + uint32_t indexBufferOffset; +} DXBOUNDINDEXBUFFER; + +typedef struct DXBOUNDRESOURCES /* Currently bound resources. Mirror SVGADXContextMobFormat structure. */ +{ + struct + { + DXBOUNDVERTEXBUFFER vertexBuffers[SVGA3D_DX_MAX_VERTEXBUFFERS]; + DXBOUNDINDEXBUFFER indexBuffer; + } inputAssembly; + struct + { + ID3D11Buffer *constantBuffers[SVGA3D_DX_MAX_CONSTBUFFERS]; + } shaderState[SVGA3D_NUM_SHADERTYPE]; +} DXBOUNDRESOURCES; + + +typedef struct VMSVGA3DBACKENDDXCONTEXT +{ + DXDEVICE dxDevice; /* DX device interfaces for this context operations. */ + + /* Arrays for Context-Object Tables. Number of entries depends on COTable size. */ + uint32_t cBlendState; /* Number of entries in the papBlendState array. */ + uint32_t cDepthStencilState; /* papDepthStencilState */ + uint32_t cSamplerState; /* papSamplerState */ + uint32_t cRasterizerState; /* papRasterizerState */ + uint32_t cElementLayout; /* paElementLayout */ + uint32_t cRenderTargetView; /* paRenderTargetView */ + uint32_t cDepthStencilView; /* paDepthStencilView */ + uint32_t cShaderResourceView; /* paShaderResourceView */ + uint32_t cQuery; /* paQuery */ + uint32_t cShader; /* paShader */ + uint32_t cStreamOutput; /* paStreamOutput */ + uint32_t cUnorderedAccessView; /* paUnorderedAccessView */ + ID3D11BlendState1 **papBlendState; + ID3D11DepthStencilState **papDepthStencilState; + ID3D11SamplerState **papSamplerState; + ID3D11RasterizerState1 **papRasterizerState; + DXELEMENTLAYOUT *paElementLayout; + DXVIEW *paRenderTargetView; + DXVIEW *paDepthStencilView; + DXVIEW *paShaderResourceView; + DXQUERY *paQuery; + DXSHADER *paShader; + DXSTREAMOUTPUT *paStreamOutput; + DXVIEW *paUnorderedAccessView; + + uint32_t cSOTarget; /* How many SO targets are currently set (SetSOTargets) */ + + DXBOUNDRESOURCES resources; +} VMSVGA3DBACKENDDXCONTEXT; + +/* Shader disassembler function. Optional. */ +typedef HRESULT FN_D3D_DISASSEMBLE(LPCVOID pSrcData, SIZE_T SrcDataSize, UINT Flags, LPCSTR szComments, ID3D10Blob **ppDisassembly); +typedef FN_D3D_DISASSEMBLE *PFN_D3D_DISASSEMBLE; + +typedef struct VMSVGA3DBACKEND +{ + RTLDRMOD hD3D11; + PFN_D3D11_CREATE_DEVICE pfnD3D11CreateDevice; + + RTLDRMOD hD3DCompiler; + PFN_D3D_DISASSEMBLE pfnD3DDisassemble; + + DXDEVICE dxDevice; /* Device for the VMSVGA3D context independent operation. */ + + DXBOUNDRESOURCES resources; /* What is currently applied to the pipeline. */ + + bool fSingleDevice; /* Whether to use one DX device for all guest contexts. */ + + /** @todo Here a set of functions which do different job in single and multiple device modes. */ +} VMSVGA3DBACKEND; + + +/* Static function prototypes. */ +static int dxDeviceFlush(DXDEVICE *pDevice); +static int dxDefineShaderResourceView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderResourceViewId shaderResourceViewId, SVGACOTableDXSRViewEntry const *pEntry); +static int dxDefineUnorderedAccessView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId, SVGACOTableDXUAViewEntry const *pEntry); +static int dxDefineRenderTargetView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId, SVGACOTableDXRTViewEntry const *pEntry); +static int dxDefineDepthStencilView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilViewId depthStencilViewId, SVGACOTableDXDSViewEntry const *pEntry); +static int dxSetRenderTargets(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext); +static int dxSetCSUnorderedAccessViews(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext); +static DECLCALLBACK(void) vmsvga3dBackSurfaceDestroy(PVGASTATECC pThisCC, bool fClearCOTableEntry, PVMSVGA3DSURFACE pSurface); +static int dxDestroyShader(DXSHADER *pDXShader); +static int dxDestroyQuery(DXQUERY *pDXQuery); +static int dxReadBuffer(DXDEVICE *pDevice, ID3D11Buffer *pBuffer, UINT Offset, UINT Bytes, void **ppvData, uint32_t *pcbData); + +static HRESULT BlitInit(D3D11BLITTER *pBlitter, ID3D11Device1 *pDevice, ID3D11DeviceContext1 *pImmediateContext); +static void BlitRelease(D3D11BLITTER *pBlitter); + + +/* This is not available with the DXVK headers for some reason. */ +#ifndef RT_OS_WINDOWS +typedef enum D3D11_TEXTURECUBE_FACE { + D3D11_TEXTURECUBE_FACE_POSITIVE_X, + D3D11_TEXTURECUBE_FACE_NEGATIVE_X, + D3D11_TEXTURECUBE_FACE_POSITIVE_Y, + D3D11_TEXTURECUBE_FACE_NEGATIVE_Y, + D3D11_TEXTURECUBE_FACE_POSITIVE_Z, + D3D11_TEXTURECUBE_FACE_NEGATIVE_Z +} D3D11_TEXTURECUBE_FACE; +#endif + + +DECLINLINE(D3D11_TEXTURECUBE_FACE) vmsvga3dCubemapFaceFromIndex(uint32_t iFace) +{ + D3D11_TEXTURECUBE_FACE Face; + switch (iFace) + { + case 0: Face = D3D11_TEXTURECUBE_FACE_POSITIVE_X; break; + case 1: Face = D3D11_TEXTURECUBE_FACE_NEGATIVE_X; break; + case 2: Face = D3D11_TEXTURECUBE_FACE_POSITIVE_Y; break; + case 3: Face = D3D11_TEXTURECUBE_FACE_NEGATIVE_Y; break; + case 4: Face = D3D11_TEXTURECUBE_FACE_POSITIVE_Z; break; + default: + case 5: Face = D3D11_TEXTURECUBE_FACE_NEGATIVE_Z; break; + } + return Face; +} + +/* This is to workaround issues with X8 formats, because they can't be used in some operations. */ +#define DX_REPLACE_X8_WITH_A8 +static DXGI_FORMAT vmsvgaDXSurfaceFormat2Dxgi(SVGA3dSurfaceFormat format) +{ + /* Ensure that correct headers are used. + * SVGA3D_AYUV was equal to 45, then replaced with SVGA3D_FORMAT_DEAD2 = 45, and redefined as SVGA3D_AYUV = 152. + */ + AssertCompile(SVGA3D_AYUV == 152); + +#define DXGI_FORMAT_ DXGI_FORMAT_UNKNOWN + /** @todo More formats. */ + switch (format) + { +#ifdef DX_REPLACE_X8_WITH_A8 + case SVGA3D_X8R8G8B8: return DXGI_FORMAT_B8G8R8A8_UNORM; +#else + case SVGA3D_X8R8G8B8: return DXGI_FORMAT_B8G8R8X8_UNORM; +#endif + case SVGA3D_A8R8G8B8: return DXGI_FORMAT_B8G8R8A8_UNORM; + case SVGA3D_R5G6B5: return DXGI_FORMAT_B5G6R5_UNORM; + case SVGA3D_X1R5G5B5: return DXGI_FORMAT_B5G5R5A1_UNORM; + case SVGA3D_A1R5G5B5: return DXGI_FORMAT_B5G5R5A1_UNORM; + case SVGA3D_A4R4G4B4: break; // 11.1 return DXGI_FORMAT_B4G4R4A4_UNORM; + case SVGA3D_Z_D32: break; + case SVGA3D_Z_D16: return DXGI_FORMAT_D16_UNORM; + case SVGA3D_Z_D24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case SVGA3D_Z_D15S1: break; + case SVGA3D_LUMINANCE8: return DXGI_FORMAT_; + case SVGA3D_LUMINANCE4_ALPHA4: return DXGI_FORMAT_; + case SVGA3D_LUMINANCE16: return DXGI_FORMAT_; + case SVGA3D_LUMINANCE8_ALPHA8: return DXGI_FORMAT_; + case SVGA3D_DXT1: return DXGI_FORMAT_; + case SVGA3D_DXT2: return DXGI_FORMAT_; + case SVGA3D_DXT3: return DXGI_FORMAT_; + case SVGA3D_DXT4: return DXGI_FORMAT_; + case SVGA3D_DXT5: return DXGI_FORMAT_; + case SVGA3D_BUMPU8V8: return DXGI_FORMAT_; + case SVGA3D_BUMPL6V5U5: return DXGI_FORMAT_; + case SVGA3D_BUMPX8L8V8U8: return DXGI_FORMAT_; + case SVGA3D_FORMAT_DEAD1: break; + case SVGA3D_ARGB_S10E5: return DXGI_FORMAT_; + case SVGA3D_ARGB_S23E8: return DXGI_FORMAT_; + case SVGA3D_A2R10G10B10: return DXGI_FORMAT_; + case SVGA3D_V8U8: return DXGI_FORMAT_; + case SVGA3D_Q8W8V8U8: return DXGI_FORMAT_; + case SVGA3D_CxV8U8: return DXGI_FORMAT_; + case SVGA3D_X8L8V8U8: return DXGI_FORMAT_; + case SVGA3D_A2W10V10U10: return DXGI_FORMAT_; + case SVGA3D_ALPHA8: return DXGI_FORMAT_; + case SVGA3D_R_S10E5: return DXGI_FORMAT_; + case SVGA3D_R_S23E8: return DXGI_FORMAT_; + case SVGA3D_RG_S10E5: return DXGI_FORMAT_; + case SVGA3D_RG_S23E8: return DXGI_FORMAT_; + case SVGA3D_BUFFER: return DXGI_FORMAT_; + case SVGA3D_Z_D24X8: return DXGI_FORMAT_; + case SVGA3D_V16U16: return DXGI_FORMAT_; + case SVGA3D_G16R16: return DXGI_FORMAT_; + case SVGA3D_A16B16G16R16: return DXGI_FORMAT_; + case SVGA3D_UYVY: return DXGI_FORMAT_; + case SVGA3D_YUY2: return DXGI_FORMAT_; + case SVGA3D_NV12: return DXGI_FORMAT_; + case SVGA3D_FORMAT_DEAD2: break; /* Old SVGA3D_AYUV */ + case SVGA3D_R32G32B32A32_TYPELESS: return DXGI_FORMAT_R32G32B32A32_TYPELESS; + case SVGA3D_R32G32B32A32_UINT: return DXGI_FORMAT_R32G32B32A32_UINT; + case SVGA3D_R32G32B32A32_SINT: return DXGI_FORMAT_R32G32B32A32_SINT; + case SVGA3D_R32G32B32_TYPELESS: return DXGI_FORMAT_R32G32B32_TYPELESS; + case SVGA3D_R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT; + case SVGA3D_R32G32B32_UINT: return DXGI_FORMAT_R32G32B32_UINT; + case SVGA3D_R32G32B32_SINT: return DXGI_FORMAT_R32G32B32_SINT; + case SVGA3D_R16G16B16A16_TYPELESS: return DXGI_FORMAT_R16G16B16A16_TYPELESS; + case SVGA3D_R16G16B16A16_UINT: return DXGI_FORMAT_R16G16B16A16_UINT; + case SVGA3D_R16G16B16A16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; + case SVGA3D_R16G16B16A16_SINT: return DXGI_FORMAT_R16G16B16A16_SINT; + case SVGA3D_R32G32_TYPELESS: return DXGI_FORMAT_R32G32_TYPELESS; + case SVGA3D_R32G32_UINT: return DXGI_FORMAT_R32G32_UINT; + case SVGA3D_R32G32_SINT: return DXGI_FORMAT_R32G32_SINT; + case SVGA3D_R32G8X24_TYPELESS: return DXGI_FORMAT_R32G8X24_TYPELESS; + case SVGA3D_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + case SVGA3D_R32_FLOAT_X8X24: return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + case SVGA3D_X32_G8X24_UINT: return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + case SVGA3D_R10G10B10A2_TYPELESS: return DXGI_FORMAT_R10G10B10A2_TYPELESS; + case SVGA3D_R10G10B10A2_UINT: return DXGI_FORMAT_R10G10B10A2_UINT; + case SVGA3D_R11G11B10_FLOAT: return DXGI_FORMAT_R11G11B10_FLOAT; + case SVGA3D_R8G8B8A8_TYPELESS: return DXGI_FORMAT_R8G8B8A8_TYPELESS; + case SVGA3D_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case SVGA3D_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case SVGA3D_R8G8B8A8_UINT: return DXGI_FORMAT_R8G8B8A8_UINT; + case SVGA3D_R8G8B8A8_SINT: return DXGI_FORMAT_R8G8B8A8_SINT; + case SVGA3D_R16G16_TYPELESS: return DXGI_FORMAT_R16G16_TYPELESS; + case SVGA3D_R16G16_UINT: return DXGI_FORMAT_R16G16_UINT; + case SVGA3D_R16G16_SINT: return DXGI_FORMAT_R16G16_SINT; + case SVGA3D_R32_TYPELESS: return DXGI_FORMAT_R32_TYPELESS; + case SVGA3D_D32_FLOAT: return DXGI_FORMAT_D32_FLOAT; + case SVGA3D_R32_UINT: return DXGI_FORMAT_R32_UINT; + case SVGA3D_R32_SINT: return DXGI_FORMAT_R32_SINT; + case SVGA3D_R24G8_TYPELESS: return DXGI_FORMAT_R24G8_TYPELESS; + case SVGA3D_D24_UNORM_S8_UINT: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case SVGA3D_R24_UNORM_X8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + case SVGA3D_X24_G8_UINT: return DXGI_FORMAT_X24_TYPELESS_G8_UINT; + case SVGA3D_R8G8_TYPELESS: return DXGI_FORMAT_R8G8_TYPELESS; + case SVGA3D_R8G8_UNORM: return DXGI_FORMAT_R8G8_UNORM; + case SVGA3D_R8G8_UINT: return DXGI_FORMAT_R8G8_UINT; + case SVGA3D_R8G8_SINT: return DXGI_FORMAT_R8G8_SINT; + case SVGA3D_R16_TYPELESS: return DXGI_FORMAT_R16_TYPELESS; + case SVGA3D_R16_UNORM: return DXGI_FORMAT_R16_UNORM; + case SVGA3D_R16_UINT: return DXGI_FORMAT_R16_UINT; + case SVGA3D_R16_SNORM: return DXGI_FORMAT_R16_SNORM; + case SVGA3D_R16_SINT: return DXGI_FORMAT_R16_SINT; + case SVGA3D_R8_TYPELESS: return DXGI_FORMAT_R8_TYPELESS; + case SVGA3D_R8_UNORM: return DXGI_FORMAT_R8_UNORM; + case SVGA3D_R8_UINT: return DXGI_FORMAT_R8_UINT; + case SVGA3D_R8_SNORM: return DXGI_FORMAT_R8_SNORM; + case SVGA3D_R8_SINT: return DXGI_FORMAT_R8_SINT; + case SVGA3D_P8: break; + case SVGA3D_R9G9B9E5_SHAREDEXP: return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; + case SVGA3D_R8G8_B8G8_UNORM: return DXGI_FORMAT_R8G8_B8G8_UNORM; + case SVGA3D_G8R8_G8B8_UNORM: return DXGI_FORMAT_G8R8_G8B8_UNORM; + case SVGA3D_BC1_TYPELESS: return DXGI_FORMAT_BC1_TYPELESS; + case SVGA3D_BC1_UNORM_SRGB: return DXGI_FORMAT_BC1_UNORM_SRGB; + case SVGA3D_BC2_TYPELESS: return DXGI_FORMAT_BC2_TYPELESS; + case SVGA3D_BC2_UNORM_SRGB: return DXGI_FORMAT_BC2_UNORM_SRGB; + case SVGA3D_BC3_TYPELESS: return DXGI_FORMAT_BC3_TYPELESS; + case SVGA3D_BC3_UNORM_SRGB: return DXGI_FORMAT_BC3_UNORM_SRGB; + case SVGA3D_BC4_TYPELESS: return DXGI_FORMAT_BC4_TYPELESS; + case SVGA3D_ATI1: break; + case SVGA3D_BC4_SNORM: return DXGI_FORMAT_BC4_SNORM; + case SVGA3D_BC5_TYPELESS: return DXGI_FORMAT_BC5_TYPELESS; + case SVGA3D_ATI2: break; + case SVGA3D_BC5_SNORM: return DXGI_FORMAT_BC5_SNORM; + case SVGA3D_R10G10B10_XR_BIAS_A2_UNORM: return DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM; + case SVGA3D_B8G8R8A8_TYPELESS: return DXGI_FORMAT_B8G8R8A8_TYPELESS; + case SVGA3D_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; +#ifdef DX_REPLACE_X8_WITH_A8 + case SVGA3D_B8G8R8X8_TYPELESS: return DXGI_FORMAT_B8G8R8A8_TYPELESS; + case SVGA3D_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; +#else + case SVGA3D_B8G8R8X8_TYPELESS: return DXGI_FORMAT_B8G8R8X8_TYPELESS; + case SVGA3D_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; +#endif + case SVGA3D_Z_DF16: break; + case SVGA3D_Z_DF24: break; + case SVGA3D_Z_D24S8_INT: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case SVGA3D_YV12: break; + case SVGA3D_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case SVGA3D_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case SVGA3D_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case SVGA3D_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; + case SVGA3D_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; + case SVGA3D_R8G8B8A8_SNORM: return DXGI_FORMAT_R8G8B8A8_SNORM; + case SVGA3D_R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case SVGA3D_R16G16_UNORM: return DXGI_FORMAT_R16G16_UNORM; + case SVGA3D_R16G16_SNORM: return DXGI_FORMAT_R16G16_SNORM; + case SVGA3D_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case SVGA3D_R8G8_SNORM: return DXGI_FORMAT_R8G8_SNORM; + case SVGA3D_R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case SVGA3D_D16_UNORM: return DXGI_FORMAT_D16_UNORM; + case SVGA3D_A8_UNORM: return DXGI_FORMAT_A8_UNORM; + case SVGA3D_BC1_UNORM: return DXGI_FORMAT_BC1_UNORM; + case SVGA3D_BC2_UNORM: return DXGI_FORMAT_BC2_UNORM; + case SVGA3D_BC3_UNORM: return DXGI_FORMAT_BC3_UNORM; + case SVGA3D_B5G6R5_UNORM: return DXGI_FORMAT_B5G6R5_UNORM; + case SVGA3D_B5G5R5A1_UNORM: return DXGI_FORMAT_B5G5R5A1_UNORM; + case SVGA3D_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; +#ifdef DX_REPLACE_X8_WITH_A8 + case SVGA3D_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; +#else + case SVGA3D_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8X8_UNORM; +#endif + case SVGA3D_BC4_UNORM: return DXGI_FORMAT_BC4_UNORM; + case SVGA3D_BC5_UNORM: return DXGI_FORMAT_BC5_UNORM; + + case SVGA3D_B4G4R4A4_UNORM: return DXGI_FORMAT_; + case SVGA3D_BC6H_TYPELESS: return DXGI_FORMAT_BC6H_TYPELESS; + case SVGA3D_BC6H_UF16: return DXGI_FORMAT_BC6H_UF16; + case SVGA3D_BC6H_SF16: return DXGI_FORMAT_BC6H_SF16; + case SVGA3D_BC7_TYPELESS: return DXGI_FORMAT_BC7_TYPELESS; + case SVGA3D_BC7_UNORM: return DXGI_FORMAT_BC7_UNORM; + case SVGA3D_BC7_UNORM_SRGB: return DXGI_FORMAT_BC7_UNORM_SRGB; + case SVGA3D_AYUV: return DXGI_FORMAT_; + + case SVGA3D_FORMAT_INVALID: + case SVGA3D_FORMAT_MAX: break; + } + // AssertFailed(); + return DXGI_FORMAT_UNKNOWN; +#undef DXGI_FORMAT_ +} + + +static SVGA3dSurfaceFormat vmsvgaDXDevCapSurfaceFmt2Format(SVGA3dDevCapIndex enmDevCap) +{ + switch (enmDevCap) + { + case SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8: return SVGA3D_X8R8G8B8; + case SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8: return SVGA3D_A8R8G8B8; + case SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10: return SVGA3D_A2R10G10B10; + case SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5: return SVGA3D_X1R5G5B5; + case SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5: return SVGA3D_A1R5G5B5; + case SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4: return SVGA3D_A4R4G4B4; + case SVGA3D_DEVCAP_SURFACEFMT_R5G6B5: return SVGA3D_R5G6B5; + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16: return SVGA3D_LUMINANCE16; + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8: return SVGA3D_LUMINANCE8_ALPHA8; + case SVGA3D_DEVCAP_SURFACEFMT_ALPHA8: return SVGA3D_ALPHA8; + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8: return SVGA3D_LUMINANCE8; + case SVGA3D_DEVCAP_SURFACEFMT_Z_D16: return SVGA3D_Z_D16; + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8: return SVGA3D_Z_D24S8; + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8: return SVGA3D_Z_D24X8; + case SVGA3D_DEVCAP_SURFACEFMT_DXT1: return SVGA3D_DXT1; + case SVGA3D_DEVCAP_SURFACEFMT_DXT2: return SVGA3D_DXT2; + case SVGA3D_DEVCAP_SURFACEFMT_DXT3: return SVGA3D_DXT3; + case SVGA3D_DEVCAP_SURFACEFMT_DXT4: return SVGA3D_DXT4; + case SVGA3D_DEVCAP_SURFACEFMT_DXT5: return SVGA3D_DXT5; + case SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8: return SVGA3D_BUMPX8L8V8U8; + case SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10: return SVGA3D_A2W10V10U10; + case SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8: return SVGA3D_BUMPU8V8; + case SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8: return SVGA3D_Q8W8V8U8; + case SVGA3D_DEVCAP_SURFACEFMT_CxV8U8: return SVGA3D_CxV8U8; + case SVGA3D_DEVCAP_SURFACEFMT_R_S10E5: return SVGA3D_R_S10E5; + case SVGA3D_DEVCAP_SURFACEFMT_R_S23E8: return SVGA3D_R_S23E8; + case SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5: return SVGA3D_RG_S10E5; + case SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8: return SVGA3D_RG_S23E8; + case SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5: return SVGA3D_ARGB_S10E5; + case SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8: return SVGA3D_ARGB_S23E8; + case SVGA3D_DEVCAP_SURFACEFMT_V16U16: return SVGA3D_V16U16; + case SVGA3D_DEVCAP_SURFACEFMT_G16R16: return SVGA3D_G16R16; + case SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16: return SVGA3D_A16B16G16R16; + case SVGA3D_DEVCAP_SURFACEFMT_UYVY: return SVGA3D_UYVY; + case SVGA3D_DEVCAP_SURFACEFMT_YUY2: return SVGA3D_YUY2; + case SVGA3D_DEVCAP_SURFACEFMT_NV12: return SVGA3D_NV12; + case SVGA3D_DEVCAP_DEAD10: return SVGA3D_FORMAT_DEAD2; /* SVGA3D_DEVCAP_SURFACEFMT_AYUV -> SVGA3D_AYUV */ + case SVGA3D_DEVCAP_SURFACEFMT_Z_DF16: return SVGA3D_Z_DF16; + case SVGA3D_DEVCAP_SURFACEFMT_Z_DF24: return SVGA3D_Z_DF24; + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT: return SVGA3D_Z_D24S8_INT; + case SVGA3D_DEVCAP_SURFACEFMT_ATI1: return SVGA3D_ATI1; + case SVGA3D_DEVCAP_SURFACEFMT_ATI2: return SVGA3D_ATI2; + case SVGA3D_DEVCAP_SURFACEFMT_YV12: return SVGA3D_YV12; + default: + AssertFailed(); + break; + } + return SVGA3D_FORMAT_INVALID; +} + + +static SVGA3dSurfaceFormat vmsvgaDXDevCapDxfmt2Format(SVGA3dDevCapIndex enmDevCap) +{ + switch (enmDevCap) + { + case SVGA3D_DEVCAP_DXFMT_X8R8G8B8: return SVGA3D_X8R8G8B8; + case SVGA3D_DEVCAP_DXFMT_A8R8G8B8: return SVGA3D_A8R8G8B8; + case SVGA3D_DEVCAP_DXFMT_R5G6B5: return SVGA3D_R5G6B5; + case SVGA3D_DEVCAP_DXFMT_X1R5G5B5: return SVGA3D_X1R5G5B5; + case SVGA3D_DEVCAP_DXFMT_A1R5G5B5: return SVGA3D_A1R5G5B5; + case SVGA3D_DEVCAP_DXFMT_A4R4G4B4: return SVGA3D_A4R4G4B4; + case SVGA3D_DEVCAP_DXFMT_Z_D32: return SVGA3D_Z_D32; + case SVGA3D_DEVCAP_DXFMT_Z_D16: return SVGA3D_Z_D16; + case SVGA3D_DEVCAP_DXFMT_Z_D24S8: return SVGA3D_Z_D24S8; + case SVGA3D_DEVCAP_DXFMT_Z_D15S1: return SVGA3D_Z_D15S1; + case SVGA3D_DEVCAP_DXFMT_LUMINANCE8: return SVGA3D_LUMINANCE8; + case SVGA3D_DEVCAP_DXFMT_LUMINANCE4_ALPHA4: return SVGA3D_LUMINANCE4_ALPHA4; + case SVGA3D_DEVCAP_DXFMT_LUMINANCE16: return SVGA3D_LUMINANCE16; + case SVGA3D_DEVCAP_DXFMT_LUMINANCE8_ALPHA8: return SVGA3D_LUMINANCE8_ALPHA8; + case SVGA3D_DEVCAP_DXFMT_DXT1: return SVGA3D_DXT1; + case SVGA3D_DEVCAP_DXFMT_DXT2: return SVGA3D_DXT2; + case SVGA3D_DEVCAP_DXFMT_DXT3: return SVGA3D_DXT3; + case SVGA3D_DEVCAP_DXFMT_DXT4: return SVGA3D_DXT4; + case SVGA3D_DEVCAP_DXFMT_DXT5: return SVGA3D_DXT5; + case SVGA3D_DEVCAP_DXFMT_BUMPU8V8: return SVGA3D_BUMPU8V8; + case SVGA3D_DEVCAP_DXFMT_BUMPL6V5U5: return SVGA3D_BUMPL6V5U5; + case SVGA3D_DEVCAP_DXFMT_BUMPX8L8V8U8: return SVGA3D_BUMPX8L8V8U8; + case SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD1: return SVGA3D_FORMAT_DEAD1; + case SVGA3D_DEVCAP_DXFMT_ARGB_S10E5: return SVGA3D_ARGB_S10E5; + case SVGA3D_DEVCAP_DXFMT_ARGB_S23E8: return SVGA3D_ARGB_S23E8; + case SVGA3D_DEVCAP_DXFMT_A2R10G10B10: return SVGA3D_A2R10G10B10; + case SVGA3D_DEVCAP_DXFMT_V8U8: return SVGA3D_V8U8; + case SVGA3D_DEVCAP_DXFMT_Q8W8V8U8: return SVGA3D_Q8W8V8U8; + case SVGA3D_DEVCAP_DXFMT_CxV8U8: return SVGA3D_CxV8U8; + case SVGA3D_DEVCAP_DXFMT_X8L8V8U8: return SVGA3D_X8L8V8U8; + case SVGA3D_DEVCAP_DXFMT_A2W10V10U10: return SVGA3D_A2W10V10U10; + case SVGA3D_DEVCAP_DXFMT_ALPHA8: return SVGA3D_ALPHA8; + case SVGA3D_DEVCAP_DXFMT_R_S10E5: return SVGA3D_R_S10E5; + case SVGA3D_DEVCAP_DXFMT_R_S23E8: return SVGA3D_R_S23E8; + case SVGA3D_DEVCAP_DXFMT_RG_S10E5: return SVGA3D_RG_S10E5; + case SVGA3D_DEVCAP_DXFMT_RG_S23E8: return SVGA3D_RG_S23E8; + case SVGA3D_DEVCAP_DXFMT_BUFFER: return SVGA3D_BUFFER; + case SVGA3D_DEVCAP_DXFMT_Z_D24X8: return SVGA3D_Z_D24X8; + case SVGA3D_DEVCAP_DXFMT_V16U16: return SVGA3D_V16U16; + case SVGA3D_DEVCAP_DXFMT_G16R16: return SVGA3D_G16R16; + case SVGA3D_DEVCAP_DXFMT_A16B16G16R16: return SVGA3D_A16B16G16R16; + case SVGA3D_DEVCAP_DXFMT_UYVY: return SVGA3D_UYVY; + case SVGA3D_DEVCAP_DXFMT_YUY2: return SVGA3D_YUY2; + case SVGA3D_DEVCAP_DXFMT_NV12: return SVGA3D_NV12; + case SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD2: return SVGA3D_FORMAT_DEAD2; /* SVGA3D_DEVCAP_DXFMT_AYUV -> SVGA3D_AYUV */ + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_TYPELESS: return SVGA3D_R32G32B32A32_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_UINT: return SVGA3D_R32G32B32A32_UINT; + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_SINT: return SVGA3D_R32G32B32A32_SINT; + case SVGA3D_DEVCAP_DXFMT_R32G32B32_TYPELESS: return SVGA3D_R32G32B32_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R32G32B32_FLOAT: return SVGA3D_R32G32B32_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R32G32B32_UINT: return SVGA3D_R32G32B32_UINT; + case SVGA3D_DEVCAP_DXFMT_R32G32B32_SINT: return SVGA3D_R32G32B32_SINT; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_TYPELESS: return SVGA3D_R16G16B16A16_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UINT: return SVGA3D_R16G16B16A16_UINT; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SNORM: return SVGA3D_R16G16B16A16_SNORM; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SINT: return SVGA3D_R16G16B16A16_SINT; + case SVGA3D_DEVCAP_DXFMT_R32G32_TYPELESS: return SVGA3D_R32G32_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R32G32_UINT: return SVGA3D_R32G32_UINT; + case SVGA3D_DEVCAP_DXFMT_R32G32_SINT: return SVGA3D_R32G32_SINT; + case SVGA3D_DEVCAP_DXFMT_R32G8X24_TYPELESS: return SVGA3D_R32G8X24_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_D32_FLOAT_S8X24_UINT: return SVGA3D_D32_FLOAT_S8X24_UINT; + case SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24: return SVGA3D_R32_FLOAT_X8X24; + case SVGA3D_DEVCAP_DXFMT_X32_G8X24_UINT: return SVGA3D_X32_G8X24_UINT; + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_TYPELESS: return SVGA3D_R10G10B10A2_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UINT: return SVGA3D_R10G10B10A2_UINT; + case SVGA3D_DEVCAP_DXFMT_R11G11B10_FLOAT: return SVGA3D_R11G11B10_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_TYPELESS: return SVGA3D_R8G8B8A8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM: return SVGA3D_R8G8B8A8_UNORM; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM_SRGB: return SVGA3D_R8G8B8A8_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UINT: return SVGA3D_R8G8B8A8_UINT; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SINT: return SVGA3D_R8G8B8A8_SINT; + case SVGA3D_DEVCAP_DXFMT_R16G16_TYPELESS: return SVGA3D_R16G16_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R16G16_UINT: return SVGA3D_R16G16_UINT; + case SVGA3D_DEVCAP_DXFMT_R16G16_SINT: return SVGA3D_R16G16_SINT; + case SVGA3D_DEVCAP_DXFMT_R32_TYPELESS: return SVGA3D_R32_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_D32_FLOAT: return SVGA3D_D32_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R32_UINT: return SVGA3D_R32_UINT; + case SVGA3D_DEVCAP_DXFMT_R32_SINT: return SVGA3D_R32_SINT; + case SVGA3D_DEVCAP_DXFMT_R24G8_TYPELESS: return SVGA3D_R24G8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_D24_UNORM_S8_UINT: return SVGA3D_D24_UNORM_S8_UINT; + case SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8: return SVGA3D_R24_UNORM_X8; + case SVGA3D_DEVCAP_DXFMT_X24_G8_UINT: return SVGA3D_X24_G8_UINT; + case SVGA3D_DEVCAP_DXFMT_R8G8_TYPELESS: return SVGA3D_R8G8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R8G8_UNORM: return SVGA3D_R8G8_UNORM; + case SVGA3D_DEVCAP_DXFMT_R8G8_UINT: return SVGA3D_R8G8_UINT; + case SVGA3D_DEVCAP_DXFMT_R8G8_SINT: return SVGA3D_R8G8_SINT; + case SVGA3D_DEVCAP_DXFMT_R16_TYPELESS: return SVGA3D_R16_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R16_UNORM: return SVGA3D_R16_UNORM; + case SVGA3D_DEVCAP_DXFMT_R16_UINT: return SVGA3D_R16_UINT; + case SVGA3D_DEVCAP_DXFMT_R16_SNORM: return SVGA3D_R16_SNORM; + case SVGA3D_DEVCAP_DXFMT_R16_SINT: return SVGA3D_R16_SINT; + case SVGA3D_DEVCAP_DXFMT_R8_TYPELESS: return SVGA3D_R8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_R8_UNORM: return SVGA3D_R8_UNORM; + case SVGA3D_DEVCAP_DXFMT_R8_UINT: return SVGA3D_R8_UINT; + case SVGA3D_DEVCAP_DXFMT_R8_SNORM: return SVGA3D_R8_SNORM; + case SVGA3D_DEVCAP_DXFMT_R8_SINT: return SVGA3D_R8_SINT; + case SVGA3D_DEVCAP_DXFMT_P8: return SVGA3D_P8; + case SVGA3D_DEVCAP_DXFMT_R9G9B9E5_SHAREDEXP: return SVGA3D_R9G9B9E5_SHAREDEXP; + case SVGA3D_DEVCAP_DXFMT_R8G8_B8G8_UNORM: return SVGA3D_R8G8_B8G8_UNORM; + case SVGA3D_DEVCAP_DXFMT_G8R8_G8B8_UNORM: return SVGA3D_G8R8_G8B8_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC1_TYPELESS: return SVGA3D_BC1_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_BC1_UNORM_SRGB: return SVGA3D_BC1_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_BC2_TYPELESS: return SVGA3D_BC2_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_BC2_UNORM_SRGB: return SVGA3D_BC2_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_BC3_TYPELESS: return SVGA3D_BC3_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_BC3_UNORM_SRGB: return SVGA3D_BC3_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_BC4_TYPELESS: return SVGA3D_BC4_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_ATI1: return SVGA3D_ATI1; + case SVGA3D_DEVCAP_DXFMT_BC4_SNORM: return SVGA3D_BC4_SNORM; + case SVGA3D_DEVCAP_DXFMT_BC5_TYPELESS: return SVGA3D_BC5_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_ATI2: return SVGA3D_ATI2; + case SVGA3D_DEVCAP_DXFMT_BC5_SNORM: return SVGA3D_BC5_SNORM; + case SVGA3D_DEVCAP_DXFMT_R10G10B10_XR_BIAS_A2_UNORM: return SVGA3D_R10G10B10_XR_BIAS_A2_UNORM; + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_TYPELESS: return SVGA3D_B8G8R8A8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM_SRGB: return SVGA3D_B8G8R8A8_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_TYPELESS: return SVGA3D_B8G8R8X8_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM_SRGB: return SVGA3D_B8G8R8X8_UNORM_SRGB; + case SVGA3D_DEVCAP_DXFMT_Z_DF16: return SVGA3D_Z_DF16; + case SVGA3D_DEVCAP_DXFMT_Z_DF24: return SVGA3D_Z_DF24; + case SVGA3D_DEVCAP_DXFMT_Z_D24S8_INT: return SVGA3D_Z_D24S8_INT; + case SVGA3D_DEVCAP_DXFMT_YV12: return SVGA3D_YV12; + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_FLOAT: return SVGA3D_R32G32B32A32_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_FLOAT: return SVGA3D_R16G16B16A16_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UNORM: return SVGA3D_R16G16B16A16_UNORM; + case SVGA3D_DEVCAP_DXFMT_R32G32_FLOAT: return SVGA3D_R32G32_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UNORM: return SVGA3D_R10G10B10A2_UNORM; + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SNORM: return SVGA3D_R8G8B8A8_SNORM; + case SVGA3D_DEVCAP_DXFMT_R16G16_FLOAT: return SVGA3D_R16G16_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R16G16_UNORM: return SVGA3D_R16G16_UNORM; + case SVGA3D_DEVCAP_DXFMT_R16G16_SNORM: return SVGA3D_R16G16_SNORM; + case SVGA3D_DEVCAP_DXFMT_R32_FLOAT: return SVGA3D_R32_FLOAT; + case SVGA3D_DEVCAP_DXFMT_R8G8_SNORM: return SVGA3D_R8G8_SNORM; + case SVGA3D_DEVCAP_DXFMT_R16_FLOAT: return SVGA3D_R16_FLOAT; + case SVGA3D_DEVCAP_DXFMT_D16_UNORM: return SVGA3D_D16_UNORM; + case SVGA3D_DEVCAP_DXFMT_A8_UNORM: return SVGA3D_A8_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC1_UNORM: return SVGA3D_BC1_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC2_UNORM: return SVGA3D_BC2_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC3_UNORM: return SVGA3D_BC3_UNORM; + case SVGA3D_DEVCAP_DXFMT_B5G6R5_UNORM: return SVGA3D_B5G6R5_UNORM; + case SVGA3D_DEVCAP_DXFMT_B5G5R5A1_UNORM: return SVGA3D_B5G5R5A1_UNORM; + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM: return SVGA3D_B8G8R8A8_UNORM; + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM: return SVGA3D_B8G8R8X8_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC4_UNORM: return SVGA3D_BC4_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC5_UNORM: return SVGA3D_BC5_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC6H_TYPELESS: return SVGA3D_BC6H_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_BC6H_UF16: return SVGA3D_BC6H_UF16; + case SVGA3D_DEVCAP_DXFMT_BC6H_SF16: return SVGA3D_BC6H_SF16; + case SVGA3D_DEVCAP_DXFMT_BC7_TYPELESS: return SVGA3D_BC7_TYPELESS; + case SVGA3D_DEVCAP_DXFMT_BC7_UNORM: return SVGA3D_BC7_UNORM; + case SVGA3D_DEVCAP_DXFMT_BC7_UNORM_SRGB: return SVGA3D_BC7_UNORM_SRGB; + default: + AssertFailed(); + break; + } + return SVGA3D_FORMAT_INVALID; +} + + +static int vmsvgaDXCheckFormatSupportPreDX(PVMSVGA3DSTATE pState, SVGA3dSurfaceFormat enmFormat, uint32_t *pu32DevCap) +{ + int rc = VINF_SUCCESS; + + *pu32DevCap = 0; + + DXGI_FORMAT const dxgiFormat = vmsvgaDXSurfaceFormat2Dxgi(enmFormat); + if (dxgiFormat != DXGI_FORMAT_UNKNOWN) + { + RT_NOREF(pState); + /** @todo Implement */ + } + else + rc = VERR_NOT_SUPPORTED; + return rc; +} + +static int vmsvgaDXCheckFormatSupport(PVMSVGA3DSTATE pState, SVGA3dSurfaceFormat enmFormat, uint32_t *pu32DevCap) +{ + int rc = VINF_SUCCESS; + + *pu32DevCap = 0; + + DXGI_FORMAT const dxgiFormat = vmsvgaDXSurfaceFormat2Dxgi(enmFormat); + if (dxgiFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *pDevice = pState->pBackend->dxDevice.pDevice; + UINT FormatSupport = 0; + HRESULT hr = pDevice->CheckFormatSupport(dxgiFormat, &FormatSupport); + if (SUCCEEDED(hr)) + { + *pu32DevCap |= SVGA3D_DXFMT_SUPPORTED; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) + *pu32DevCap |= SVGA3D_DXFMT_SHADER_SAMPLE; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET) + *pu32DevCap |= SVGA3D_DXFMT_COLOR_RENDERTARGET; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) + *pu32DevCap |= SVGA3D_DXFMT_DEPTH_RENDERTARGET; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_BLENDABLE) + *pu32DevCap |= SVGA3D_DXFMT_BLENDABLE; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_MIP) + *pu32DevCap |= SVGA3D_DXFMT_MIPS; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) + *pu32DevCap |= SVGA3D_DXFMT_ARRAY; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) + *pu32DevCap |= SVGA3D_DXFMT_VOLUME; + + if (FormatSupport & D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER) + *pu32DevCap |= SVGA3D_DXFMT_DX_VERTEX_BUFFER; + + UINT NumQualityLevels; + hr = pDevice->CheckMultisampleQualityLevels(dxgiFormat, 2, &NumQualityLevels); + if (SUCCEEDED(hr) && NumQualityLevels != 0) + *pu32DevCap |= SVGA3D_DXFMT_MULTISAMPLE; + } + else + { + LogFunc(("CheckFormatSupport failed for 0x%08x, hr = 0x%08x\n", dxgiFormat, hr)); + rc = VERR_NOT_SUPPORTED; + } + } + else + rc = VERR_NOT_SUPPORTED; + return rc; +} + + +static int dxDeviceCreate(PVMSVGA3DBACKEND pBackend, DXDEVICE *pDXDevice) +{ + int rc = VINF_SUCCESS; + + if (pBackend->fSingleDevice && pBackend->dxDevice.pDevice) + { + pDXDevice->pDevice = pBackend->dxDevice.pDevice; + pDXDevice->pDevice->AddRef(); + + pDXDevice->pImmediateContext = pBackend->dxDevice.pImmediateContext; + pDXDevice->pImmediateContext->AddRef(); + + pDXDevice->pDxgiFactory = pBackend->dxDevice.pDxgiFactory; + pDXDevice->pDxgiFactory->AddRef(); + + pDXDevice->FeatureLevel = pBackend->dxDevice.FeatureLevel; + +#ifdef DX_COMMON_STAGING_BUFFER + pDXDevice->pStagingBuffer = 0; + pDXDevice->cbStagingBuffer = 0; +#endif + + BlitInit(&pDXDevice->Blitter, pDXDevice->pDevice, pDXDevice->pImmediateContext); + return rc; + } + + IDXGIAdapter *pAdapter = NULL; /* Default adapter. */ + static D3D_FEATURE_LEVEL const s_aFeatureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + UINT Flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; +#ifdef DEBUG + Flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + ID3D11Device *pDevice = 0; + ID3D11DeviceContext *pImmediateContext = 0; + HRESULT hr = pBackend->pfnD3D11CreateDevice(pAdapter, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + Flags, + s_aFeatureLevels, + RT_ELEMENTS(s_aFeatureLevels), + D3D11_SDK_VERSION, + &pDevice, + &pDXDevice->FeatureLevel, + &pImmediateContext); +#ifdef DEBUG + if (FAILED(hr)) + { + /* Device creation may fail because _DEBUG flag requires "D3D11 SDK Layers for Windows 10" ("Graphics Tools"): + * Settings/System/Apps/Optional features/Add a feature/Graphics Tools + * Retry without the flag. + */ + Flags &= ~D3D11_CREATE_DEVICE_DEBUG; + hr = pBackend->pfnD3D11CreateDevice(pAdapter, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + Flags, + s_aFeatureLevels, + RT_ELEMENTS(s_aFeatureLevels), + D3D11_SDK_VERSION, + &pDevice, + &pDXDevice->FeatureLevel, + &pImmediateContext); + } +#endif + + if (SUCCEEDED(hr)) + { + LogRel(("VMSVGA: Feature level %#x\n", pDXDevice->FeatureLevel)); + + hr = pDevice->QueryInterface(__uuidof(ID3D11Device1), (void**)&pDXDevice->pDevice); + AssertReturnStmt(SUCCEEDED(hr), + D3D_RELEASE(pImmediateContext); D3D_RELEASE(pDevice), + VERR_NOT_SUPPORTED); + + hr = pImmediateContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void**)&pDXDevice->pImmediateContext); + AssertReturnStmt(SUCCEEDED(hr), + D3D_RELEASE(pImmediateContext); D3D_RELEASE(pDXDevice->pDevice); D3D_RELEASE(pDevice), + VERR_NOT_SUPPORTED); + +#ifdef DEBUG + /* Break into debugger when DX runtime detects anything unusual. */ + HRESULT hr2; + ID3D11Debug *pDebug = 0; + hr2 = pDXDevice->pDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pDebug); + if (SUCCEEDED(hr2)) + { + ID3D11InfoQueue *pInfoQueue = 0; + hr2 = pDebug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&pInfoQueue); + if (SUCCEEDED(hr2)) + { + pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); +// pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); +// pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); + + /* No breakpoints for the following messages. */ + D3D11_MESSAGE_ID saIgnoredMessageIds[] = + { + /* Message ID: Caused by: */ + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH, /* Autogenerated input signatures. */ + D3D11_MESSAGE_ID_LIVE_DEVICE, /* Live object report. Does not seem to prevent a breakpoint. */ + (D3D11_MESSAGE_ID)3146081 /*DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET*/, /* U. */ + D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_NOT_SET, /* U. */ + D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_MISMATCH, /* U. */ + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT, /* P. */ + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERMASK, /* S. */ + }; + + D3D11_INFO_QUEUE_FILTER filter; + RT_ZERO(filter); + filter.DenyList.NumIDs = RT_ELEMENTS(saIgnoredMessageIds); + filter.DenyList.pIDList = saIgnoredMessageIds; + pInfoQueue->AddStorageFilterEntries(&filter); + + D3D_RELEASE(pInfoQueue); + } + D3D_RELEASE(pDebug); + } +#endif + + IDXGIDevice *pDxgiDevice = 0; + hr = pDXDevice->pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDxgiDevice); + if (SUCCEEDED(hr)) + { + IDXGIAdapter *pDxgiAdapter = 0; + hr = pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pDxgiAdapter); + if (SUCCEEDED(hr)) + { + hr = pDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&pDXDevice->pDxgiFactory); + D3D_RELEASE(pDxgiAdapter); + } + + D3D_RELEASE(pDxgiDevice); + } + } + + if (SUCCEEDED(hr)) + BlitInit(&pDXDevice->Blitter, pDXDevice->pDevice, pDXDevice->pImmediateContext); + else + rc = VERR_NOT_SUPPORTED; + + return rc; +} + + +static void dxDeviceDestroy(PVMSVGA3DBACKEND pBackend, DXDEVICE *pDevice) +{ + RT_NOREF(pBackend); + + BlitRelease(&pDevice->Blitter); + +#ifdef DX_COMMON_STAGING_BUFFER + D3D_RELEASE(pDevice->pStagingBuffer); +#endif + + D3D_RELEASE(pDevice->pDxgiFactory); + D3D_RELEASE(pDevice->pImmediateContext); + +#ifdef DEBUG + HRESULT hr2; + ID3D11Debug *pDebug = 0; + hr2 = pDevice->pDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pDebug); + if (SUCCEEDED(hr2)) + { + /// @todo Use this to see whether all resources have been properly released. + //DEBUG_BREAKPOINT_TEST(); + //pDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL | (D3D11_RLDO_FLAGS)0x4 /*D3D11_RLDO_IGNORE_INTERNAL*/); + D3D_RELEASE(pDebug); + } +#endif + + D3D_RELEASE(pDevice->pDevice); + RT_ZERO(*pDevice); +} + + +static void dxViewAddToList(PVGASTATECC pThisCC, DXVIEW *pDXView) +{ + LogFunc(("cid = %u, sid = %u, viewId = %u, type = %u\n", + pDXView->cid, pDXView->sid, pDXView->viewId, pDXView->enmViewType)); + + Assert(pDXView->u.pView); /* Only already created views should be added. Guard against mis-use by callers. */ + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pDXView->sid, &pSurface); + AssertRCReturnVoid(rc); + + RTListAppend(&pSurface->pBackendSurface->listView, &pDXView->nodeSurfaceView); +} + + +static void dxViewRemoveFromList(DXVIEW *pDXView) +{ + LogFunc(("cid = %u, sid = %u, viewId = %u, type = %u\n", + pDXView->cid, pDXView->sid, pDXView->viewId, pDXView->enmViewType)); + /* pView can be NULL, if COT entry is already empty. */ + if (pDXView->u.pView) + { + Assert(pDXView->nodeSurfaceView.pNext && pDXView->nodeSurfaceView.pPrev); + RTListNodeRemove(&pDXView->nodeSurfaceView); + } +} + + +static int dxViewDestroy(DXVIEW *pDXView) +{ + LogFunc(("cid = %u, sid = %u, viewId = %u, type = %u\n", + pDXView->cid, pDXView->sid, pDXView->viewId, pDXView->enmViewType)); + if (pDXView->u.pView) + { + D3D_RELEASE(pDXView->u.pView); + RTListNodeRemove(&pDXView->nodeSurfaceView); + RT_ZERO(*pDXView); + } + + return VINF_SUCCESS; +} + + +static int dxViewInit(DXVIEW *pDXView, PVMSVGA3DSURFACE pSurface, VMSVGA3DDXCONTEXT *pDXContext, uint32_t viewId, VMSVGA3DBACKVIEWTYPE enmViewType, ID3D11View *pView) +{ + pDXView->cid = pDXContext->cid; + pDXView->sid = pSurface->id; + pDXView->viewId = viewId; + pDXView->enmViewType = enmViewType; + pDXView->u.pView = pView; + RTListAppend(&pSurface->pBackendSurface->listView, &pDXView->nodeSurfaceView); + + LogFunc(("cid = %u, sid = %u, viewId = %u, type = %u\n", + pDXView->cid, pDXView->sid, pDXView->viewId, pDXView->enmViewType)); + +DXVIEW *pIter, *pNext; +RTListForEachSafe(&pSurface->pBackendSurface->listView, pIter, pNext, DXVIEW, nodeSurfaceView) +{ + AssertPtr(pNext); + LogFunc(("pIter=%p, pNext=%p\n", pIter, pNext)); +} + + return VINF_SUCCESS; +} + + +DECLINLINE(bool) dxIsSurfaceShareable(PVMSVGA3DSURFACE pSurface) +{ + /* It is not expected that volume textures will be shared between contexts. */ + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_VOLUME) + return false; + + return (pSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) + || (pSurface->f.surfaceFlags & SVGA3D_SURFACE_BIND_RENDER_TARGET); +} + + +static DXDEVICE *dxDeviceFromCid(uint32_t cid, PVMSVGA3DSTATE pState) +{ + if (cid != DX_CID_BACKEND) + { + if (pState->pBackend->fSingleDevice) + return &pState->pBackend->dxDevice; + + VMSVGA3DDXCONTEXT *pDXContext; + int rc = vmsvga3dDXContextFromCid(pState, cid, &pDXContext); + if (RT_SUCCESS(rc)) + return &pDXContext->pBackendDXContext->dxDevice; + } + else + return &pState->pBackend->dxDevice; + + AssertFailed(); + return NULL; +} + + +static DXDEVICE *dxDeviceFromContext(PVMSVGA3DSTATE p3dState, VMSVGA3DDXCONTEXT *pDXContext) +{ + if (pDXContext && !p3dState->pBackend->fSingleDevice) + return &pDXContext->pBackendDXContext->dxDevice; + + return &p3dState->pBackend->dxDevice; +} + + +static int dxDeviceFlush(DXDEVICE *pDevice) +{ + /** @todo Should the flush follow the query submission? */ + pDevice->pImmediateContext->Flush(); + + ID3D11Query *pQuery = 0; + D3D11_QUERY_DESC qd; + RT_ZERO(qd); + qd.Query = D3D11_QUERY_EVENT; + + HRESULT hr = pDevice->pDevice->CreateQuery(&qd, &pQuery); + Assert(hr == S_OK); RT_NOREF(hr); + pDevice->pImmediateContext->End(pQuery); + + BOOL queryData; + while (pDevice->pImmediateContext->GetData(pQuery, &queryData, sizeof(queryData), 0) != S_OK) + RTThreadYield(); + + D3D_RELEASE(pQuery); + + return VINF_SUCCESS; +} + + +static int dxContextWait(uint32_t cidDrawing, PVMSVGA3DSTATE pState) +{ + if (pState->pBackend->fSingleDevice) + return VINF_SUCCESS; + + /* Flush cidDrawing context and issue a query. */ + DXDEVICE *pDXDevice = dxDeviceFromCid(cidDrawing, pState); + if (pDXDevice) + return dxDeviceFlush(pDXDevice); + /* cidDrawing does not exist anymore. */ + return VINF_SUCCESS; +} + + +static int dxSurfaceWait(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, uint32_t cidRequesting) +{ + if (pState->pBackend->fSingleDevice) + return VINF_SUCCESS; + + VMSVGA3DBACKENDSURFACE *pBackendSurface = pSurface->pBackendSurface; + if (!pBackendSurface) + AssertFailedReturn(VERR_INVALID_STATE); + + int rc = VINF_SUCCESS; + if (pBackendSurface->cidDrawing != SVGA_ID_INVALID) + { + if (pBackendSurface->cidDrawing != cidRequesting) + { + LogFunc(("sid = %u, assoc cid = %u, drawing cid = %u, req cid = %u\n", + pSurface->id, pSurface->idAssociatedContext, pBackendSurface->cidDrawing, cidRequesting)); + Assert(dxIsSurfaceShareable(pSurface)); + rc = dxContextWait(pBackendSurface->cidDrawing, pState); + pBackendSurface->cidDrawing = SVGA_ID_INVALID; + } + } + return rc; +} + + +static ID3D11Resource *dxResource(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, VMSVGA3DDXCONTEXT *pDXContext) +{ + VMSVGA3DBACKENDSURFACE *pBackendSurface = pSurface->pBackendSurface; + if (!pBackendSurface) + AssertFailedReturn(NULL); + + ID3D11Resource *pResource; + + uint32_t const cidRequesting = pDXContext ? pDXContext->cid : DX_CID_BACKEND; + if (cidRequesting == pSurface->idAssociatedContext || pState->pBackend->fSingleDevice) + pResource = pBackendSurface->u.pResource; + else + { + /* + * Context, which as not created the surface, is requesting. + */ + AssertReturn(pDXContext, NULL); + + Assert(dxIsSurfaceShareable(pSurface)); + Assert(pSurface->idAssociatedContext == DX_CID_BACKEND); + + DXSHAREDTEXTURE *pSharedTexture = (DXSHAREDTEXTURE *)RTAvlU32Get(&pBackendSurface->SharedTextureTree, pDXContext->cid); + if (!pSharedTexture) + { + DXDEVICE *pDevice = dxDeviceFromContext(pState, pDXContext); + AssertReturn(pDevice->pDevice, NULL); + + AssertReturn(pBackendSurface->SharedHandle, NULL); + + /* This context has not yet opened the texture. */ + pSharedTexture = (DXSHAREDTEXTURE *)RTMemAllocZ(sizeof(DXSHAREDTEXTURE)); + AssertReturn(pSharedTexture, NULL); + + pSharedTexture->Core.Key = pDXContext->cid; + bool const fSuccess = RTAvlU32Insert(&pBackendSurface->SharedTextureTree, &pSharedTexture->Core); + AssertReturn(fSuccess, NULL); + + HRESULT hr = pDevice->pDevice->OpenSharedResource(pBackendSurface->SharedHandle, __uuidof(ID3D11Texture2D), (void**)&pSharedTexture->pTexture); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + pSharedTexture->sid = pSurface->id; + else + { + RTAvlU32Remove(&pBackendSurface->SharedTextureTree, pDXContext->cid); + RTMemFree(pSharedTexture); + return NULL; + } + } + + pResource = pSharedTexture->pTexture; + } + + /* Wait for drawing to finish. */ + dxSurfaceWait(pState, pSurface, cidRequesting); + + return pResource; +} + + +static uint32_t dxGetRenderTargetViewSid(PVMSVGA3DDXCONTEXT pDXContext, uint32_t renderTargetViewId) +{ + ASSERT_GUEST_RETURN(renderTargetViewId < pDXContext->cot.cRTView, SVGA_ID_INVALID); + + SVGACOTableDXRTViewEntry const *pRTViewEntry = &pDXContext->cot.paRTView[renderTargetViewId]; + return pRTViewEntry->sid; +} + + +static SVGACOTableDXSRViewEntry const *dxGetShaderResourceViewEntry(PVMSVGA3DDXCONTEXT pDXContext, uint32_t shaderResourceViewId) +{ + ASSERT_GUEST_RETURN(shaderResourceViewId < pDXContext->cot.cSRView, NULL); + + SVGACOTableDXSRViewEntry const *pSRViewEntry = &pDXContext->cot.paSRView[shaderResourceViewId]; + return pSRViewEntry; +} + + +static SVGACOTableDXUAViewEntry const *dxGetUnorderedAccessViewEntry(PVMSVGA3DDXCONTEXT pDXContext, uint32_t uaViewId) +{ + ASSERT_GUEST_RETURN(uaViewId < pDXContext->cot.cUAView, NULL); + + SVGACOTableDXUAViewEntry const *pUAViewEntry = &pDXContext->cot.paUAView[uaViewId]; + return pUAViewEntry; +} + + +static SVGACOTableDXDSViewEntry const *dxGetDepthStencilViewEntry(PVMSVGA3DDXCONTEXT pDXContext, uint32_t depthStencilViewId) +{ + ASSERT_GUEST_RETURN(depthStencilViewId < pDXContext->cot.cDSView, NULL); + + SVGACOTableDXDSViewEntry const *pDSViewEntry = &pDXContext->cot.paDSView[depthStencilViewId]; + return pDSViewEntry; +} + + +static SVGACOTableDXRTViewEntry const *dxGetRenderTargetViewEntry(PVMSVGA3DDXCONTEXT pDXContext, uint32_t renderTargetViewId) +{ + ASSERT_GUEST_RETURN(renderTargetViewId < pDXContext->cot.cRTView, NULL); + + SVGACOTableDXRTViewEntry const *pRTViewEntry = &pDXContext->cot.paRTView[renderTargetViewId]; + return pRTViewEntry; +} + + +static int dxTrackRenderTargets(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + for (unsigned long i = 0; i < RT_ELEMENTS(pDXContext->svgaDXContext.renderState.renderTargetViewIds); ++i) + { + uint32_t const renderTargetViewId = pDXContext->svgaDXContext.renderState.renderTargetViewIds[i]; + if (renderTargetViewId == SVGA_ID_INVALID) + continue; + + uint32_t const sid = dxGetRenderTargetViewSid(pDXContext, renderTargetViewId); + LogFunc(("[%u] sid = %u, drawing cid = %u\n", i, sid, pDXContext->cid)); + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pState, sid, &pSurface); + if (RT_SUCCESS(rc)) + { + AssertContinue(pSurface->pBackendSurface); + pSurface->pBackendSurface->cidDrawing = pDXContext->cid; + } + } + return VINF_SUCCESS; +} + + +static int dxDefineStreamOutput(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dStreamOutputId soid, SVGACOTableDXStreamOutputEntry const *pEntry, DXSHADER *pDXShader) +{ + PVMSVGAR3STATE const pSvgaR3State = pThisCC->svga.pSvgaR3State; + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[soid]; + + /* Make D3D11_SO_DECLARATION_ENTRY array from SVGA3dStreamOutputDeclarationEntry. */ + SVGA3dStreamOutputDeclarationEntry const *paDecls; + PVMSVGAMOB pMob = NULL; + if (pEntry->usesMob) + { + pMob = vmsvgaR3MobGet(pSvgaR3State, pEntry->mobid); + ASSERT_GUEST_RETURN(pMob, VERR_INVALID_PARAMETER); + + /* Create a memory pointer for the MOB, which is accessible by host. */ + int rc = vmsvgaR3MobBackingStoreCreate(pSvgaR3State, pMob, vmsvgaR3MobSize(pMob)); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + /* Get pointer to the shader bytecode. This will also verify the offset. */ + paDecls = (SVGA3dStreamOutputDeclarationEntry const *)vmsvgaR3MobBackingStorePtr(pMob, pEntry->offsetInBytes); + AssertReturnStmt(paDecls, vmsvgaR3MobBackingStoreDelete(pSvgaR3State, pMob), VERR_INTERNAL_ERROR); + } + else + paDecls = &pEntry->decl[0]; + + pDXStreamOutput->cDeclarationEntry = pEntry->numOutputStreamEntries; + for (uint32_t i = 0; i < pDXStreamOutput->cDeclarationEntry; ++i) + { + D3D11_SO_DECLARATION_ENTRY *pDst = &pDXStreamOutput->aDeclarationEntry[i]; + SVGA3dStreamOutputDeclarationEntry const *pSrc = &paDecls[i]; + + uint32_t const registerMask = pSrc->registerMask & 0xF; + unsigned const iFirstBit = ASMBitFirstSetU32(registerMask); + unsigned const iLastBit = ASMBitLastSetU32(registerMask); + + pDst->Stream = pSrc->stream; + pDst->SemanticName = NULL; /* Semantic name and index will be taken from the shader output declaration. */ + pDst->SemanticIndex = 0; + pDst->StartComponent = iFirstBit > 0 ? iFirstBit - 1 : 0; + pDst->ComponentCount = iFirstBit > 0 ? iLastBit - (iFirstBit - 1) : 0; + pDst->OutputSlot = pSrc->outputSlot; + } + + uint32_t MaxSemanticIndex = 0; + for (uint32_t i = 0; i < pDXStreamOutput->cDeclarationEntry; ++i) + { + D3D11_SO_DECLARATION_ENTRY *pDeclarationEntry = &pDXStreamOutput->aDeclarationEntry[i]; + SVGA3dStreamOutputDeclarationEntry const *decl = &paDecls[i]; + + /* Find the corresponding register and mask in the GS shader output. */ + int idxFound = -1; + for (uint32_t iOutputEntry = 0; iOutputEntry < pDXShader->shaderInfo.cOutputSignature; ++iOutputEntry) + { + SVGA3dDXSignatureEntry const *pOutputEntry = &pDXShader->shaderInfo.aOutputSignature[iOutputEntry]; + if ( pOutputEntry->registerIndex == decl->registerIndex + && (decl->registerMask & ~pOutputEntry->mask) == 0) /* SO decl mask is a subset of shader output mask. */ + { + idxFound = iOutputEntry; + break; + } + } + + if (idxFound >= 0) + { + DXShaderAttributeSemantic const *pOutputSemantic = &pDXShader->shaderInfo.aOutputSemantic[idxFound]; + pDeclarationEntry->SemanticName = pOutputSemantic->pcszSemanticName; + pDeclarationEntry->SemanticIndex = pOutputSemantic->SemanticIndex; + MaxSemanticIndex = RT_MAX(MaxSemanticIndex, pOutputSemantic->SemanticIndex); + } + else + AssertFailed(); + } + + /* A geometry shader may return components of the same register as different attributes: + * + * Output signature + * Name Index Mask Register + * ATTRIB 2 xy 2 + * ATTRIB 3 z 2 + * + * For ATTRIB 3 the stream output declaration expects StartComponent = 0 and ComponentCount = 1 + * (not StartComponent = 2 and ComponentCount = 1): + * + * Stream output declaration + * SemanticName SemanticIndex StartComponent ComponentCount + * ATTRIB 2 0 2 + * ATTRIB 3 0 1 + * + * Stream output declaration can have multiple entries for the same attribute. + * In this case StartComponent is the offset within the attribute. + * + * Output signature + * Name Index Mask Register + * ATTRIB 0 xyzw 0 + * + * Stream output declaration + * SemanticName SemanticIndex StartComponent ComponentCount + * ATTRIB 0 0 1 + * ATTRIB 0 1 1 + * + * StartComponent has been computed as the component offset in a register: + * 'StartComponent = iFirstBit > 0 ? iFirstBit - 1 : 0;'. + * + * StartComponent must be the offset in an attribute. + */ + for (uint32_t SemanticIndex = 0; SemanticIndex <= MaxSemanticIndex; ++SemanticIndex) + { + /* Find minimum StartComponent value for this attribute. */ + uint32_t MinStartComponent = UINT32_MAX; + for (uint32_t i = 0; i < pDXStreamOutput->cDeclarationEntry; ++i) + { + D3D11_SO_DECLARATION_ENTRY *pDeclarationEntry = &pDXStreamOutput->aDeclarationEntry[i]; + if (pDeclarationEntry->SemanticIndex == SemanticIndex) + MinStartComponent = RT_MIN(MinStartComponent, pDeclarationEntry->StartComponent); + } + + AssertContinue(MinStartComponent != UINT32_MAX); + + /* Adjust the StartComponent to start from 0 for this attribute. */ + for (uint32_t i = 0; i < pDXStreamOutput->cDeclarationEntry; ++i) + { + D3D11_SO_DECLARATION_ENTRY *pDeclarationEntry = &pDXStreamOutput->aDeclarationEntry[i]; + if (pDeclarationEntry->SemanticIndex == SemanticIndex) + pDeclarationEntry->StartComponent -= MinStartComponent; + } + } + + if (pMob) + vmsvgaR3MobBackingStoreDelete(pSvgaR3State, pMob); + + return VINF_SUCCESS; +} + +static void dxDestroyStreamOutput(DXSTREAMOUTPUT *pDXStreamOutput) +{ + RT_ZERO(*pDXStreamOutput); +} + +static D3D11_BLEND dxBlendFactorAlpha(uint8_t svgaBlend) +{ + /* "Blend options that end in _COLOR are not allowed." but the guest sometimes sends them. */ + switch (svgaBlend) + { + case SVGA3D_BLENDOP_ZERO: return D3D11_BLEND_ZERO; + case SVGA3D_BLENDOP_ONE: return D3D11_BLEND_ONE; + case SVGA3D_BLENDOP_SRCCOLOR: return D3D11_BLEND_SRC_ALPHA; + case SVGA3D_BLENDOP_INVSRCCOLOR: return D3D11_BLEND_INV_SRC_ALPHA; + case SVGA3D_BLENDOP_SRCALPHA: return D3D11_BLEND_SRC_ALPHA; + case SVGA3D_BLENDOP_INVSRCALPHA: return D3D11_BLEND_INV_SRC_ALPHA; + case SVGA3D_BLENDOP_DESTALPHA: return D3D11_BLEND_DEST_ALPHA; + case SVGA3D_BLENDOP_INVDESTALPHA: return D3D11_BLEND_INV_DEST_ALPHA; + case SVGA3D_BLENDOP_DESTCOLOR: return D3D11_BLEND_DEST_ALPHA; + case SVGA3D_BLENDOP_INVDESTCOLOR: return D3D11_BLEND_INV_DEST_ALPHA; + case SVGA3D_BLENDOP_SRCALPHASAT: return D3D11_BLEND_SRC_ALPHA_SAT; + case SVGA3D_BLENDOP_BLENDFACTOR: return D3D11_BLEND_BLEND_FACTOR; + case SVGA3D_BLENDOP_INVBLENDFACTOR: return D3D11_BLEND_INV_BLEND_FACTOR; + case SVGA3D_BLENDOP_SRC1COLOR: return D3D11_BLEND_SRC1_ALPHA; + case SVGA3D_BLENDOP_INVSRC1COLOR: return D3D11_BLEND_INV_SRC1_ALPHA; + case SVGA3D_BLENDOP_SRC1ALPHA: return D3D11_BLEND_SRC1_ALPHA; + case SVGA3D_BLENDOP_INVSRC1ALPHA: return D3D11_BLEND_INV_SRC1_ALPHA; + case SVGA3D_BLENDOP_BLENDFACTORALPHA: return D3D11_BLEND_BLEND_FACTOR; + case SVGA3D_BLENDOP_INVBLENDFACTORALPHA: return D3D11_BLEND_INV_BLEND_FACTOR; + default: + break; + } + return D3D11_BLEND_ZERO; +} + + +static D3D11_BLEND dxBlendFactorColor(uint8_t svgaBlend) +{ + switch (svgaBlend) + { + case SVGA3D_BLENDOP_ZERO: return D3D11_BLEND_ZERO; + case SVGA3D_BLENDOP_ONE: return D3D11_BLEND_ONE; + case SVGA3D_BLENDOP_SRCCOLOR: return D3D11_BLEND_SRC_COLOR; + case SVGA3D_BLENDOP_INVSRCCOLOR: return D3D11_BLEND_INV_SRC_COLOR; + case SVGA3D_BLENDOP_SRCALPHA: return D3D11_BLEND_SRC_ALPHA; + case SVGA3D_BLENDOP_INVSRCALPHA: return D3D11_BLEND_INV_SRC_ALPHA; + case SVGA3D_BLENDOP_DESTALPHA: return D3D11_BLEND_DEST_ALPHA; + case SVGA3D_BLENDOP_INVDESTALPHA: return D3D11_BLEND_INV_DEST_ALPHA; + case SVGA3D_BLENDOP_DESTCOLOR: return D3D11_BLEND_DEST_COLOR; + case SVGA3D_BLENDOP_INVDESTCOLOR: return D3D11_BLEND_INV_DEST_COLOR; + case SVGA3D_BLENDOP_SRCALPHASAT: return D3D11_BLEND_SRC_ALPHA_SAT; + case SVGA3D_BLENDOP_BLENDFACTOR: return D3D11_BLEND_BLEND_FACTOR; + case SVGA3D_BLENDOP_INVBLENDFACTOR: return D3D11_BLEND_INV_BLEND_FACTOR; + case SVGA3D_BLENDOP_SRC1COLOR: return D3D11_BLEND_SRC1_COLOR; + case SVGA3D_BLENDOP_INVSRC1COLOR: return D3D11_BLEND_INV_SRC1_COLOR; + case SVGA3D_BLENDOP_SRC1ALPHA: return D3D11_BLEND_SRC1_ALPHA; + case SVGA3D_BLENDOP_INVSRC1ALPHA: return D3D11_BLEND_INV_SRC1_ALPHA; + case SVGA3D_BLENDOP_BLENDFACTORALPHA: return D3D11_BLEND_BLEND_FACTOR; + case SVGA3D_BLENDOP_INVBLENDFACTORALPHA: return D3D11_BLEND_INV_BLEND_FACTOR; + default: + break; + } + return D3D11_BLEND_ZERO; +} + + +static D3D11_BLEND_OP dxBlendOp(uint8_t svgaBlendEq) +{ + return (D3D11_BLEND_OP)svgaBlendEq; +} + + +static D3D11_LOGIC_OP dxLogicOp(uint8_t svgaLogicEq) +{ + return (D3D11_LOGIC_OP)svgaLogicEq; +} + + +/** @todo AssertCompile for types like D3D11_COMPARISON_FUNC and SVGA3dComparisonFunc */ +static HRESULT dxBlendStateCreate(DXDEVICE *pDevice, SVGACOTableDXBlendStateEntry const *pEntry, ID3D11BlendState1 **pp) +{ + D3D11_BLEND_DESC1 BlendDesc; + BlendDesc.AlphaToCoverageEnable = RT_BOOL(pEntry->alphaToCoverageEnable); + BlendDesc.IndependentBlendEnable = RT_BOOL(pEntry->independentBlendEnable); + for (int i = 0; i < SVGA3D_MAX_RENDER_TARGETS; ++i) + { + BlendDesc.RenderTarget[i].BlendEnable = RT_BOOL(pEntry->perRT[i].blendEnable); + BlendDesc.RenderTarget[i].LogicOpEnable = RT_BOOL(pEntry->perRT[i].logicOpEnable); + BlendDesc.RenderTarget[i].SrcBlend = dxBlendFactorColor(pEntry->perRT[i].srcBlend); + BlendDesc.RenderTarget[i].DestBlend = dxBlendFactorColor(pEntry->perRT[i].destBlend); + BlendDesc.RenderTarget[i].BlendOp = dxBlendOp (pEntry->perRT[i].blendOp); + BlendDesc.RenderTarget[i].SrcBlendAlpha = dxBlendFactorAlpha(pEntry->perRT[i].srcBlendAlpha); + BlendDesc.RenderTarget[i].DestBlendAlpha = dxBlendFactorAlpha(pEntry->perRT[i].destBlendAlpha); + BlendDesc.RenderTarget[i].BlendOpAlpha = dxBlendOp (pEntry->perRT[i].blendOpAlpha); + BlendDesc.RenderTarget[i].LogicOp = dxLogicOp (pEntry->perRT[i].logicOp); + BlendDesc.RenderTarget[i].RenderTargetWriteMask = pEntry->perRT[i].renderTargetWriteMask; + } + + HRESULT hr = pDevice->pDevice->CreateBlendState1(&BlendDesc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxDepthStencilStateCreate(DXDEVICE *pDevice, SVGACOTableDXDepthStencilEntry const *pEntry, ID3D11DepthStencilState **pp) +{ + D3D11_DEPTH_STENCIL_DESC desc; + desc.DepthEnable = pEntry->depthEnable; + desc.DepthWriteMask = (D3D11_DEPTH_WRITE_MASK)pEntry->depthWriteMask; + desc.DepthFunc = (D3D11_COMPARISON_FUNC)pEntry->depthFunc; + desc.StencilEnable = pEntry->stencilEnable; + desc.StencilReadMask = pEntry->stencilReadMask; + desc.StencilWriteMask = pEntry->stencilWriteMask; + desc.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)pEntry->frontStencilFailOp; + desc.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)pEntry->frontStencilDepthFailOp; + desc.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)pEntry->frontStencilPassOp; + desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)pEntry->frontStencilFunc; + desc.BackFace.StencilFailOp = (D3D11_STENCIL_OP)pEntry->backStencilFailOp; + desc.BackFace.StencilDepthFailOp = (D3D11_STENCIL_OP)pEntry->backStencilDepthFailOp; + desc.BackFace.StencilPassOp = (D3D11_STENCIL_OP)pEntry->backStencilPassOp; + desc.BackFace.StencilFunc = (D3D11_COMPARISON_FUNC)pEntry->backStencilFunc; + /** @todo frontEnable, backEnable */ + + HRESULT hr = pDevice->pDevice->CreateDepthStencilState(&desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxSamplerStateCreate(DXDEVICE *pDevice, SVGACOTableDXSamplerEntry const *pEntry, ID3D11SamplerState **pp) +{ + D3D11_SAMPLER_DESC desc; + /* Guest sometimes sends inconsistent (from D3D11 point of view) set of filter flags. */ + if (pEntry->filter & SVGA3D_FILTER_ANISOTROPIC) + desc.Filter = (pEntry->filter & SVGA3D_FILTER_COMPARE) + ? D3D11_FILTER_COMPARISON_ANISOTROPIC + : D3D11_FILTER_ANISOTROPIC; + else + desc.Filter = (D3D11_FILTER)pEntry->filter; + desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)pEntry->addressU; + desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)pEntry->addressV; + desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)pEntry->addressW; + desc.MipLODBias = pEntry->mipLODBias; + desc.MaxAnisotropy = RT_CLAMP(pEntry->maxAnisotropy, 1, 16); /* "Valid values are between 1 and 16" */ + desc.ComparisonFunc = (D3D11_COMPARISON_FUNC)pEntry->comparisonFunc; + desc.BorderColor[0] = pEntry->borderColor.value[0]; + desc.BorderColor[1] = pEntry->borderColor.value[1]; + desc.BorderColor[2] = pEntry->borderColor.value[2]; + desc.BorderColor[3] = pEntry->borderColor.value[3]; + desc.MinLOD = pEntry->minLOD; + desc.MaxLOD = pEntry->maxLOD; + + HRESULT hr = pDevice->pDevice->CreateSamplerState(&desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static D3D11_FILL_MODE dxFillMode(uint8_t svgaFillMode) +{ + if (svgaFillMode == SVGA3D_FILLMODE_POINT) + return D3D11_FILL_WIREFRAME; + return (D3D11_FILL_MODE)svgaFillMode; +} + + +static D3D11_CULL_MODE dxCullMode(uint8_t svgaCullMode) +{ + return (D3D11_CULL_MODE)svgaCullMode; +} + + +static HRESULT dxRasterizerStateCreate(DXDEVICE *pDevice, SVGACOTableDXRasterizerStateEntry const *pEntry, ID3D11RasterizerState1 **pp) +{ + D3D11_RASTERIZER_DESC1 desc; + desc.FillMode = dxFillMode(pEntry->fillMode); + desc.CullMode = dxCullMode(pEntry->cullMode); + desc.FrontCounterClockwise = pEntry->frontCounterClockwise; + /** @todo provokingVertexLast */ + desc.DepthBias = pEntry->depthBias; + desc.DepthBiasClamp = pEntry->depthBiasClamp; + desc.SlopeScaledDepthBias = pEntry->slopeScaledDepthBias; + desc.DepthClipEnable = pEntry->depthClipEnable; + desc.ScissorEnable = pEntry->scissorEnable; + desc.MultisampleEnable = pEntry->multisampleEnable; + desc.AntialiasedLineEnable = pEntry->antialiasedLineEnable; + desc.ForcedSampleCount = pEntry->forcedSampleCount; + /** @todo lineWidth lineStippleEnable lineStippleFactor lineStipplePattern */ + + HRESULT hr = pDevice->pDevice->CreateRasterizerState1(&desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxRenderTargetViewCreate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGACOTableDXRTViewEntry const *pEntry, VMSVGA3DSURFACE *pSurface, ID3D11RenderTargetView **pp) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + ID3D11Resource *pResource = dxResource(pThisCC->svga.p3dState, pSurface, pDXContext); + + D3D11_RENDER_TARGET_VIEW_DESC desc; + RT_ZERO(desc); + desc.Format = vmsvgaDXSurfaceFormat2Dxgi(pEntry->format); + AssertReturn(desc.Format != DXGI_FORMAT_UNKNOWN || pEntry->format == SVGA3D_BUFFER, E_FAIL); + switch (pEntry->resourceDimension) + { + case SVGA3D_RESOURCE_BUFFER: + desc.ViewDimension = D3D11_RTV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = pEntry->desc.buffer.firstElement; + desc.Buffer.NumElements = pEntry->desc.buffer.numElements; + break; + case SVGA3D_RESOURCE_TEXTURE1D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; + desc.Texture1D.MipSlice = pEntry->desc.tex.mipSlice; + } + else + { + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY; + desc.Texture1DArray.MipSlice = pEntry->desc.tex.mipSlice; + desc.Texture1DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture1DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE2D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = pEntry->desc.tex.mipSlice; + } + else + { + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = pEntry->desc.tex.mipSlice; + desc.Texture2DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture2DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE3D: + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + desc.Texture3D.MipSlice = pEntry->desc.tex3D.mipSlice; + desc.Texture3D.FirstWSlice = pEntry->desc.tex3D.firstW; + desc.Texture3D.WSize = pEntry->desc.tex3D.wSize; + break; + case SVGA3D_RESOURCE_TEXTURECUBE: + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = pEntry->desc.tex.mipSlice; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = 6; + break; + case SVGA3D_RESOURCE_BUFFEREX: + AssertFailed(); /** @todo test. Probably not applicable to a render target view. */ + desc.ViewDimension = D3D11_RTV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = pEntry->desc.buffer.firstElement; + desc.Buffer.NumElements = pEntry->desc.buffer.numElements; + break; + default: + ASSERT_GUEST_FAILED_RETURN(E_INVALIDARG); + } + + HRESULT hr = pDevice->pDevice->CreateRenderTargetView(pResource, &desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxShaderResourceViewCreate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGACOTableDXSRViewEntry const *pEntry, VMSVGA3DSURFACE *pSurface, ID3D11ShaderResourceView **pp) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + ID3D11Resource *pResource = dxResource(pThisCC->svga.p3dState, pSurface, pDXContext); + + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + RT_ZERO(desc); + desc.Format = vmsvgaDXSurfaceFormat2Dxgi(pEntry->format); + AssertReturn(desc.Format != DXGI_FORMAT_UNKNOWN || pEntry->format == SVGA3D_BUFFER, E_FAIL); + + switch (pEntry->resourceDimension) + { + case SVGA3D_RESOURCE_BUFFER: + desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = pEntry->desc.buffer.firstElement; + desc.Buffer.NumElements = pEntry->desc.buffer.numElements; + break; + case SVGA3D_RESOURCE_TEXTURE1D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; + desc.Texture1D.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.Texture1D.MipLevels = pEntry->desc.tex.mipLevels; + } + else + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + desc.Texture1DArray.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.Texture1DArray.MipLevels = pEntry->desc.tex.mipLevels; + desc.Texture1DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture1DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE2D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + desc.Texture2D.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.Texture2D.MipLevels = pEntry->desc.tex.mipLevels; + } + else + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.Texture2DArray.MipLevels = pEntry->desc.tex.mipLevels; + desc.Texture2DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture2DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE3D: + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + desc.Texture3D.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.Texture3D.MipLevels = pEntry->desc.tex.mipLevels; + break; + case SVGA3D_RESOURCE_TEXTURECUBE: + if (pSurface->surfaceDesc.numArrayElements <= 6) + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + desc.TextureCube.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.TextureCube.MipLevels = pEntry->desc.tex.mipLevels; + } + else + { + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + desc.TextureCubeArray.MostDetailedMip = pEntry->desc.tex.mostDetailedMip; + desc.TextureCubeArray.MipLevels = pEntry->desc.tex.mipLevels; + desc.TextureCubeArray.First2DArrayFace = pEntry->desc.tex.firstArraySlice; + desc.TextureCubeArray.NumCubes = pEntry->desc.tex.arraySize / 6; + } + break; + case SVGA3D_RESOURCE_BUFFEREX: + AssertFailed(); /** @todo test. */ + desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; + desc.BufferEx.FirstElement = pEntry->desc.bufferex.firstElement; + desc.BufferEx.NumElements = pEntry->desc.bufferex.numElements; + desc.BufferEx.Flags = pEntry->desc.bufferex.flags; + break; + default: + ASSERT_GUEST_FAILED_RETURN(E_INVALIDARG); + } + + HRESULT hr = pDevice->pDevice->CreateShaderResourceView(pResource, &desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxUnorderedAccessViewCreate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGACOTableDXUAViewEntry const *pEntry, VMSVGA3DSURFACE *pSurface, ID3D11UnorderedAccessView **pp) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + ID3D11Resource *pResource = dxResource(pThisCC->svga.p3dState, pSurface, pDXContext); + + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + RT_ZERO(desc); + desc.Format = vmsvgaDXSurfaceFormat2Dxgi(pEntry->format); + AssertReturn(desc.Format != DXGI_FORMAT_UNKNOWN || pEntry->format == SVGA3D_BUFFER, E_FAIL); + + switch (pEntry->resourceDimension) + { + case SVGA3D_RESOURCE_BUFFER: + desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = pEntry->desc.buffer.firstElement; + desc.Buffer.NumElements = pEntry->desc.buffer.numElements; + desc.Buffer.Flags = pEntry->desc.buffer.flags; + break; + case SVGA3D_RESOURCE_TEXTURE1D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D; + desc.Texture1D.MipSlice = pEntry->desc.tex.mipSlice; + } + else + { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY; + desc.Texture1DArray.MipSlice = pEntry->desc.tex.mipSlice; + desc.Texture1DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture1DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE2D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = pEntry->desc.tex.mipSlice; + } + else + { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = pEntry->desc.tex.mipSlice; + desc.Texture2DArray.FirstArraySlice = pEntry->desc.tex.firstArraySlice; + desc.Texture2DArray.ArraySize = pEntry->desc.tex.arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE3D: + desc.Texture3D.MipSlice = pEntry->desc.tex3D.mipSlice; + desc.Texture3D.FirstWSlice = pEntry->desc.tex3D.firstW; + desc.Texture3D.WSize = pEntry->desc.tex3D.wSize; + break; + default: + ASSERT_GUEST_FAILED_RETURN(E_INVALIDARG); + } + + HRESULT hr = pDevice->pDevice->CreateUnorderedAccessView(pResource, &desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxDepthStencilViewCreate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGACOTableDXDSViewEntry const *pEntry, VMSVGA3DSURFACE *pSurface, ID3D11DepthStencilView **pp) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + ID3D11Resource *pResource = dxResource(pThisCC->svga.p3dState, pSurface, pDXContext); + + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + RT_ZERO(desc); + desc.Format = vmsvgaDXSurfaceFormat2Dxgi(pEntry->format); + AssertReturn(desc.Format != DXGI_FORMAT_UNKNOWN || pEntry->format == SVGA3D_BUFFER, E_FAIL); + desc.Flags = pEntry->flags; + switch (pEntry->resourceDimension) + { + case SVGA3D_RESOURCE_TEXTURE1D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D; + desc.Texture1D.MipSlice = pEntry->mipSlice; + } + else + { + desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY; + desc.Texture1DArray.MipSlice = pEntry->mipSlice; + desc.Texture1DArray.FirstArraySlice = pEntry->firstArraySlice; + desc.Texture1DArray.ArraySize = pEntry->arraySize; + } + break; + case SVGA3D_RESOURCE_TEXTURE2D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + { + desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = pEntry->mipSlice; + } + else + { + desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = pEntry->mipSlice; + desc.Texture2DArray.FirstArraySlice = pEntry->firstArraySlice; + desc.Texture2DArray.ArraySize = pEntry->arraySize; + } + break; + default: + ASSERT_GUEST_FAILED_RETURN(E_INVALIDARG); + } + + HRESULT hr = pDevice->pDevice->CreateDepthStencilView(pResource, &desc, pp); + Assert(SUCCEEDED(hr)); + return hr; +} + + +static HRESULT dxShaderCreate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, DXSHADER *pDXShader) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + HRESULT hr = S_OK; + + switch (pDXShader->enmShaderType) + { + case SVGA3D_SHADERTYPE_VS: + hr = pDevice->pDevice->CreateVertexShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pVertexShader); + Assert(SUCCEEDED(hr)); + break; + case SVGA3D_SHADERTYPE_PS: + hr = pDevice->pDevice->CreatePixelShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pPixelShader); + Assert(SUCCEEDED(hr)); + break; + case SVGA3D_SHADERTYPE_GS: + { + SVGA3dStreamOutputId const soid = pDXContext->svgaDXContext.streamOut.soid; + if (soid == SVGA_ID_INVALID) + { + hr = pDevice->pDevice->CreateGeometryShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pGeometryShader); + Assert(SUCCEEDED(hr)); + } + else + { + ASSERT_GUEST_RETURN(soid < pDXContext->pBackendDXContext->cStreamOutput, E_INVALIDARG); + + SVGACOTableDXStreamOutputEntry const *pEntry = &pDXContext->cot.paStreamOutput[soid]; + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[soid]; + + hr = pDevice->pDevice->CreateGeometryShaderWithStreamOutput(pDXShader->pvDXBC, pDXShader->cbDXBC, + pDXStreamOutput->aDeclarationEntry, pDXStreamOutput->cDeclarationEntry, + pEntry->numOutputStreamStrides ? pEntry->streamOutputStrideInBytes : NULL, pEntry->numOutputStreamStrides, + pEntry->rasterizedStream, + /*pClassLinkage=*/ NULL, &pDXShader->pGeometryShader); + AssertBreak(SUCCEEDED(hr)); + + pDXShader->soid = soid; + } + break; + } + case SVGA3D_SHADERTYPE_HS: + hr = pDevice->pDevice->CreateHullShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pHullShader); + Assert(SUCCEEDED(hr)); + break; + case SVGA3D_SHADERTYPE_DS: + hr = pDevice->pDevice->CreateDomainShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pDomainShader); + Assert(SUCCEEDED(hr)); + break; + case SVGA3D_SHADERTYPE_CS: + hr = pDevice->pDevice->CreateComputeShader(pDXShader->pvDXBC, pDXShader->cbDXBC, NULL, &pDXShader->pComputeShader); + Assert(SUCCEEDED(hr)); + break; + default: + ASSERT_GUEST_FAILED_RETURN(E_INVALIDARG); + } + + return hr; +} + + +static void dxShaderSet(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderType type, DXSHADER *pDXShader) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + + switch (type) + { + case SVGA3D_SHADERTYPE_VS: + pDevice->pImmediateContext->VSSetShader(pDXShader ? pDXShader->pVertexShader : NULL, NULL, 0); + break; + case SVGA3D_SHADERTYPE_PS: + pDevice->pImmediateContext->PSSetShader(pDXShader ? pDXShader->pPixelShader : NULL, NULL, 0); + break; + case SVGA3D_SHADERTYPE_GS: + { + Assert(!pDXShader || (pDXShader->soid == pDXContext->svgaDXContext.streamOut.soid)); + pDevice->pImmediateContext->GSSetShader(pDXShader ? pDXShader->pGeometryShader : NULL, NULL, 0); + } break; + case SVGA3D_SHADERTYPE_HS: + pDevice->pImmediateContext->HSSetShader(pDXShader ? pDXShader->pHullShader : NULL, NULL, 0); + break; + case SVGA3D_SHADERTYPE_DS: + pDevice->pImmediateContext->DSSetShader(pDXShader ? pDXShader->pDomainShader : NULL, NULL, 0); + break; + case SVGA3D_SHADERTYPE_CS: + pDevice->pImmediateContext->CSSetShader(pDXShader ? pDXShader->pComputeShader : NULL, NULL, 0); + break; + default: + ASSERT_GUEST_FAILED_RETURN_VOID(); + } +} + + +static void dxConstantBufferSet(DXDEVICE *pDevice, uint32_t slot, SVGA3dShaderType type, ID3D11Buffer *pConstantBuffer) +{ + switch (type) + { + case SVGA3D_SHADERTYPE_VS: + pDevice->pImmediateContext->VSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + case SVGA3D_SHADERTYPE_PS: + pDevice->pImmediateContext->PSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + case SVGA3D_SHADERTYPE_GS: + pDevice->pImmediateContext->GSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + case SVGA3D_SHADERTYPE_HS: + pDevice->pImmediateContext->HSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + case SVGA3D_SHADERTYPE_DS: + pDevice->pImmediateContext->DSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + case SVGA3D_SHADERTYPE_CS: + pDevice->pImmediateContext->CSSetConstantBuffers(slot, 1, &pConstantBuffer); + break; + default: + ASSERT_GUEST_FAILED_RETURN_VOID(); + } +} + + +static void dxSamplerSet(DXDEVICE *pDevice, SVGA3dShaderType type, uint32_t startSampler, uint32_t cSampler, ID3D11SamplerState * const *papSampler) +{ + switch (type) + { + case SVGA3D_SHADERTYPE_VS: + pDevice->pImmediateContext->VSSetSamplers(startSampler, cSampler, papSampler); + break; + case SVGA3D_SHADERTYPE_PS: + pDevice->pImmediateContext->PSSetSamplers(startSampler, cSampler, papSampler); + break; + case SVGA3D_SHADERTYPE_GS: + pDevice->pImmediateContext->GSSetSamplers(startSampler, cSampler, papSampler); + break; + case SVGA3D_SHADERTYPE_HS: + pDevice->pImmediateContext->HSSetSamplers(startSampler, cSampler, papSampler); + break; + case SVGA3D_SHADERTYPE_DS: + pDevice->pImmediateContext->DSSetSamplers(startSampler, cSampler, papSampler); + break; + case SVGA3D_SHADERTYPE_CS: + pDevice->pImmediateContext->CSSetSamplers(startSampler, cSampler, papSampler); + break; + default: + ASSERT_GUEST_FAILED_RETURN_VOID(); + } +} + + +static void dxShaderResourceViewSet(DXDEVICE *pDevice, SVGA3dShaderType type, uint32_t startView, uint32_t cShaderResourceView, ID3D11ShaderResourceView * const *papShaderResourceView) +{ + switch (type) + { + case SVGA3D_SHADERTYPE_VS: + pDevice->pImmediateContext->VSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + case SVGA3D_SHADERTYPE_PS: + pDevice->pImmediateContext->PSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + case SVGA3D_SHADERTYPE_GS: + pDevice->pImmediateContext->GSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + case SVGA3D_SHADERTYPE_HS: + pDevice->pImmediateContext->HSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + case SVGA3D_SHADERTYPE_DS: + pDevice->pImmediateContext->DSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + case SVGA3D_SHADERTYPE_CS: + pDevice->pImmediateContext->CSSetShaderResources(startView, cShaderResourceView, papShaderResourceView); + break; + default: + ASSERT_GUEST_FAILED_RETURN_VOID(); + } +} + + +static void dxCSUnorderedAccessViewSet(DXDEVICE *pDevice, uint32_t startView, uint32_t cView, ID3D11UnorderedAccessView * const *papUnorderedAccessView, UINT *pUAVInitialCounts) +{ + pDevice->pImmediateContext->CSSetUnorderedAccessViews(startView, cView, papUnorderedAccessView, pUAVInitialCounts); +} + + +static int dxBackendSurfaceAlloc(PVMSVGA3DBACKENDSURFACE *ppBackendSurface) +{ + PVMSVGA3DBACKENDSURFACE pBackendSurface = (PVMSVGA3DBACKENDSURFACE)RTMemAllocZ(sizeof(VMSVGA3DBACKENDSURFACE)); + AssertPtrReturn(pBackendSurface, VERR_NO_MEMORY); + pBackendSurface->cidDrawing = SVGA_ID_INVALID; + RTListInit(&pBackendSurface->listView); + *ppBackendSurface = pBackendSurface; + return VINF_SUCCESS; +} + + +static HRESULT dxInitSharedHandle(PVMSVGA3DBACKEND pBackend, PVMSVGA3DBACKENDSURFACE pBackendSurface) +{ + if (pBackend->fSingleDevice) + return S_OK; + + /* Get the shared handle. */ + IDXGIResource *pDxgiResource = NULL; + HRESULT hr = pBackendSurface->u.pResource->QueryInterface(__uuidof(IDXGIResource), (void**)&pDxgiResource); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + { + hr = pDxgiResource->GetSharedHandle(&pBackendSurface->SharedHandle); + Assert(SUCCEEDED(hr)); + D3D_RELEASE(pDxgiResource); + } + + return hr; +} + + +static UINT dxBindFlags(SVGA3dSurfaceAllFlags surfaceFlags) +{ + /* Catch unimplemented flags. */ + Assert(!RT_BOOL(surfaceFlags & (SVGA3D_SURFACE_BIND_LOGICOPS | SVGA3D_SURFACE_BIND_RAW_VIEWS))); + + UINT BindFlags = 0; + + if (surfaceFlags & (SVGA3D_SURFACE_BIND_VERTEX_BUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER)) + BindFlags |= D3D11_BIND_VERTEX_BUFFER; + if (surfaceFlags & (SVGA3D_SURFACE_BIND_INDEX_BUFFER | SVGA3D_SURFACE_HINT_INDEXBUFFER)) + BindFlags |= D3D11_BIND_INDEX_BUFFER; + if (surfaceFlags & SVGA3D_SURFACE_BIND_CONSTANT_BUFFER) BindFlags |= D3D11_BIND_CONSTANT_BUFFER; + if (surfaceFlags & SVGA3D_SURFACE_BIND_SHADER_RESOURCE) BindFlags |= D3D11_BIND_SHADER_RESOURCE; + if (surfaceFlags & SVGA3D_SURFACE_BIND_RENDER_TARGET) BindFlags |= D3D11_BIND_RENDER_TARGET; + if (surfaceFlags & SVGA3D_SURFACE_BIND_DEPTH_STENCIL) BindFlags |= D3D11_BIND_DEPTH_STENCIL; + if (surfaceFlags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) BindFlags |= D3D11_BIND_STREAM_OUTPUT; + if (surfaceFlags & SVGA3D_SURFACE_BIND_UAVIEW) BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + return BindFlags; +} + + +static DXDEVICE *dxSurfaceDevice(PVMSVGA3DSTATE p3dState, PVMSVGA3DSURFACE pSurface, PVMSVGA3DDXCONTEXT pDXContext, UINT *pMiscFlags) +{ + if (p3dState->pBackend->fSingleDevice) + { + *pMiscFlags = 0; + return &p3dState->pBackend->dxDevice; + } + + if (!pDXContext || dxIsSurfaceShareable(pSurface)) + { + *pMiscFlags = D3D11_RESOURCE_MISC_SHARED; + return &p3dState->pBackend->dxDevice; + } + + *pMiscFlags = 0; + return &pDXContext->pBackendDXContext->dxDevice; +} + + +static DXGI_FORMAT dxGetDxgiTypelessFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return DXGI_FORMAT_R32G32B32A32_TYPELESS; /* 1 */ + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return DXGI_FORMAT_R32G32B32_TYPELESS; /* 5 */ + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_TYPELESS; /* 9 */ + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + return DXGI_FORMAT_R32G32_TYPELESS; /* 15 */ + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return DXGI_FORMAT_R32G8X24_TYPELESS; /* 19 */ + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + return DXGI_FORMAT_R10G10B10A2_TYPELESS; /* 23 */ + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_TYPELESS; /* 27 */ + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_TYPELESS; /* 33 */ + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + return DXGI_FORMAT_R32_TYPELESS; /* 39 */ + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return DXGI_FORMAT_R24G8_TYPELESS; /* 44 */ + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_TYPELESS; /* 48*/ + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_TYPELESS; /* 53 */ + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + return DXGI_FORMAT_R8_TYPELESS; /* 60*/ + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return DXGI_FORMAT_BC1_TYPELESS; /* 70 */ + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return DXGI_FORMAT_BC2_TYPELESS; /* 73 */ + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return DXGI_FORMAT_BC3_TYPELESS; /* 76 */ + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return DXGI_FORMAT_BC4_TYPELESS; /* 79 */ + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + return DXGI_FORMAT_BC5_TYPELESS; /* 82 */ + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return DXGI_FORMAT_B8G8R8A8_TYPELESS; /* 90 */ + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return DXGI_FORMAT_B8G8R8X8_TYPELESS; /* 92 */ + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + return DXGI_FORMAT_BC6H_TYPELESS; /* 94 */ + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return DXGI_FORMAT_BC7_TYPELESS; /* 97 */ + default: + break; + } + + return dxgiFormat; +} + + +static bool dxIsDepthStencilFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_D16_UNORM: + return true; + default: + break; + } + + return false; +} + + +static int vmsvga3dBackSurfaceCreateTexture(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PVMSVGA3DSURFACE pSurface) +{ + PVMSVGA3DSTATE p3dState = pThisCC->svga.p3dState; + AssertReturn(p3dState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = p3dState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + UINT MiscFlags; + DXDEVICE *pDXDevice = dxSurfaceDevice(p3dState, pSurface, pDXContext, &MiscFlags); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + if (pSurface->pBackendSurface != NULL) + { + AssertFailed(); /** @todo Should the function not be used like that? */ + vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + + PVMSVGA3DBACKENDSURFACE pBackendSurface; + int rc = dxBackendSurfaceAlloc(&pBackendSurface); + AssertRCReturn(rc, rc); + + uint32_t const cWidth = pSurface->paMipmapLevels[0].cBlocksX * pSurface->cxBlock; + uint32_t const cHeight = pSurface->paMipmapLevels[0].cBlocksY * pSurface->cyBlock; + uint32_t const cDepth = pSurface->paMipmapLevels[0].mipmapSize.depth; + uint32_t const numMipLevels = pSurface->cLevels; + + DXGI_FORMAT dxgiFormat = vmsvgaDXSurfaceFormat2Dxgi(pSurface->format); + AssertReturn(dxgiFormat != DXGI_FORMAT_UNKNOWN, E_FAIL); + + /* Create typeless textures, unless it is a depth/stencil resource, + * because D3D11_BIND_DEPTH_STENCIL requires a depth/stencil format. + * Always use typeless format for staging/dynamic resources. + */ + DXGI_FORMAT const dxgiFormatTypeless = dxGetDxgiTypelessFormat(dxgiFormat); + if (!dxIsDepthStencilFormat(dxgiFormat)) + dxgiFormat = dxgiFormatTypeless; + + /* Format for staging resource is always the typeless one. */ + DXGI_FORMAT const dxgiFormatStaging = dxgiFormatTypeless; + + DXGI_FORMAT dxgiFormatDynamic; + /* Some drivers do not allow to use depth typeless formats for dynamic resources. + * Create a placeholder texture (it does not work with CopySubresource). + */ + /** @todo Implement upload from such textures. */ + if (dxgiFormatTypeless == DXGI_FORMAT_R24G8_TYPELESS) + dxgiFormatDynamic = DXGI_FORMAT_R32_UINT; + else if (dxgiFormatTypeless == DXGI_FORMAT_R32G8X24_TYPELESS) + dxgiFormatDynamic = DXGI_FORMAT_R32G32_UINT; + else + dxgiFormatDynamic = dxgiFormatTypeless; + + /* + * Create D3D11 texture object. + */ + D3D11_SUBRESOURCE_DATA *paInitialData = NULL; + if (pSurface->paMipmapLevels[0].pSurfaceData) + { + /* Can happen for a non GBO surface or if GBO texture was updated prior to creation of the hardware resource. */ + uint32_t const cSubresource = numMipLevels * pSurface->surfaceDesc.numArrayElements; + paInitialData = (D3D11_SUBRESOURCE_DATA *)RTMemAlloc(cSubresource * sizeof(D3D11_SUBRESOURCE_DATA)); + AssertPtrReturn(paInitialData, VERR_NO_MEMORY); + + for (uint32_t i = 0; i < cSubresource; ++i) + { + PVMSVGA3DMIPMAPLEVEL pMipmapLevel = &pSurface->paMipmapLevels[i]; + D3D11_SUBRESOURCE_DATA *p = &paInitialData[i]; + p->pSysMem = pMipmapLevel->pSurfaceData; + p->SysMemPitch = pMipmapLevel->cbSurfacePitch; + p->SysMemSlicePitch = pMipmapLevel->cbSurfacePlane; + } + } + + HRESULT hr = S_OK; + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_CUBEMAP) + { + Assert(pSurface->cFaces == 6); + Assert(cWidth == cHeight); + Assert(cDepth == 1); +//DEBUG_BREAKPOINT_TEST(); + + D3D11_TEXTURE2D_DESC td; + RT_ZERO(td); + td.Width = cWidth; + td.Height = cHeight; + td.MipLevels = numMipLevels; + td.ArraySize = pSurface->surfaceDesc.numArrayElements; /* This is 6 * numCubes */ + td.Format = dxgiFormat; + td.SampleDesc.Count = 1; + td.SampleDesc.Quality = 0; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + td.CPUAccessFlags = 0; /** @todo */ + td.MiscFlags = MiscFlags | D3D11_RESOURCE_MISC_TEXTURECUBE; /** @todo */ + if ( numMipLevels > 1 + && (td.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) == (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + td.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; /* Required for GenMips. */ + + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->u.pTexture2D); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + { + /* Map-able texture. */ + td.Format = dxgiFormatDynamic; + td.MipLevels = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.ArraySize = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.Usage = D3D11_USAGE_DYNAMIC; + td.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->dynamic.pTexture2D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + td.Format = dxgiFormatStaging; + td.Usage = D3D11_USAGE_STAGING; + td.BindFlags = 0; /* No flags allowed. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->staging.pTexture2D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + hr = dxInitSharedHandle(pBackend, pBackendSurface); + + if (SUCCEEDED(hr)) + { + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_TEXTURE_CUBE; + } + } + else if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_1D) + { + /* + * 1D texture. + */ + Assert(pSurface->cFaces == 1); + + D3D11_TEXTURE1D_DESC td; + RT_ZERO(td); + td.Width = cWidth; + td.MipLevels = numMipLevels; + td.ArraySize = pSurface->surfaceDesc.numArrayElements; + td.Format = dxgiFormat; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + td.CPUAccessFlags = 0; + td.MiscFlags = MiscFlags; /** @todo */ + if ( numMipLevels > 1 + && (td.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) == (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + td.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; /* Required for GenMips. */ + + hr = pDXDevice->pDevice->CreateTexture1D(&td, paInitialData, &pBackendSurface->u.pTexture1D); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + { + /* Map-able texture. */ + td.Format = dxgiFormatDynamic; + td.MipLevels = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.ArraySize = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.Usage = D3D11_USAGE_DYNAMIC; + td.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture1D(&td, paInitialData, &pBackendSurface->dynamic.pTexture1D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + td.Format = dxgiFormatStaging; + td.Usage = D3D11_USAGE_STAGING; + td.BindFlags = 0; /* No flags allowed. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture1D(&td, paInitialData, &pBackendSurface->staging.pTexture1D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + hr = dxInitSharedHandle(pBackend, pBackendSurface); + + if (SUCCEEDED(hr)) + { + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_TEXTURE_1D; + } + } + else + { + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_VOLUME) + { + /* + * Volume texture. + */ + Assert(pSurface->cFaces == 1); + Assert(pSurface->surfaceDesc.numArrayElements == 1); + + D3D11_TEXTURE3D_DESC td; + RT_ZERO(td); + td.Width = cWidth; + td.Height = cHeight; + td.Depth = cDepth; + td.MipLevels = numMipLevels; + td.Format = dxgiFormat; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + td.CPUAccessFlags = 0; /** @todo */ + td.MiscFlags = MiscFlags; /** @todo */ + if ( numMipLevels > 1 + && (td.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) == (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + td.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; /* Required for GenMips. */ + + hr = pDXDevice->pDevice->CreateTexture3D(&td, paInitialData, &pBackendSurface->u.pTexture3D); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + { + /* Map-able texture. */ + td.Format = dxgiFormatDynamic; + td.MipLevels = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.Usage = D3D11_USAGE_DYNAMIC; + td.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture3D(&td, paInitialData, &pBackendSurface->dynamic.pTexture3D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + td.Format = dxgiFormatStaging; + td.Usage = D3D11_USAGE_STAGING; + td.BindFlags = 0; /* No flags allowed. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture3D(&td, paInitialData, &pBackendSurface->staging.pTexture3D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + hr = dxInitSharedHandle(pBackend, pBackendSurface); + + if (SUCCEEDED(hr)) + { + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_TEXTURE_3D; + } + } + else + { + /* + * 2D texture. + */ + Assert(cDepth == 1); + Assert(pSurface->cFaces == 1); + + D3D11_TEXTURE2D_DESC td; + RT_ZERO(td); + td.Width = cWidth; + td.Height = cHeight; + td.MipLevels = numMipLevels; + td.ArraySize = pSurface->surfaceDesc.numArrayElements; + td.Format = dxgiFormat; + td.SampleDesc.Count = 1; + td.SampleDesc.Quality = 0; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + td.CPUAccessFlags = 0; /** @todo */ + td.MiscFlags = MiscFlags; /** @todo */ + if ( numMipLevels > 1 + && (td.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) == (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET)) + td.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; /* Required for GenMips. */ + + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->u.pTexture2D); + Assert(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) + { + /* Map-able texture. */ + td.Format = dxgiFormatDynamic; + td.MipLevels = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.ArraySize = 1; /* Must be for D3D11_USAGE_DYNAMIC. */ + td.Usage = D3D11_USAGE_DYNAMIC; + td.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->dynamic.pTexture2D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + td.Format = dxgiFormatStaging; + td.Usage = D3D11_USAGE_STAGING; + td.BindFlags = 0; /* No flags allowed. */ + td.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + td.MiscFlags = 0; + hr = pDXDevice->pDevice->CreateTexture2D(&td, paInitialData, &pBackendSurface->staging.pTexture2D); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + hr = dxInitSharedHandle(pBackend, pBackendSurface); + + if (SUCCEEDED(hr)) + { + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_TEXTURE_2D; + } + } + } + + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + DEBUG_BREAKPOINT_TEST(); + hr = pDXDevice->pDevice->GetDeviceRemovedReason(); + } + + Assert(hr == S_OK); + + RTMemFree(paInitialData); + + if (pSurface->autogenFilter != SVGA3D_TEX_FILTER_NONE) + { + } + + if (SUCCEEDED(hr)) + { + /* + * Success. + */ + LogFunc(("sid = %u\n", pSurface->id)); + pBackendSurface->enmDxgiFormat = dxgiFormat; + pSurface->pBackendSurface = pBackendSurface; + if (p3dState->pBackend->fSingleDevice || RT_BOOL(MiscFlags & D3D11_RESOURCE_MISC_SHARED)) + pSurface->idAssociatedContext = DX_CID_BACKEND; + else + pSurface->idAssociatedContext = pDXContext->cid; + return VINF_SUCCESS; + } + + D3D_RELEASE(pBackendSurface->staging.pResource); + D3D_RELEASE(pBackendSurface->dynamic.pResource); + D3D_RELEASE(pBackendSurface->u.pResource); + RTMemFree(pBackendSurface); + return VERR_NO_MEMORY; +} + + +static int vmsvga3dBackSurfaceCreateBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PVMSVGA3DSURFACE pSurface) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Buffers should be created as such. */ + AssertReturn(RT_BOOL(pSurface->f.surfaceFlags & ( SVGA3D_SURFACE_HINT_INDEXBUFFER + | SVGA3D_SURFACE_HINT_VERTEXBUFFER + | SVGA3D_SURFACE_BIND_VERTEX_BUFFER + | SVGA3D_SURFACE_BIND_INDEX_BUFFER + )), VERR_INVALID_PARAMETER); + + if (pSurface->pBackendSurface != NULL) + { + AssertFailed(); /** @todo Should the function not be used like that? */ + vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + int rc = vmsvga3dMipmapLevel(pSurface, 0, 0, &pMipLevel); + AssertRCReturn(rc, rc); + + PVMSVGA3DBACKENDSURFACE pBackendSurface; + rc = dxBackendSurfaceAlloc(&pBackendSurface); + AssertRCReturn(rc, rc); + + LogFunc(("sid = %u, size = %u\n", pSurface->id, pMipLevel->cbSurface)); + + /* Upload the current data, if any. */ + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_SUBRESOURCE_DATA initialData; + if (pMipLevel->pSurfaceData) + { + initialData.pSysMem = pMipLevel->pSurfaceData; + initialData.SysMemPitch = pMipLevel->cbSurface; + initialData.SysMemSlicePitch = pMipLevel->cbSurface; + + pInitialData = &initialData; + } + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = pMipLevel->cbSurface; + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->u.pBuffer); + Assert(SUCCEEDED(hr)); +#ifndef DX_COMMON_STAGING_BUFFER + if (SUCCEEDED(hr)) + { + /* Map-able Buffer. */ + bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->dynamic.pBuffer); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + bd.Usage = D3D11_USAGE_STAGING; + bd.BindFlags = 0; /* No flags allowed. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->staging.pBuffer); + Assert(SUCCEEDED(hr)); + } +#endif + + if (SUCCEEDED(hr)) + { + /* + * Success. + */ + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_BUFFER; + pBackendSurface->enmDxgiFormat = DXGI_FORMAT_UNKNOWN; + pSurface->pBackendSurface = pBackendSurface; + pSurface->idAssociatedContext = pDXContext->cid; + return VINF_SUCCESS; + } + + /* Failure. */ + D3D_RELEASE(pBackendSurface->u.pBuffer); +#ifndef DX_COMMON_STAGING_BUFFER + D3D_RELEASE(pBackendSurface->dynamic.pBuffer); + D3D_RELEASE(pBackendSurface->staging.pBuffer); +#endif + RTMemFree(pBackendSurface); + return VERR_NO_MEMORY; +} + + +static int vmsvga3dBackSurfaceCreateSoBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PVMSVGA3DSURFACE pSurface) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Buffers should be created as such. */ + AssertReturn(RT_BOOL(pSurface->f.surfaceFlags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT), VERR_INVALID_PARAMETER); + + if (pSurface->pBackendSurface != NULL) + { + AssertFailed(); /** @todo Should the function not be used like that? */ + vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + + PVMSVGA3DBACKENDSURFACE pBackendSurface; + int rc = dxBackendSurfaceAlloc(&pBackendSurface); + AssertRCReturn(rc, rc); + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = pSurface->paMipmapLevels[0].cbSurface; + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + bd.CPUAccessFlags = 0; /// @todo ? D3D11_CPU_ACCESS_READ; + bd.MiscFlags = 0; + bd.StructureByteStride = 0; + + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, 0, &pBackendSurface->u.pBuffer); +#ifndef DX_COMMON_STAGING_BUFFER + if (SUCCEEDED(hr)) + { + /* Map-able Buffer. */ + bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, 0, &pBackendSurface->dynamic.pBuffer); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + bd.Usage = D3D11_USAGE_STAGING; + bd.BindFlags = 0; /* No flags allowed. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, 0, &pBackendSurface->staging.pBuffer); + Assert(SUCCEEDED(hr)); + } +#endif + + if (SUCCEEDED(hr)) + { + /* + * Success. + */ + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_BUFFER; + pBackendSurface->enmDxgiFormat = DXGI_FORMAT_UNKNOWN; + pSurface->pBackendSurface = pBackendSurface; + pSurface->idAssociatedContext = pDXContext->cid; + return VINF_SUCCESS; + } + + /* Failure. */ + D3D_RELEASE(pBackendSurface->u.pBuffer); +#ifndef DX_COMMON_STAGING_BUFFER + D3D_RELEASE(pBackendSurface->dynamic.pBuffer); + D3D_RELEASE(pBackendSurface->staging.pBuffer); +#endif + RTMemFree(pBackendSurface); + return VERR_NO_MEMORY; +} + +#if 0 +static int vmsvga3dBackSurfaceCreateConstantBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PVMSVGA3DSURFACE pSurface, uint32_t offsetInBytes, uint32_t sizeInBytes) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Buffers should be created as such. */ + AssertReturn(RT_BOOL(pSurface->f.surfaceFlags & ( SVGA3D_SURFACE_BIND_CONSTANT_BUFFER)), VERR_INVALID_PARAMETER); + + if (pSurface->pBackendSurface != NULL) + { + AssertFailed(); /** @todo Should the function not be used like that? */ + vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + int rc = vmsvga3dMipmapLevel(pSurface, 0, 0, &pMipLevel); + AssertRCReturn(rc, rc); + + ASSERT_GUEST_RETURN( offsetInBytes < pMipLevel->cbSurface + && sizeInBytes <= pMipLevel->cbSurface - offsetInBytes, VERR_INVALID_PARAMETER); + + PVMSVGA3DBACKENDSURFACE pBackendSurface; + rc = dxBackendSurfaceAlloc(&pBackendSurface); + AssertRCReturn(rc, rc); + + /* Upload the current data, if any. */ + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_SUBRESOURCE_DATA initialData; + if (pMipLevel->pSurfaceData) + { + initialData.pSysMem = (uint8_t *)pMipLevel->pSurfaceData + offsetInBytes; + initialData.SysMemPitch = pMipLevel->cbSurface; + initialData.SysMemSlicePitch = pMipLevel->cbSurface; + + pInitialData = &initialData; + + // Log(("%.*Rhxd\n", sizeInBytes, initialData.pSysMem)); + } + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = sizeInBytes; + bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bd.MiscFlags = 0; + bd.StructureByteStride = 0; + + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->u.pBuffer); + if (SUCCEEDED(hr)) + { + /* + * Success. + */ + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_BUFFER; + pBackendSurface->enmDxgiFormat = DXGI_FORMAT_UNKNOWN; + pSurface->pBackendSurface = pBackendSurface; + pSurface->idAssociatedContext = pDXContext->cid; + return VINF_SUCCESS; + } + + /* Failure. */ + D3D_RELEASE(pBackendSurface->u.pBuffer); + RTMemFree(pBackendSurface); + return VERR_NO_MEMORY; +} +#endif + +static int vmsvga3dBackSurfaceCreateResource(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PVMSVGA3DSURFACE pSurface) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + if (pSurface->pBackendSurface != NULL) + { + AssertFailed(); /** @todo Should the function not be used like that? */ + vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + int rc = vmsvga3dMipmapLevel(pSurface, 0, 0, &pMipLevel); + AssertRCReturn(rc, rc); + + PVMSVGA3DBACKENDSURFACE pBackendSurface; + rc = dxBackendSurfaceAlloc(&pBackendSurface); + AssertRCReturn(rc, rc); + + HRESULT hr; + + /* + * Figure out the type of the surface. + */ + if (pSurface->format == SVGA3D_BUFFER) + { + /* Upload the current data, if any. */ + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_SUBRESOURCE_DATA initialData; + if (pMipLevel->pSurfaceData) + { + initialData.pSysMem = pMipLevel->pSurfaceData; + initialData.SysMemPitch = pMipLevel->cbSurface; + initialData.SysMemSlicePitch = pMipLevel->cbSurface; + + pInitialData = &initialData; + } + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = pMipLevel->cbSurface; + + if (pSurface->f.surfaceFlags & (SVGA3D_SURFACE_STAGING_UPLOAD | SVGA3D_SURFACE_STAGING_DOWNLOAD)) + bd.Usage = D3D11_USAGE_STAGING; + else if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_HINT_DYNAMIC) + bd.Usage = D3D11_USAGE_DYNAMIC; + else if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_HINT_STATIC) + bd.Usage = pInitialData ? D3D11_USAGE_IMMUTABLE : D3D11_USAGE_DEFAULT; /* Guest will update later. */ + else if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_HINT_INDIRECT_UPDATE) + bd.Usage = D3D11_USAGE_DEFAULT; + + bd.BindFlags = dxBindFlags(pSurface->f.surfaceFlags); + + if (bd.Usage == D3D11_USAGE_STAGING) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; + else if (bd.Usage == D3D11_USAGE_DYNAMIC) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_DRAWINDIRECT_ARGS) + bd.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_BIND_RAW_VIEWS) + bd.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_BUFFER_STRUCTURED) + bd.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + if (pSurface->f.surfaceFlags & SVGA3D_SURFACE_RESOURCE_CLAMP) + bd.MiscFlags |= D3D11_RESOURCE_MISC_RESOURCE_CLAMP; + + if (bd.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) + { + SVGAOTableSurfaceEntry entrySurface; + rc = vmsvgaR3OTableReadSurface(pThisCC->svga.pSvgaR3State, pSurface->id, &entrySurface); + AssertRCReturn(rc, rc); + + bd.StructureByteStride = entrySurface.bufferByteStride; + } + + hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->u.pBuffer); + Assert(SUCCEEDED(hr)); +#ifndef DX_COMMON_STAGING_BUFFER + if (SUCCEEDED(hr)) + { + /* Map-able Buffer. */ + bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_SHADER_RESOURCE; /* Have to specify a supported flag, otherwise E_INVALIDARG will be returned. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->dynamic.pBuffer); + Assert(SUCCEEDED(hr)); + } + + if (SUCCEEDED(hr)) + { + /* Staging texture. */ + bd.Usage = D3D11_USAGE_STAGING; + bd.BindFlags = 0; /* No flags allowed. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBackendSurface->staging.pBuffer); + Assert(SUCCEEDED(hr)); + } +#endif + if (SUCCEEDED(hr)) + { + pBackendSurface->enmResType = VMSVGA3D_RESTYPE_BUFFER; + pBackendSurface->enmDxgiFormat = DXGI_FORMAT_UNKNOWN; + } + } + else + { + /** @todo Texture. Currently vmsvga3dBackSurfaceCreateTexture is called for textures. */ + AssertFailed(); + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + /* + * Success. + */ + pSurface->pBackendSurface = pBackendSurface; + pSurface->idAssociatedContext = pDXContext->cid; + return VINF_SUCCESS; + } + + /* Failure. */ + D3D_RELEASE(pBackendSurface->u.pResource); + D3D_RELEASE(pBackendSurface->dynamic.pResource); + D3D_RELEASE(pBackendSurface->staging.pResource); + RTMemFree(pBackendSurface); + return VERR_NO_MEMORY; +} + + +#ifdef DX_COMMON_STAGING_BUFFER +static int dxStagingBufferRealloc(DXDEVICE *pDXDevice, uint32_t cbRequiredSize) +{ + AssertReturn(cbRequiredSize < SVGA3D_MAX_SURFACE_MEM_SIZE, VERR_INVALID_PARAMETER); + + if (RT_LIKELY(cbRequiredSize <= pDXDevice->cbStagingBuffer)) + return VINF_SUCCESS; + + D3D_RELEASE(pDXDevice->pStagingBuffer); + + uint32_t const cbAlloc = RT_ALIGN_32(cbRequiredSize, _64K); + + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = cbAlloc; + bd.Usage = D3D11_USAGE_STAGING; + //bd.BindFlags = 0; /* No bind flags are allowed for staging resources. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; + + int rc = VINF_SUCCESS; + ID3D11Buffer *pBuffer; + HRESULT hr = pDXDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBuffer); + if (SUCCEEDED(hr)) + { + pDXDevice->pStagingBuffer = pBuffer; + pDXDevice->cbStagingBuffer = cbAlloc; + } + else + { + pDXDevice->cbStagingBuffer = 0; + rc = VERR_NO_MEMORY; + } + + return rc; +} +#endif + + +static DECLCALLBACK(int) vmsvga3dBackInit(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC) +{ + RT_NOREF(pDevIns, pThis); + + int rc; +#ifdef RT_OS_LINUX /** @todo Remove, this is currently needed for loading the X11 library in order to call XInitThreads(). */ + rc = glLdrInit(pDevIns); + if (RT_FAILURE(rc)) + { + LogRel(("VMSVGA3d: Error loading OpenGL library and resolving necessary functions: %Rrc\n", rc)); + return rc; + } +#endif + + PVMSVGA3DBACKEND pBackend = (PVMSVGA3DBACKEND)RTMemAllocZ(sizeof(VMSVGA3DBACKEND)); + AssertReturn(pBackend, VERR_NO_MEMORY); + pThisCC->svga.p3dState->pBackend = pBackend; + + rc = RTLdrLoadSystem(VBOX_D3D11_LIBRARY_NAME, /* fNoUnload = */ true, &pBackend->hD3D11); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + rc = RTLdrGetSymbol(pBackend->hD3D11, "D3D11CreateDevice", (void **)&pBackend->pfnD3D11CreateDevice); + AssertRC(rc); + } + + if (RT_SUCCESS(rc)) + { + /* Failure to load the shader disassembler is ignored. */ + int rc2 = RTLdrLoadSystem("D3DCompiler_47", /* fNoUnload = */ true, &pBackend->hD3DCompiler); + if (RT_SUCCESS(rc2)) + rc2 = RTLdrGetSymbol(pBackend->hD3DCompiler, "D3DDisassemble", (void **)&pBackend->pfnD3DDisassemble); + Log6Func(("Load D3DDisassemble: %Rrc\n", rc2)); + } + +#if !defined(RT_OS_WINDOWS) || defined(DX_FORCE_SINGLE_DEVICE) + pBackend->fSingleDevice = true; +#endif + + LogRelMax(1, ("VMSVGA: Single DX device mode: %s\n", pBackend->fSingleDevice ? "enabled" : "disabled")); + +//DEBUG_BREAKPOINT_TEST(); + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackPowerOn(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTATECC pThisCC) +{ + RT_NOREF(pDevIns, pThis); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + int rc = dxDeviceCreate(pBackend, &pBackend->dxDevice); + if (RT_SUCCESS(rc)) + { + IDXGIAdapter *pAdapter = NULL; + HRESULT hr = pBackend->dxDevice.pDxgiFactory->EnumAdapters(0, &pAdapter); + if (SUCCEEDED(hr)) + { + DXGI_ADAPTER_DESC desc; + hr = pAdapter->GetDesc(&desc); + if (SUCCEEDED(hr)) + { + char sz[RT_ELEMENTS(desc.Description)]; + for (unsigned i = 0; i < RT_ELEMENTS(desc.Description); ++i) + sz[i] = (char)desc.Description[i]; + LogRelMax(1, ("VMSVGA: Adapter [%s]\n", sz)); + } + + pAdapter->Release(); + } + } + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackReset(PVGASTATECC pThisCC) +{ + RT_NOREF(pThisCC); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackTerminate(PVGASTATECC pThisCC) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + if (pState->pBackend) + dxDeviceDestroy(pState->pBackend, &pState->pBackend->dxDevice); + + return VINF_SUCCESS; +} + + +/** @todo Such structures must be in VBoxVideo3D.h */ +typedef struct VBOX3DNOTIFYDEFINESCREEN +{ + VBOX3DNOTIFY Core; + uint32_t cWidth; + uint32_t cHeight; + int32_t xRoot; + int32_t yRoot; + uint32_t fPrimary; + uint32_t cDpi; +} VBOX3DNOTIFYDEFINESCREEN; + + +static int vmsvga3dDrvNotifyDefineScreen(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen) +{ + VBOX3DNOTIFYDEFINESCREEN n; + n.Core.enmNotification = VBOX3D_NOTIFY_TYPE_HW_SCREEN_CREATED; + n.Core.iDisplay = pScreen->idScreen; + n.Core.u32Reserved = 0; + n.Core.cbData = sizeof(n) - RT_UOFFSETOF(VBOX3DNOTIFY, au8Data); + RT_ZERO(n.Core.au8Data); + n.cWidth = pScreen->cWidth; + n.cHeight = pScreen->cHeight; + n.xRoot = pScreen->xOrigin; + n.yRoot = pScreen->yOrigin; + n.fPrimary = RT_BOOL(pScreen->fuScreen & SVGA_SCREEN_IS_PRIMARY); + n.cDpi = pScreen->cDpi; + + return pThisCC->pDrv->pfn3DNotifyProcess(pThisCC->pDrv, &n.Core); +} + + +static int vmsvga3dDrvNotifyDestroyScreen(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen) +{ + VBOX3DNOTIFY n; + n.enmNotification = VBOX3D_NOTIFY_TYPE_HW_SCREEN_DESTROYED; + n.iDisplay = pScreen->idScreen; + n.u32Reserved = 0; + n.cbData = sizeof(n) - RT_UOFFSETOF(VBOX3DNOTIFY, au8Data); + RT_ZERO(n.au8Data); + + return pThisCC->pDrv->pfn3DNotifyProcess(pThisCC->pDrv, &n); +} + + +static int vmsvga3dDrvNotifyBindSurface(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, HANDLE hSharedSurface) +{ + VBOX3DNOTIFY n; + n.enmNotification = VBOX3D_NOTIFY_TYPE_HW_SCREEN_BIND_SURFACE; + n.iDisplay = pScreen->idScreen; + n.u32Reserved = 0; + n.cbData = sizeof(n) - RT_UOFFSETOF(VBOX3DNOTIFY, au8Data); + *(uint64_t *)&n.au8Data[0] = (uint64_t)hSharedSurface; + + return pThisCC->pDrv->pfn3DNotifyProcess(pThisCC->pDrv, &n); +} + + +typedef struct VBOX3DNOTIFYUPDATE +{ + VBOX3DNOTIFY Core; + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +} VBOX3DNOTIFYUPDATE; + + +static int vmsvga3dDrvNotifyUpdate(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + VBOX3DNOTIFYUPDATE n; + n.Core.enmNotification = VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_END; + n.Core.iDisplay = pScreen->idScreen; + n.Core.u32Reserved = 0; + n.Core.cbData = sizeof(n) - RT_UOFFSETOF(VBOX3DNOTIFY, au8Data); + RT_ZERO(n.Core.au8Data); + n.x = x; + n.y = y; + n.w = w; + n.h = h; + + return pThisCC->pDrv->pfn3DNotifyProcess(pThisCC->pDrv, &n.Core); +} + +static int vmsvga3dHwScreenCreate(PVMSVGA3DSTATE pState, uint32_t cWidth, uint32_t cHeight, VMSVGAHWSCREEN *p) +{ + PVMSVGA3DBACKEND pBackend = pState->pBackend; + + DXDEVICE *pDXDevice = &pBackend->dxDevice; + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + D3D11_TEXTURE2D_DESC td; + RT_ZERO(td); + td.Width = cWidth; + td.Height = cHeight; + td.MipLevels = 1; + td.ArraySize = 1; + td.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + td.SampleDesc.Count = 1; + td.SampleDesc.Quality = 0; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + td.CPUAccessFlags = 0; + td.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; + + HRESULT hr = pDXDevice->pDevice->CreateTexture2D(&td, 0, &p->pTexture); + if (SUCCEEDED(hr)) + { + /* Get the shared handle. */ + hr = p->pTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&p->pDxgiResource); + if (SUCCEEDED(hr)) + { + hr = p->pDxgiResource->GetSharedHandle(&p->SharedHandle); + if (SUCCEEDED(hr)) + hr = p->pTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&p->pDXGIKeyedMutex); + } + } + + if (SUCCEEDED(hr)) + return VINF_SUCCESS; + + AssertFailed(); + return VERR_NOT_SUPPORTED; +} + + +static void vmsvga3dHwScreenDestroy(PVMSVGA3DSTATE pState, VMSVGAHWSCREEN *p) +{ + RT_NOREF(pState); + D3D_RELEASE(p->pDXGIKeyedMutex); + D3D_RELEASE(p->pDxgiResource); + D3D_RELEASE(p->pTexture); + p->SharedHandle = 0; + p->sidScreenTarget = SVGA_ID_INVALID; +} + + +static DECLCALLBACK(int) vmsvga3dBackDefineScreen(PVGASTATE pThis, PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen) +{ + RT_NOREF(pThis, pThisCC, pScreen); + + LogRel4(("VMSVGA: vmsvga3dBackDefineScreen: screen %u\n", pScreen->idScreen)); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + Assert(pScreen->pHwScreen == NULL); + + VMSVGAHWSCREEN *p = (VMSVGAHWSCREEN *)RTMemAllocZ(sizeof(VMSVGAHWSCREEN)); + AssertPtrReturn(p, VERR_NO_MEMORY); + + p->sidScreenTarget = SVGA_ID_INVALID; + + int rc = vmsvga3dDrvNotifyDefineScreen(pThisCC, pScreen); + if (RT_SUCCESS(rc)) + { + /* The frontend supports the screen. Create the actual resource. */ + rc = vmsvga3dHwScreenCreate(pState, pScreen->cWidth, pScreen->cHeight, p); + if (RT_SUCCESS(rc)) + LogRel4(("VMSVGA: vmsvga3dBackDefineScreen: created\n")); + } + + if (RT_SUCCESS(rc)) + { + LogRel(("VMSVGA: Using HW accelerated screen %u\n", pScreen->idScreen)); + pScreen->pHwScreen = p; + } + else + { + LogRel4(("VMSVGA: vmsvga3dBackDefineScreen: %Rrc\n", rc)); + vmsvga3dHwScreenDestroy(pState, p); + RTMemFree(p); + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackDestroyScreen(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + vmsvga3dDrvNotifyDestroyScreen(pThisCC, pScreen); + + if (pScreen->pHwScreen) + { + vmsvga3dHwScreenDestroy(pState, pScreen->pHwScreen); + RTMemFree(pScreen->pHwScreen); + pScreen->pHwScreen = NULL; + } + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceBlitToScreen(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, + SVGASignedRect destRect, SVGA3dSurfaceImageId srcImage, + SVGASignedRect srcRect, uint32_t cRects, SVGASignedRect *paRects) +{ + RT_NOREF(pThisCC, pScreen, destRect, srcImage, srcRect, cRects, paRects); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + VMSVGAHWSCREEN *p = pScreen->pHwScreen; + AssertReturn(p, VERR_NOT_SUPPORTED); + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pState, srcImage.sid, &pSurface); + AssertRCReturn(rc, rc); + + /** @todo Implement. */ + AssertFailed(); + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceMap(PVGASTATECC pThisCC, SVGA3dSurfaceImageId const *pImage, SVGA3dBox const *pBox, + VMSVGA3D_SURFACE_MAP enmMapType, VMSVGA3D_MAPPED_SURFACE *pMap) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pState, pImage->sid, &pSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + AssertPtrReturn(pBackendSurface, VERR_INVALID_STATE); + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + rc = vmsvga3dMipmapLevel(pSurface, pImage->face, pImage->mipmap, &pMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + /* A surface is always mapped by the DX context which has created the surface. */ + DXDEVICE *pDevice = dxDeviceFromCid(pSurface->idAssociatedContext, pState); + AssertReturn(pDevice && pDevice->pDevice, VERR_INVALID_STATE); + + SVGA3dBox clipBox; + if (pBox) + { + clipBox = *pBox; + vmsvgaR3ClipBox(&pMipLevel->mipmapSize, &clipBox); + ASSERT_GUEST_RETURN(clipBox.w && clipBox.h && clipBox.d, VERR_INVALID_PARAMETER); + } + else + { + clipBox.x = 0; + clipBox.y = 0; + clipBox.z = 0; + clipBox.w = pMipLevel->mipmapSize.width; + clipBox.h = pMipLevel->mipmapSize.height; + clipBox.d = pMipLevel->mipmapSize.depth; + } + + D3D11_MAP d3d11MapType; + switch (enmMapType) + { + case VMSVGA3D_SURFACE_MAP_READ: d3d11MapType = D3D11_MAP_READ; break; + case VMSVGA3D_SURFACE_MAP_WRITE: d3d11MapType = D3D11_MAP_WRITE; break; + case VMSVGA3D_SURFACE_MAP_READ_WRITE: d3d11MapType = D3D11_MAP_READ_WRITE; break; + case VMSVGA3D_SURFACE_MAP_WRITE_DISCARD: d3d11MapType = D3D11_MAP_WRITE_DISCARD; break; + default: + AssertFailed(); + return VERR_INVALID_PARAMETER; + } + + D3D11_MAPPED_SUBRESOURCE mappedResource; + RT_ZERO(mappedResource); + + if ( pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_1D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_CUBE + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_3D) + { + dxSurfaceWait(pState, pSurface, pSurface->idAssociatedContext); + + ID3D11Resource *pMappedResource; + if (enmMapType == VMSVGA3D_SURFACE_MAP_READ) + { + pMappedResource = pBackendSurface->staging.pResource; + + /* Copy the texture content to the staging texture. + * The requested miplevel of the texture is copied to the miplevel 0 of the staging texture, + * because the staging (and dynamic) structures do not have miplevels. + * Always copy entire miplevel so all Dst are zero and pSrcBox is NULL, as D3D11 requires. + */ + ID3D11Resource *pDstResource = pMappedResource; + UINT DstSubresource = 0; + UINT DstX = 0; + UINT DstY = 0; + UINT DstZ = 0; + ID3D11Resource *pSrcResource = pBackendSurface->u.pResource; + UINT SrcSubresource = D3D11CalcSubresource(pImage->mipmap, pImage->face, pSurface->cLevels); + D3D11_BOX *pSrcBox = NULL; + //D3D11_BOX SrcBox; + //SrcBox.left = 0; + //SrcBox.top = 0; + //SrcBox.front = 0; + //SrcBox.right = pMipLevel->mipmapSize.width; + //SrcBox.bottom = pMipLevel->mipmapSize.height; + //SrcBox.back = pMipLevel->mipmapSize.depth; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, pSrcBox); + } + else if (enmMapType == VMSVGA3D_SURFACE_MAP_WRITE) + pMappedResource = pBackendSurface->staging.pResource; + else + pMappedResource = pBackendSurface->dynamic.pResource; + + UINT const Subresource = 0; /* Dynamic or staging textures have one subresource. */ + HRESULT hr = pDevice->pImmediateContext->Map(pMappedResource, Subresource, + d3d11MapType, /* MapFlags = */ 0, &mappedResource); + if (SUCCEEDED(hr)) + vmsvga3dSurfaceMapInit(pMap, enmMapType, &clipBox, pSurface, + mappedResource.pData, mappedResource.RowPitch, mappedResource.DepthPitch); + else + AssertFailedStmt(rc = VERR_NOT_SUPPORTED); + } + else if (pBackendSurface->enmResType == VMSVGA3D_RESTYPE_BUFFER) + { +#ifdef DX_COMMON_STAGING_BUFFER + /* Map the staging buffer. */ + rc = dxStagingBufferRealloc(pDevice, pMipLevel->cbSurface); + if (RT_SUCCESS(rc)) + { + /* The staging buffer does not allow D3D11_MAP_WRITE_DISCARD, so replace it. */ + if (d3d11MapType == D3D11_MAP_WRITE_DISCARD) + d3d11MapType = D3D11_MAP_WRITE; + + if (enmMapType == VMSVGA3D_SURFACE_MAP_READ) + { + /* Copy from the buffer to the staging buffer. */ + ID3D11Resource *pDstResource = pDevice->pStagingBuffer; + UINT DstSubresource = 0; + UINT DstX = clipBox.x; + UINT DstY = clipBox.y; + UINT DstZ = clipBox.z; + ID3D11Resource *pSrcResource = pBackendSurface->u.pResource; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + SrcBox.left = clipBox.x; + SrcBox.top = clipBox.y; + SrcBox.front = clipBox.z; + SrcBox.right = clipBox.w; + SrcBox.bottom = clipBox.h; + SrcBox.back = clipBox.d; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + } + + UINT const Subresource = 0; /* Buffers have only one subresource. */ + HRESULT hr = pDevice->pImmediateContext->Map(pDevice->pStagingBuffer, Subresource, + d3d11MapType, /* MapFlags = */ 0, &mappedResource); + if (SUCCEEDED(hr)) + vmsvga3dSurfaceMapInit(pMap, enmMapType, &clipBox, pSurface, + mappedResource.pData, mappedResource.RowPitch, mappedResource.DepthPitch); + else + AssertFailedStmt(rc = VERR_NOT_SUPPORTED); + } +#else + ID3D11Resource *pMappedResource; + if (enmMapType == VMSVGA3D_SURFACE_MAP_READ) + { + pMappedResource = pBackendSurface->staging.pResource; + + /* Copy the resource content to the staging resource. */ + ID3D11Resource *pDstResource = pMappedResource; + UINT DstSubresource = 0; + UINT DstX = clipBox.x; + UINT DstY = clipBox.y; + UINT DstZ = clipBox.z; + ID3D11Resource *pSrcResource = pBackendSurface->u.pResource; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + SrcBox.left = clipBox.x; + SrcBox.top = clipBox.y; + SrcBox.front = clipBox.z; + SrcBox.right = clipBox.w; + SrcBox.bottom = clipBox.h; + SrcBox.back = clipBox.d; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + } + else if (enmMapType == VMSVGA3D_SURFACE_MAP_WRITE) + pMappedResource = pBackendSurface->staging.pResource; + else + pMappedResource = pBackendSurface->dynamic.pResource; + + UINT const Subresource = 0; /* Dynamic or staging textures have one subresource. */ + HRESULT hr = pDevice->pImmediateContext->Map(pMappedResource, Subresource, + d3d11MapType, /* MapFlags = */ 0, &mappedResource); + if (SUCCEEDED(hr)) + vmsvga3dSurfaceMapInit(pMap, enmMapType, &clipBox, pSurface, + mappedResource.pData, mappedResource.RowPitch, mappedResource.DepthPitch); + else + AssertFailedStmt(rc = VERR_NOT_SUPPORTED); +#endif + } + else + { + // UINT D3D11CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT MipLevels); + /** @todo Implement. */ + AssertFailed(); + rc = VERR_NOT_IMPLEMENTED; + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceUnmap(PVGASTATECC pThisCC, SVGA3dSurfaceImageId const *pImage, VMSVGA3D_MAPPED_SURFACE *pMap, bool fWritten) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pState, pImage->sid, &pSurface); + AssertRCReturn(rc, rc); + + /* The called should not use the function for system memory surfaces. */ + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + AssertReturn(pBackendSurface, VERR_INVALID_PARAMETER); + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + rc = vmsvga3dMipmapLevel(pSurface, pImage->face, pImage->mipmap, &pMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + /* A surface is always mapped by the DX context which has created the surface. */ + DXDEVICE *pDevice = dxDeviceFromCid(pSurface->idAssociatedContext, pState); + AssertReturn(pDevice && pDevice->pDevice, VERR_INVALID_STATE); + + if ( pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_1D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_CUBE + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_3D) + { + ID3D11Resource *pMappedResource; + if (pMap->enmMapType == VMSVGA3D_SURFACE_MAP_READ) + pMappedResource = pBackendSurface->staging.pResource; + else if (pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE) + pMappedResource = pBackendSurface->staging.pResource; + else + pMappedResource = pBackendSurface->dynamic.pResource; + + UINT const Subresource = 0; /* Staging or dynamic textures have one subresource. */ + pDevice->pImmediateContext->Unmap(pMappedResource, Subresource); + + if ( fWritten + && ( pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_READ_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE_DISCARD)) + { + /* If entire resource must be copied then use pSrcBox = NULL and dst point (0,0,0) + * Because DX11 insists on this for some resource types, for example DEPTH_STENCIL resources. + */ + uint32_t const cWidth0 = pSurface->paMipmapLevels[0].mipmapSize.width; + uint32_t const cHeight0 = pSurface->paMipmapLevels[0].mipmapSize.height; + uint32_t const cDepth0 = pSurface->paMipmapLevels[0].mipmapSize.depth; + /** @todo Entire subresource is always mapped. So find a way to copy it back, important for DEPTH_STENCIL mipmaps. */ + bool const fEntireResource = pMap->box.x == 0 && pMap->box.y == 0 && pMap->box.z == 0 + && pMap->box.w == cWidth0 && pMap->box.h == cHeight0 && pMap->box.d == cDepth0; + + ID3D11Resource *pDstResource = pBackendSurface->u.pResource; + UINT DstSubresource = D3D11CalcSubresource(pImage->mipmap, pImage->face, pSurface->cLevels); + UINT DstX = (pMap->box.x / pSurface->cxBlock) * pSurface->cxBlock; + UINT DstY = (pMap->box.y / pSurface->cyBlock) * pSurface->cyBlock; + UINT DstZ = pMap->box.z; + ID3D11Resource *pSrcResource = pMappedResource; + UINT SrcSubresource = Subresource; + D3D11_BOX *pSrcBox; + D3D11_BOX SrcBox; + if (fEntireResource) + pSrcBox = NULL; + else + { + uint32_t const cxBlocks = (pMap->box.w + pSurface->cxBlock - 1) / pSurface->cxBlock; + uint32_t const cyBlocks = (pMap->box.h + pSurface->cyBlock - 1) / pSurface->cyBlock; + + SrcBox.left = DstX; + SrcBox.top = DstY; + SrcBox.front = DstZ; + SrcBox.right = DstX + cxBlocks * pSurface->cxBlock; + SrcBox.bottom = DstY + cyBlocks * pSurface->cyBlock; + SrcBox.back = DstZ + pMap->box.d; + pSrcBox = &SrcBox; + } + + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, pSrcBox); + + pBackendSurface->cidDrawing = pSurface->idAssociatedContext; + } + } + else if (pBackendSurface->enmResType == VMSVGA3D_RESTYPE_BUFFER) + { + Log4(("Unmap buffer sid = %u:\n%.*Rhxd\n", pSurface->id, pMap->cbRow, pMap->pvData)); + +#ifdef DX_COMMON_STAGING_BUFFER + /* Unmap the staging buffer. */ + UINT const Subresource = 0; /* Buffers have only one subresource. */ + pDevice->pImmediateContext->Unmap(pDevice->pStagingBuffer, Subresource); + + /* Copy from the staging buffer to the actual buffer */ + if ( fWritten + && ( pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_READ_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE_DISCARD)) + { + ID3D11Resource *pDstResource = pBackendSurface->u.pResource; + UINT DstSubresource = 0; + UINT DstX = (pMap->box.x / pSurface->cxBlock) * pSurface->cxBlock; + UINT DstY = (pMap->box.y / pSurface->cyBlock) * pSurface->cyBlock; + UINT DstZ = pMap->box.z; + ID3D11Resource *pSrcResource = pDevice->pStagingBuffer; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + + uint32_t const cxBlocks = (pMap->box.w + pSurface->cxBlock - 1) / pSurface->cxBlock; + uint32_t const cyBlocks = (pMap->box.h + pSurface->cyBlock - 1) / pSurface->cyBlock; + + SrcBox.left = DstX; + SrcBox.top = DstY; + SrcBox.front = DstZ; + SrcBox.right = DstX + cxBlocks * pSurface->cxBlock; + SrcBox.bottom = DstY + cyBlocks * pSurface->cyBlock; + SrcBox.back = DstZ + pMap->box.d; + + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + } +#else + ID3D11Resource *pMappedResource; + if (pMap->enmMapType == VMSVGA3D_SURFACE_MAP_READ) + pMappedResource = pBackendSurface->staging.pResource; + else if (pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE) + pMappedResource = pBackendSurface->staging.pResource; + else + pMappedResource = pBackendSurface->dynamic.pResource; + + UINT const Subresource = 0; /* Staging or dynamic textures have one subresource. */ + pDevice->pImmediateContext->Unmap(pMappedResource, Subresource); + + if ( fWritten + && ( pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_READ_WRITE + || pMap->enmMapType == VMSVGA3D_SURFACE_MAP_WRITE_DISCARD)) + { + ID3D11Resource *pDstResource = pBackendSurface->u.pResource; + UINT DstSubresource = 0; + UINT DstX = pMap->box.x; + UINT DstY = pMap->box.y; + UINT DstZ = pMap->box.z; + ID3D11Resource *pSrcResource = pMappedResource; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + SrcBox.left = DstX; + SrcBox.top = DstY; + SrcBox.front = DstZ; + SrcBox.right = DstX + pMap->box.w; + SrcBox.bottom = DstY + pMap->box.h; + SrcBox.back = DstZ + pMap->box.d; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + + pBackendSurface->cidDrawing = pSurface->idAssociatedContext; + } +#endif + } + else + { + AssertFailed(); + rc = VERR_NOT_IMPLEMENTED; + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dScreenTargetBind(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, uint32_t sid) +{ + int rc = VINF_SUCCESS; + + PVMSVGA3DSURFACE pSurface; + if (sid != SVGA_ID_INVALID) + { + /* Create the surface if does not yet exist. */ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + rc = vmsvga3dSurfaceFromSid(pState, sid, &pSurface); + AssertRCReturn(rc, rc); + + if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface)) + { + /* Create the actual texture. */ + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, NULL, pSurface); + AssertRCReturn(rc, rc); + } + } + else + pSurface = NULL; + + /* Notify the HW accelerated screen if it is used. */ + VMSVGAHWSCREEN *pHwScreen = pScreen->pHwScreen; + if (!pHwScreen) + return VINF_SUCCESS; + + /* Same surface -> do nothing. */ + if (pHwScreen->sidScreenTarget == sid) + return VINF_SUCCESS; + + if (sid != SVGA_ID_INVALID) + { + AssertReturn( pSurface->pBackendSurface + && pSurface->pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + && RT_BOOL(pSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET), VERR_INVALID_PARAMETER); + + HANDLE const hSharedSurface = pHwScreen->SharedHandle; + rc = vmsvga3dDrvNotifyBindSurface(pThisCC, pScreen, hSharedSurface); + } + + if (RT_SUCCESS(rc)) + { + pHwScreen->sidScreenTarget = sid; + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dScreenTargetUpdate(PVGASTATECC pThisCC, VMSVGASCREENOBJECT *pScreen, SVGA3dRect const *pRect) +{ + VMSVGAHWSCREEN *pHwScreen = pScreen->pHwScreen; + AssertReturn(pHwScreen, VERR_NOT_SUPPORTED); + + if (pHwScreen->sidScreenTarget == SVGA_ID_INVALID) + return VINF_SUCCESS; /* No surface bound. */ + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + AssertReturn(pBackend, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pState, pHwScreen->sidScreenTarget, &pSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + AssertReturn( pBackendSurface + && pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + && RT_BOOL(pSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET), + VERR_INVALID_PARAMETER); + + SVGA3dRect boundRect; + boundRect.x = 0; + boundRect.y = 0; + boundRect.w = pSurface->paMipmapLevels[0].mipmapSize.width; + boundRect.h = pSurface->paMipmapLevels[0].mipmapSize.height; + SVGA3dRect clipRect = *pRect; + vmsvgaR3Clip3dRect(&boundRect, &clipRect); + ASSERT_GUEST_RETURN(clipRect.w && clipRect.h, VERR_INVALID_PARAMETER); + + /* Wait for the surface to finish drawing. */ + dxSurfaceWait(pState, pSurface, DX_CID_BACKEND); + + /* Copy the screen texture to the shared surface. */ + DWORD result = pHwScreen->pDXGIKeyedMutex->AcquireSync(0, 10000); + if (result == S_OK) + { + pBackend->dxDevice.pImmediateContext->CopyResource(pHwScreen->pTexture, pBackendSurface->u.pTexture2D); + + dxDeviceFlush(&pBackend->dxDevice); + + result = pHwScreen->pDXGIKeyedMutex->ReleaseSync(1); + } + else + AssertFailed(); + + rc = vmsvga3dDrvNotifyUpdate(pThisCC, pScreen, pRect->x, pRect->y, pRect->w, pRect->h); + return rc; +} + + +/* + * + * 3D interface. + * + */ + +static DECLCALLBACK(int) vmsvga3dBackQueryCaps(PVGASTATECC pThisCC, SVGA3dDevCapIndex idx3dCaps, uint32_t *pu32Val) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + int rc = VINF_SUCCESS; + + *pu32Val = 0; + + if (idx3dCaps > SVGA3D_DEVCAP_MAX) + { + LogRelMax(16, ("VMSVGA: unsupported SVGA3D_DEVCAP %d\n", idx3dCaps)); + return VERR_NOT_SUPPORTED; + } + + D3D_FEATURE_LEVEL const FeatureLevel = pState->pBackend->dxDevice.FeatureLevel; + + /* Most values are taken from: + * https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-downlevel-intro + * + * Shader values are from + * https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-models + */ + + switch (idx3dCaps) + { + case SVGA3D_DEVCAP_3D: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_MAX_LIGHTS: + *pu32Val = SVGA3D_NUM_LIGHTS; /* VGPU9. Not applicable to DX11. */ + break; + + case SVGA3D_DEVCAP_MAX_TEXTURES: + *pu32Val = SVGA3D_NUM_TEXTURE_UNITS; /* VGPU9. Not applicable to DX11. */ + break; + + case SVGA3D_DEVCAP_MAX_CLIP_PLANES: + *pu32Val = SVGA3D_NUM_CLIPPLANES; + break; + + case SVGA3D_DEVCAP_VERTEX_SHADER_VERSION: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = SVGA3DVSVERSION_40; + else + *pu32Val = SVGA3DVSVERSION_30; + break; + + case SVGA3D_DEVCAP_VERTEX_SHADER: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = SVGA3DPSVERSION_40; + else + *pu32Val = SVGA3DPSVERSION_30; + break; + + case SVGA3D_DEVCAP_FRAGMENT_SHADER: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_MAX_RENDER_TARGETS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 8; + else + *pu32Val = 4; + break; + + case SVGA3D_DEVCAP_S23E8_TEXTURES: + case SVGA3D_DEVCAP_S10E5_TEXTURES: + /* Must be obsolete by now; surface format caps specify the same thing. */ + break; + + case SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND: + /* Obsolete */ + break; + + /* + * 2. The BUFFER_FORMAT capabilities are deprecated, and they always + * return TRUE. Even on physical hardware that does not support + * these formats natively, the SVGA3D device will provide an emulation + * which should be invisible to the guest OS. + */ + case SVGA3D_DEVCAP_D16_BUFFER_FORMAT: + case SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT: + case SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_QUERY_TYPES: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_MAX_POINT_SIZE: + AssertCompile(sizeof(uint32_t) == sizeof(float)); + *(float *)pu32Val = 256.0f; /* VGPU9. Not applicable to DX11. */ + break; + + case SVGA3D_DEVCAP_MAX_SHADER_TEXTURES: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH: + case SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT: + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + *pu32Val = 16384; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 8192; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_3) + *pu32Val = 4096; + else + *pu32Val = 2048; + break; + + case SVGA3D_DEVCAP_MAX_VOLUME_EXTENT: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 2048; + else + *pu32Val = 256; + break; + + case SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT: + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + *pu32Val = 16384; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_3) + *pu32Val = 8192; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_2) + *pu32Val = 2048; + else + *pu32Val = 128; + break; + + case SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY: + if (FeatureLevel >= D3D_FEATURE_LEVEL_9_2) + *pu32Val = D3D11_REQ_MAXANISOTROPY; + else + *pu32Val = 2; // D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + break; + + case SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = UINT32_MAX; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_2) + *pu32Val = 1048575; // D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + else + *pu32Val = 65535; // D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; + break; + + case SVGA3D_DEVCAP_MAX_VERTEX_INDEX: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = UINT32_MAX; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_2) + *pu32Val = 1048575; + else + *pu32Val = 65534; + break; + + case SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = UINT32_MAX; + else + *pu32Val = 512; + break; + + case SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = UINT32_MAX; + else + *pu32Val = 512; + break; + + case SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 4096; + else + *pu32Val = 32; + break; + + case SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 4096; + else + *pu32Val = 32; + break; + + case SVGA3D_DEVCAP_TEXTURE_OPS: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8: + case SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8: + case SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10: + case SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5: + case SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5: + case SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4: + case SVGA3D_DEVCAP_SURFACEFMT_R5G6B5: + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16: + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8: + case SVGA3D_DEVCAP_SURFACEFMT_ALPHA8: + case SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8: + case SVGA3D_DEVCAP_SURFACEFMT_Z_D16: + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8: + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8: + case SVGA3D_DEVCAP_SURFACEFMT_DXT1: + case SVGA3D_DEVCAP_SURFACEFMT_DXT2: + case SVGA3D_DEVCAP_SURFACEFMT_DXT3: + case SVGA3D_DEVCAP_SURFACEFMT_DXT4: + case SVGA3D_DEVCAP_SURFACEFMT_DXT5: + case SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8: + case SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10: + case SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8: + case SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8: + case SVGA3D_DEVCAP_SURFACEFMT_CxV8U8: + case SVGA3D_DEVCAP_SURFACEFMT_R_S10E5: + case SVGA3D_DEVCAP_SURFACEFMT_R_S23E8: + case SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5: + case SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8: + case SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5: + case SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8: + case SVGA3D_DEVCAP_SURFACEFMT_V16U16: + case SVGA3D_DEVCAP_SURFACEFMT_G16R16: + case SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16: + case SVGA3D_DEVCAP_SURFACEFMT_UYVY: + case SVGA3D_DEVCAP_SURFACEFMT_YUY2: + case SVGA3D_DEVCAP_SURFACEFMT_NV12: + case SVGA3D_DEVCAP_DEAD10: /* SVGA3D_DEVCAP_SURFACEFMT_AYUV */ + case SVGA3D_DEVCAP_SURFACEFMT_Z_DF16: + case SVGA3D_DEVCAP_SURFACEFMT_Z_DF24: + case SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT: + case SVGA3D_DEVCAP_SURFACEFMT_ATI1: + case SVGA3D_DEVCAP_SURFACEFMT_ATI2: + case SVGA3D_DEVCAP_SURFACEFMT_YV12: + { + SVGA3dSurfaceFormat const enmFormat = vmsvgaDXDevCapSurfaceFmt2Format(idx3dCaps); + rc = vmsvgaDXCheckFormatSupportPreDX(pState, enmFormat, pu32Val); + break; + } + + case SVGA3D_DEVCAP_MISSING62: + /* Unused */ + break; + + case SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS: + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) + *pu32Val = 8; + else if (FeatureLevel >= D3D_FEATURE_LEVEL_9_3) + *pu32Val = 4; // D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT + else + *pu32Val = 1; // D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT + break; + + case SVGA3D_DEVCAP_DEAD4: /* SVGA3D_DEVCAP_MULTISAMPLE_NONMASKABLESAMPLES */ + case SVGA3D_DEVCAP_DEAD5: /* SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES */ + *pu32Val = (1 << (2-1)) | (1 << (4-1)) | (1 << (8-1)); /* 2x, 4x, 8x */ + break; + + case SVGA3D_DEVCAP_DEAD7: /* SVGA3D_DEVCAP_ALPHATOCOVERAGE */ + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_DEAD6: /* SVGA3D_DEVCAP_SUPERSAMPLE */ + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_AUTOGENMIPMAPS: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_MAX_CONTEXT_IDS: + *pu32Val = SVGA3D_MAX_CONTEXT_IDS; + break; + + case SVGA3D_DEVCAP_MAX_SURFACE_IDS: + *pu32Val = SVGA3D_MAX_SURFACE_IDS; + break; + + case SVGA3D_DEVCAP_DEAD1: + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_DEAD8: /* SVGA3D_DEVCAP_VIDEO_DECODE */ + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_DEAD9: /* SVGA3D_DEVCAP_VIDEO_PROCESS */ + /* Obsolete */ + break; + + case SVGA3D_DEVCAP_LINE_AA: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_LINE_STIPPLE: + *pu32Val = 0; /* DX11 does not seem to support this directly. */ + break; + + case SVGA3D_DEVCAP_MAX_LINE_WIDTH: + AssertCompile(sizeof(uint32_t) == sizeof(float)); + *(float *)pu32Val = 1.0f; + break; + + case SVGA3D_DEVCAP_MAX_AA_LINE_WIDTH: + AssertCompile(sizeof(uint32_t) == sizeof(float)); + *(float *)pu32Val = 1.0f; + break; + + case SVGA3D_DEVCAP_DEAD3: /* Old SVGA3D_DEVCAP_LOGICOPS */ + /* Deprecated. */ + AssertCompile(SVGA3D_DEVCAP_DEAD3 == 92); /* Newer SVGA headers redefine this. */ + break; + + case SVGA3D_DEVCAP_TS_COLOR_KEY: + *pu32Val = 0; /* DX11 does not seem to support this directly. */ + break; + + case SVGA3D_DEVCAP_DEAD2: + break; + + case SVGA3D_DEVCAP_DXCONTEXT: + *pu32Val = 1; + break; + + case SVGA3D_DEVCAP_DEAD11: /* SVGA3D_DEVCAP_MAX_TEXTURE_ARRAY_SIZE */ + *pu32Val = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + break; + + case SVGA3D_DEVCAP_DX_MAX_VERTEXBUFFERS: + *pu32Val = D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; + break; + + case SVGA3D_DEVCAP_DX_MAX_CONSTANT_BUFFERS: + *pu32Val = D3D11_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT; + break; + + case SVGA3D_DEVCAP_DX_PROVOKING_VERTEX: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_DXFMT_X8R8G8B8: + case SVGA3D_DEVCAP_DXFMT_A8R8G8B8: + case SVGA3D_DEVCAP_DXFMT_R5G6B5: + case SVGA3D_DEVCAP_DXFMT_X1R5G5B5: + case SVGA3D_DEVCAP_DXFMT_A1R5G5B5: + case SVGA3D_DEVCAP_DXFMT_A4R4G4B4: + case SVGA3D_DEVCAP_DXFMT_Z_D32: + case SVGA3D_DEVCAP_DXFMT_Z_D16: + case SVGA3D_DEVCAP_DXFMT_Z_D24S8: + case SVGA3D_DEVCAP_DXFMT_Z_D15S1: + case SVGA3D_DEVCAP_DXFMT_LUMINANCE8: + case SVGA3D_DEVCAP_DXFMT_LUMINANCE4_ALPHA4: + case SVGA3D_DEVCAP_DXFMT_LUMINANCE16: + case SVGA3D_DEVCAP_DXFMT_LUMINANCE8_ALPHA8: + case SVGA3D_DEVCAP_DXFMT_DXT1: + case SVGA3D_DEVCAP_DXFMT_DXT2: + case SVGA3D_DEVCAP_DXFMT_DXT3: + case SVGA3D_DEVCAP_DXFMT_DXT4: + case SVGA3D_DEVCAP_DXFMT_DXT5: + case SVGA3D_DEVCAP_DXFMT_BUMPU8V8: + case SVGA3D_DEVCAP_DXFMT_BUMPL6V5U5: + case SVGA3D_DEVCAP_DXFMT_BUMPX8L8V8U8: + case SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD1: + case SVGA3D_DEVCAP_DXFMT_ARGB_S10E5: + case SVGA3D_DEVCAP_DXFMT_ARGB_S23E8: + case SVGA3D_DEVCAP_DXFMT_A2R10G10B10: + case SVGA3D_DEVCAP_DXFMT_V8U8: + case SVGA3D_DEVCAP_DXFMT_Q8W8V8U8: + case SVGA3D_DEVCAP_DXFMT_CxV8U8: + case SVGA3D_DEVCAP_DXFMT_X8L8V8U8: + case SVGA3D_DEVCAP_DXFMT_A2W10V10U10: + case SVGA3D_DEVCAP_DXFMT_ALPHA8: + case SVGA3D_DEVCAP_DXFMT_R_S10E5: + case SVGA3D_DEVCAP_DXFMT_R_S23E8: + case SVGA3D_DEVCAP_DXFMT_RG_S10E5: + case SVGA3D_DEVCAP_DXFMT_RG_S23E8: + case SVGA3D_DEVCAP_DXFMT_BUFFER: + case SVGA3D_DEVCAP_DXFMT_Z_D24X8: + case SVGA3D_DEVCAP_DXFMT_V16U16: + case SVGA3D_DEVCAP_DXFMT_G16R16: + case SVGA3D_DEVCAP_DXFMT_A16B16G16R16: + case SVGA3D_DEVCAP_DXFMT_UYVY: + case SVGA3D_DEVCAP_DXFMT_YUY2: + case SVGA3D_DEVCAP_DXFMT_NV12: + case SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD2: /* SVGA3D_DEVCAP_DXFMT_AYUV */ + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_UINT: + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_SINT: + case SVGA3D_DEVCAP_DXFMT_R32G32B32_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R32G32B32_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R32G32B32_UINT: + case SVGA3D_DEVCAP_DXFMT_R32G32B32_SINT: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UINT: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SNORM: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SINT: + case SVGA3D_DEVCAP_DXFMT_R32G32_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R32G32_UINT: + case SVGA3D_DEVCAP_DXFMT_R32G32_SINT: + case SVGA3D_DEVCAP_DXFMT_R32G8X24_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_D32_FLOAT_S8X24_UINT: + case SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24: + case SVGA3D_DEVCAP_DXFMT_X32_G8X24_UINT: + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UINT: + case SVGA3D_DEVCAP_DXFMT_R11G11B10_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UINT: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SINT: + case SVGA3D_DEVCAP_DXFMT_R16G16_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R16G16_UINT: + case SVGA3D_DEVCAP_DXFMT_R16G16_SINT: + case SVGA3D_DEVCAP_DXFMT_R32_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_D32_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R32_UINT: + case SVGA3D_DEVCAP_DXFMT_R32_SINT: + case SVGA3D_DEVCAP_DXFMT_R24G8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_D24_UNORM_S8_UINT: + case SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8: + case SVGA3D_DEVCAP_DXFMT_X24_G8_UINT: + case SVGA3D_DEVCAP_DXFMT_R8G8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R8G8_UNORM: + case SVGA3D_DEVCAP_DXFMT_R8G8_UINT: + case SVGA3D_DEVCAP_DXFMT_R8G8_SINT: + case SVGA3D_DEVCAP_DXFMT_R16_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R16_UNORM: + case SVGA3D_DEVCAP_DXFMT_R16_UINT: + case SVGA3D_DEVCAP_DXFMT_R16_SNORM: + case SVGA3D_DEVCAP_DXFMT_R16_SINT: + case SVGA3D_DEVCAP_DXFMT_R8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_R8_UNORM: + case SVGA3D_DEVCAP_DXFMT_R8_UINT: + case SVGA3D_DEVCAP_DXFMT_R8_SNORM: + case SVGA3D_DEVCAP_DXFMT_R8_SINT: + case SVGA3D_DEVCAP_DXFMT_P8: + case SVGA3D_DEVCAP_DXFMT_R9G9B9E5_SHAREDEXP: + case SVGA3D_DEVCAP_DXFMT_R8G8_B8G8_UNORM: + case SVGA3D_DEVCAP_DXFMT_G8R8_G8B8_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC1_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_BC1_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_BC2_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_BC2_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_BC3_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_BC3_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_BC4_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_ATI1: + case SVGA3D_DEVCAP_DXFMT_BC4_SNORM: + case SVGA3D_DEVCAP_DXFMT_BC5_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_ATI2: + case SVGA3D_DEVCAP_DXFMT_BC5_SNORM: + case SVGA3D_DEVCAP_DXFMT_R10G10B10_XR_BIAS_A2_UNORM: + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM_SRGB: + case SVGA3D_DEVCAP_DXFMT_Z_DF16: + case SVGA3D_DEVCAP_DXFMT_Z_DF24: + case SVGA3D_DEVCAP_DXFMT_Z_D24S8_INT: + case SVGA3D_DEVCAP_DXFMT_YV12: + case SVGA3D_DEVCAP_DXFMT_R32G32B32A32_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UNORM: + case SVGA3D_DEVCAP_DXFMT_R32G32_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UNORM: + case SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SNORM: + case SVGA3D_DEVCAP_DXFMT_R16G16_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R16G16_UNORM: + case SVGA3D_DEVCAP_DXFMT_R16G16_SNORM: + case SVGA3D_DEVCAP_DXFMT_R32_FLOAT: + case SVGA3D_DEVCAP_DXFMT_R8G8_SNORM: + case SVGA3D_DEVCAP_DXFMT_R16_FLOAT: + case SVGA3D_DEVCAP_DXFMT_D16_UNORM: + case SVGA3D_DEVCAP_DXFMT_A8_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC1_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC2_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC3_UNORM: + case SVGA3D_DEVCAP_DXFMT_B5G6R5_UNORM: + case SVGA3D_DEVCAP_DXFMT_B5G5R5A1_UNORM: + case SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM: + case SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC4_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC5_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC6H_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_BC6H_UF16: + case SVGA3D_DEVCAP_DXFMT_BC6H_SF16: + case SVGA3D_DEVCAP_DXFMT_BC7_TYPELESS: + case SVGA3D_DEVCAP_DXFMT_BC7_UNORM: + case SVGA3D_DEVCAP_DXFMT_BC7_UNORM_SRGB: + { + SVGA3dSurfaceFormat const enmFormat = vmsvgaDXDevCapDxfmt2Format(idx3dCaps); + rc = vmsvgaDXCheckFormatSupport(pState, enmFormat, pu32Val); + break; + } + + case SVGA3D_DEVCAP_SM41: + *pu32Val = 1; /* boolean */ + break; + + case SVGA3D_DEVCAP_MULTISAMPLE_2X: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_MULTISAMPLE_4X: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_MS_FULL_QUALITY: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_LOGICOPS: + AssertCompile(SVGA3D_DEVCAP_LOGICOPS == 248); + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_LOGIC_BLENDOPS: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_RESERVED_1: + break; + + case SVGA3D_DEVCAP_RESERVED_2: + break; + + case SVGA3D_DEVCAP_SM5: + *pu32Val = 1; /* boolean */ + break; + + case SVGA3D_DEVCAP_MULTISAMPLE_8X: + *pu32Val = 0; /* boolean */ + break; + + case SVGA3D_DEVCAP_MAX: + case SVGA3D_DEVCAP_INVALID: + rc = VERR_NOT_SUPPORTED; + break; + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackChangeMode(PVGASTATECC pThisCC) +{ + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceCopy(PVGASTATECC pThisCC, SVGA3dSurfaceImageId dest, SVGA3dSurfaceImageId src, + uint32_t cCopyBoxes, SVGA3dCopyBox *pBox) +{ + RT_NOREF(cCopyBoxes, pBox); + + LogFunc(("src sid %d -> dst sid %d\n", src.sid, dest.sid)); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + + PVMSVGA3DSURFACE pSrcSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, src.sid, &pSrcSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DSURFACE pDstSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, dest.sid, &pDstSurface); + AssertRCReturn(rc, rc); + + LogFunc(("src%s cid %d -> dst%s cid %d\n", + pSrcSurface->pBackendSurface ? "" : " sysmem", + pSrcSurface ? pSrcSurface->idAssociatedContext : SVGA_ID_INVALID, + pDstSurface->pBackendSurface ? "" : " sysmem", + pDstSurface ? pDstSurface->idAssociatedContext : SVGA_ID_INVALID)); + + //DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + //AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + if (pSrcSurface->pBackendSurface) + { + if (pDstSurface->pBackendSurface == NULL) + { + /* Create the target if it can be used as a device context shared resource (render or screen target). */ + if (pBackend->fSingleDevice || dxIsSurfaceShareable(pDstSurface)) + { + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, NULL, pDstSurface); + AssertRCReturn(rc, rc); + } + } + + if (pDstSurface->pBackendSurface) + { + /* Surface -> Surface. */ + /* Expect both of them to be shared surfaces created by the backend context. */ + Assert(pSrcSurface->idAssociatedContext == DX_CID_BACKEND && pDstSurface->idAssociatedContext == DX_CID_BACKEND); + + /* Wait for the source surface to finish drawing. */ + dxSurfaceWait(pState, pSrcSurface, DX_CID_BACKEND); + + DXDEVICE *pDXDevice = &pBackend->dxDevice; + + /* Clip the box. */ + PVMSVGA3DMIPMAPLEVEL pSrcMipLevel; + rc = vmsvga3dMipmapLevel(pSrcSurface, src.face, src.mipmap, &pSrcMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + PVMSVGA3DMIPMAPLEVEL pDstMipLevel; + rc = vmsvga3dMipmapLevel(pDstSurface, dest.face, dest.mipmap, &pDstMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + SVGA3dCopyBox clipBox = *pBox; + vmsvgaR3ClipCopyBox(&pSrcMipLevel->mipmapSize, &pDstMipLevel->mipmapSize, &clipBox); + + UINT DstSubresource = vmsvga3dCalcSubresource(dest.mipmap, dest.face, pDstSurface->cLevels); + UINT DstX = clipBox.x; + UINT DstY = clipBox.y; + UINT DstZ = clipBox.z; + + UINT SrcSubresource = vmsvga3dCalcSubresource(src.mipmap, src.face, pSrcSurface->cLevels); + D3D11_BOX SrcBox; + SrcBox.left = clipBox.srcx; + SrcBox.top = clipBox.srcy; + SrcBox.front = clipBox.srcz; + SrcBox.right = clipBox.srcx + clipBox.w; + SrcBox.bottom = clipBox.srcy + clipBox.h; + SrcBox.back = clipBox.srcz + clipBox.d; + + Assert(cCopyBoxes == 1); /** @todo */ + + ID3D11Resource *pDstResource; + ID3D11Resource *pSrcResource; + pDstResource = dxResource(pState, pDstSurface, NULL); + pSrcResource = dxResource(pState, pSrcSurface, NULL); + + pDXDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + + pDstSurface->pBackendSurface->cidDrawing = DX_CID_BACKEND; + } + else + { + /* Surface -> Memory. */ + AssertFailed(); /** @todo implement */ + } + } + else + { + /* Memory -> Surface. */ + AssertFailed(); /** @todo implement */ + } + + return rc; +} + + +static DECLCALLBACK(void) vmsvga3dBackUpdateHostScreenViewport(PVGASTATECC pThisCC, uint32_t idScreen, VMSVGAVIEWPORT const *pOldViewport) +{ + RT_NOREF(pThisCC, idScreen, pOldViewport); + /** @todo Scroll the screen content without requiring the guest to redraw. */ +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceUpdateHeapBuffers(PVGASTATECC pThisCC, PVMSVGA3DSURFACE pSurface) +{ + /** @todo */ + RT_NOREF(pThisCC, pSurface); + return VERR_NOT_IMPLEMENTED; +} + + +/* + * + * VGPU9 callbacks. Not implemented. + * + */ +/** @todo later */ + +/** + * Create a new 3d context + * + * @returns VBox status code. + * @param pThisCC The VGA/VMSVGA state for ring-3. + * @param cid Context id + */ +static DECLCALLBACK(int) vmsvga3dBackContextDefine(PVGASTATECC pThisCC, uint32_t cid) +{ + RT_NOREF(cid); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VERR_NOT_IMPLEMENTED; +} + + +/** + * Destroy an existing 3d context + * + * @returns VBox status code. + * @param pThisCC The VGA/VMSVGA state for ring-3. + * @param cid Context id + */ +static DECLCALLBACK(int) vmsvga3dBackContextDestroy(PVGASTATECC pThisCC, uint32_t cid) +{ + RT_NOREF(cid); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetTransform(PVGASTATECC pThisCC, uint32_t cid, SVGA3dTransformType type, float matrix[16]) +{ + RT_NOREF(cid, type, matrix); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetZRange(PVGASTATECC pThisCC, uint32_t cid, SVGA3dZRange zRange) +{ + RT_NOREF(cid, zRange); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetRenderState(PVGASTATECC pThisCC, uint32_t cid, uint32_t cRenderStates, SVGA3dRenderState *pRenderState) +{ + RT_NOREF(cid, cRenderStates, pRenderState); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetRenderTarget(PVGASTATECC pThisCC, uint32_t cid, SVGA3dRenderTargetType type, SVGA3dSurfaceImageId target) +{ + RT_NOREF(cid, type, target); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetTextureState(PVGASTATECC pThisCC, uint32_t cid, uint32_t cTextureStates, SVGA3dTextureState *pTextureState) +{ + RT_NOREF(cid, cTextureStates, pTextureState); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetMaterial(PVGASTATECC pThisCC, uint32_t cid, SVGA3dFace face, SVGA3dMaterial *pMaterial) +{ + RT_NOREF(cid, face, pMaterial); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetLightData(PVGASTATECC pThisCC, uint32_t cid, uint32_t index, SVGA3dLightData *pData) +{ + RT_NOREF(cid, index, pData); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetLightEnabled(PVGASTATECC pThisCC, uint32_t cid, uint32_t index, uint32_t enabled) +{ + RT_NOREF(cid, index, enabled); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetViewPort(PVGASTATECC pThisCC, uint32_t cid, SVGA3dRect *pRect) +{ + RT_NOREF(cid, pRect); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetClipPlane(PVGASTATECC pThisCC, uint32_t cid, uint32_t index, float plane[4]) +{ + RT_NOREF(cid, index, plane); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackCommandClear(PVGASTATECC pThisCC, uint32_t cid, SVGA3dClearFlag clearFlag, uint32_t color, float depth, + uint32_t stencil, uint32_t cRects, SVGA3dRect *pRect) +{ + /* From SVGA3D_BeginClear comments: + * + * Clear is not affected by clipping, depth test, or other + * render state which affects the fragment pipeline. + * + * Therefore this code must ignore the current scissor rect. + */ + + RT_NOREF(cid, clearFlag, color, depth, stencil, cRects, pRect); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDrawPrimitives(PVGASTATECC pThisCC, uint32_t cid, uint32_t numVertexDecls, SVGA3dVertexDecl *pVertexDecl, + uint32_t numRanges, SVGA3dPrimitiveRange *pRange, + uint32_t cVertexDivisor, SVGA3dVertexDivisor *pVertexDivisor) +{ + RT_NOREF(cid, numVertexDecls, pVertexDecl, numRanges, pRange, cVertexDivisor, pVertexDivisor); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackSetScissorRect(PVGASTATECC pThisCC, uint32_t cid, SVGA3dRect *pRect) +{ + RT_NOREF(cid, pRect); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackGenerateMipmaps(PVGASTATECC pThisCC, uint32_t sid, SVGA3dTextureFilter filter) +{ + RT_NOREF(sid, filter); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackShaderDefine(PVGASTATECC pThisCC, uint32_t cid, uint32_t shid, SVGA3dShaderType type, + uint32_t cbData, uint32_t *pShaderData) +{ + RT_NOREF(cid, shid, type, cbData, pShaderData); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackShaderDestroy(PVGASTATECC pThisCC, uint32_t cid, uint32_t shid, SVGA3dShaderType type) +{ + RT_NOREF(cid, shid, type); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackShaderSet(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext, uint32_t cid, SVGA3dShaderType type, uint32_t shid) +{ + RT_NOREF(pContext, cid, type, shid); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackShaderSetConst(PVGASTATECC pThisCC, uint32_t cid, uint32_t reg, SVGA3dShaderType type, + SVGA3dShaderConstType ctype, uint32_t cRegisters, uint32_t *pValues) +{ + RT_NOREF(cid, reg, type, ctype, cRegisters, pValues); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackOcclusionQueryCreate(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext) +{ + RT_NOREF(pThisCC, pContext); + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackOcclusionQueryDelete(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext) +{ + RT_NOREF(pThisCC, pContext); + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackOcclusionQueryBegin(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext) +{ + RT_NOREF(pThisCC, pContext); + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackOcclusionQueryEnd(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext) +{ + RT_NOREF(pThisCC, pContext); + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackOcclusionQueryGetData(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext, uint32_t *pu32Pixels) +{ + RT_NOREF(pThisCC, pContext, pu32Pixels); + DEBUG_BREAKPOINT_TEST(); + return VINF_SUCCESS; +} + + +/** + * Destroy backend specific surface bits (part of SVGA_3D_CMD_SURFACE_DESTROY). + * + * @param pThisCC The device context. + * @param fClearCOTableEntry Whether to clear the corresponding COTable entry. + * @param pSurface The surface being destroyed. + */ +static DECLCALLBACK(void) vmsvga3dBackSurfaceDestroy(PVGASTATECC pThisCC, bool fClearCOTableEntry, PVMSVGA3DSURFACE pSurface) +{ + RT_NOREF(pThisCC); + + /* The caller should not use the function for system memory surfaces. */ + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + if (!pBackendSurface) + return; + pSurface->pBackendSurface = NULL; + + LogFunc(("sid=%u\n", pSurface->id)); + + /* If any views have been created for this resource, then also release them. */ + DXVIEW *pIter, *pNext; + RTListForEachSafe(&pBackendSurface->listView, pIter, pNext, DXVIEW, nodeSurfaceView) + { + LogFunc(("pIter=%p, pNext=%p\n", pIter, pNext)); + + /** @todo The common DX code should track the views and clean COTable on a surface destruction. */ + if (fClearCOTableEntry) + { + PVMSVGA3DDXCONTEXT pDXContext; + int rc = vmsvga3dDXContextFromCid(pThisCC->svga.p3dState, pIter->cid, &pDXContext); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + switch (pIter->enmViewType) + { + case VMSVGA3D_VIEWTYPE_RENDERTARGET: + { + SVGACOTableDXRTViewEntry *pEntry = &pDXContext->cot.paRTView[pIter->viewId]; + RT_ZERO(*pEntry); + break; + } + case VMSVGA3D_VIEWTYPE_DEPTHSTENCIL: + { + SVGACOTableDXDSViewEntry *pEntry = &pDXContext->cot.paDSView[pIter->viewId]; + RT_ZERO(*pEntry); + break; + } + case VMSVGA3D_VIEWTYPE_SHADERRESOURCE: + { + SVGACOTableDXSRViewEntry *pEntry = &pDXContext->cot.paSRView[pIter->viewId]; + RT_ZERO(*pEntry); + break; + } + case VMSVGA3D_VIEWTYPE_UNORDEREDACCESS: + { + SVGACOTableDXUAViewEntry *pEntry = &pDXContext->cot.paUAView[pIter->viewId]; + RT_ZERO(*pEntry); + break; + } + default: + AssertFailed(); + } + } + } + + dxViewDestroy(pIter); + } + + if ( pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_1D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_CUBE + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_3D) + { + D3D_RELEASE(pBackendSurface->staging.pResource); + D3D_RELEASE(pBackendSurface->dynamic.pResource); + D3D_RELEASE(pBackendSurface->u.pResource); + } + else if (pBackendSurface->enmResType == VMSVGA3D_RESTYPE_BUFFER) + { +#ifndef DX_COMMON_STAGING_BUFFER + D3D_RELEASE(pBackendSurface->staging.pBuffer); + D3D_RELEASE(pBackendSurface->dynamic.pBuffer); +#endif + D3D_RELEASE(pBackendSurface->u.pBuffer); + } + else + { + AssertFailed(); + } + + RTMemFree(pBackendSurface); + + /* No context has created the surface, because the surface does not exist anymore. */ + pSurface->idAssociatedContext = SVGA_ID_INVALID; +} + + +static DECLCALLBACK(void) vmsvga3dBackSurfaceInvalidateImage(PVGASTATECC pThisCC, PVMSVGA3DSURFACE pSurface, uint32_t uFace, uint32_t uMipmap) +{ + RT_NOREF(pThisCC, uFace, uMipmap); + + /* The caller should not use the function for system memory surfaces. */ + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + if (!pBackendSurface) + return; + + LogFunc(("sid=%u\n", pSurface->id)); + + /* The guest uses this to invalidate a buffer. */ + if (pBackendSurface->enmResType == VMSVGA3D_RESTYPE_BUFFER) + { + Assert(uFace == 0 && uMipmap == 0); /* The caller ensures this. */ + /** @todo This causes flickering when a buffer is invalidated and re-created right before a draw call. */ + //vmsvga3dBackSurfaceDestroy(pThisCC, false, pSurface); + } + else + { + /** @todo Delete views that have been created for this mipmap. + * For now just delete all views, they will be recte=reated if necessary. + */ + ASSERT_GUEST_FAILED(); + DXVIEW *pIter, *pNext; + RTListForEachSafe(&pBackendSurface->listView, pIter, pNext, DXVIEW, nodeSurfaceView) + { + dxViewDestroy(pIter); + } + } +} + + +/** + * Backend worker for implementing SVGA_3D_CMD_SURFACE_STRETCHBLT. + * + * @returns VBox status code. + * @param pThis The VGA device instance. + * @param pState The VMSVGA3d state. + * @param pDstSurface The destination host surface. + * @param uDstFace The destination face (valid). + * @param uDstMipmap The destination mipmap level (valid). + * @param pDstBox The destination box. + * @param pSrcSurface The source host surface. + * @param uSrcFace The destination face (valid). + * @param uSrcMipmap The source mimap level (valid). + * @param pSrcBox The source box. + * @param enmMode The strecht blt mode . + * @param pContext The VMSVGA3d context (already current for OGL). + */ +static DECLCALLBACK(int) vmsvga3dBackSurfaceStretchBlt(PVGASTATE pThis, PVMSVGA3DSTATE pState, + PVMSVGA3DSURFACE pDstSurface, uint32_t uDstFace, uint32_t uDstMipmap, SVGA3dBox const *pDstBox, + PVMSVGA3DSURFACE pSrcSurface, uint32_t uSrcFace, uint32_t uSrcMipmap, SVGA3dBox const *pSrcBox, + SVGA3dStretchBltMode enmMode, PVMSVGA3DCONTEXT pContext) +{ + RT_NOREF(pThis, pState, pDstSurface, uDstFace, uDstMipmap, pDstBox, + pSrcSurface, uSrcFace, uSrcMipmap, pSrcBox, enmMode, pContext); + + AssertFailed(); + return VINF_SUCCESS; +} + + +/** + * Backend worker for implementing SVGA_3D_CMD_SURFACE_DMA that copies one box. + * + * @returns Failure status code or @a rc. + * @param pThis The shared VGA/VMSVGA instance data. + * @param pThisCC The VGA/VMSVGA state for ring-3. + * @param pState The VMSVGA3d state. + * @param pSurface The host surface. + * @param pMipLevel Mipmap level. The caller knows it already. + * @param uHostFace The host face (valid). + * @param uHostMipmap The host mipmap level (valid). + * @param GuestPtr The guest pointer. + * @param cbGuestPitch The guest pitch. + * @param transfer The transfer direction. + * @param pBox The box to copy (clipped, valid, except for guest's srcx, srcy, srcz). + * @param pContext The context (for OpenGL). + * @param rc The current rc for all boxes. + * @param iBox The current box number (for Direct 3D). + */ +static DECLCALLBACK(int) vmsvga3dBackSurfaceDMACopyBox(PVGASTATE pThis, PVGASTATECC pThisCC, PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, + PVMSVGA3DMIPMAPLEVEL pMipLevel, uint32_t uHostFace, uint32_t uHostMipmap, + SVGAGuestPtr GuestPtr, uint32_t cbGuestPitch, SVGA3dTransferType transfer, + SVGA3dCopyBox const *pBox, PVMSVGA3DCONTEXT pContext, int rc, int iBox) +{ + RT_NOREF(pState, pMipLevel, pContext, iBox); + + /* The called should not use the function for system memory surfaces. */ + PVMSVGA3DBACKENDSURFACE pBackendSurface = pSurface->pBackendSurface; + AssertReturn(pBackendSurface, VERR_INVALID_PARAMETER); + + if ( pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_1D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_2D + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_CUBE + || pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_3D) + { + /** @todo This is generic code and should be in DevVGA-SVGA3d.cpp for backends which support Map/Unmap. */ + uint32_t const u32GuestBlockX = pBox->srcx / pSurface->cxBlock; + uint32_t const u32GuestBlockY = pBox->srcy / pSurface->cyBlock; + Assert(u32GuestBlockX * pSurface->cxBlock == pBox->srcx); + Assert(u32GuestBlockY * pSurface->cyBlock == pBox->srcy); + uint32_t const cBlocksX = (pBox->w + pSurface->cxBlock - 1) / pSurface->cxBlock; + uint32_t const cBlocksY = (pBox->h + pSurface->cyBlock - 1) / pSurface->cyBlock; + AssertMsgReturn(cBlocksX && cBlocksY && pBox->d, ("Empty box %dx%dx%d\n", pBox->w, pBox->h, pBox->d), VERR_INTERNAL_ERROR); + + /* vmsvgaR3GmrTransfer verifies uGuestOffset. + * srcx(u32GuestBlockX) and srcy(u32GuestBlockY) have been verified in vmsvga3dSurfaceDMA + * to not cause 32 bit overflow when multiplied by cbBlock and cbGuestPitch. + */ + uint64_t uGuestOffset = u32GuestBlockX * pSurface->cbBlock + u32GuestBlockY * cbGuestPitch; + AssertReturn(uGuestOffset < UINT32_MAX, VERR_INVALID_PARAMETER); + + /* 3D texture needs additional processing. */ + ASSERT_GUEST_RETURN( pBox->z < D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION + && pBox->d <= D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION + && pBox->d <= D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION - pBox->z, + VERR_INVALID_PARAMETER); + ASSERT_GUEST_RETURN( pBox->srcz < D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION + && pBox->d <= D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION + && pBox->d <= D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION - pBox->srcz, + VERR_INVALID_PARAMETER); + + uGuestOffset += pBox->srcz * pMipLevel->cbSurfacePlane; + + SVGA3dSurfaceImageId image; + image.sid = pSurface->id; + image.face = uHostFace; + image.mipmap = uHostMipmap; + + SVGA3dBox box; + box.x = pBox->x; + box.y = pBox->y; + box.z = pBox->z; + box.w = pBox->w; + box.h = pBox->h; + box.d = pBox->d; + + VMSVGA3D_SURFACE_MAP const enmMap = transfer == SVGA3D_WRITE_HOST_VRAM + ? VMSVGA3D_SURFACE_MAP_WRITE + : VMSVGA3D_SURFACE_MAP_READ; + + VMSVGA3D_MAPPED_SURFACE map; + rc = vmsvga3dBackSurfaceMap(pThisCC, &image, &box, enmMap, &map); + if (RT_SUCCESS(rc)) + { +#if 0 + if (box.w == 250 && box.h == 250 && box.d == 1 && enmMap == VMSVGA3D_SURFACE_MAP_READ) + { + DEBUG_BREAKPOINT_TEST(); + vmsvga3dMapWriteBmpFile(&map, "P"); + } +#endif + /* Prepare parameters for vmsvgaR3GmrTransfer, which needs the host buffer address, size + * and offset of the first scanline. + */ + uint32_t cbLockedBuf = map.cbRowPitch * cBlocksY; + if (pBackendSurface->enmResType == VMSVGA3D_RESTYPE_TEXTURE_3D) + cbLockedBuf += map.cbDepthPitch * (pBox->d - 1); /// @todo why map does not compute this for 2D textures + uint8_t *pu8LockedBuf = (uint8_t *)map.pvData; + uint32_t offLockedBuf = 0; + + for (uint32_t iPlane = 0; iPlane < pBox->d; ++iPlane) + { + AssertBreak(uGuestOffset < UINT32_MAX); + + rc = vmsvgaR3GmrTransfer(pThis, + pThisCC, + transfer, + pu8LockedBuf, + cbLockedBuf, + offLockedBuf, + map.cbRowPitch, + GuestPtr, + (uint32_t)uGuestOffset, + cbGuestPitch, + cBlocksX * pSurface->cbBlock, + cBlocksY); + AssertRC(rc); + + uGuestOffset += pMipLevel->cbSurfacePlane; + offLockedBuf += map.cbDepthPitch; + } + + bool const fWritten = (transfer == SVGA3D_WRITE_HOST_VRAM); + vmsvga3dBackSurfaceUnmap(pThisCC, &image, &map, fWritten); + } + } + else + { + AssertMsgFailed(("Unsupported surface type %d\n", pBackendSurface->enmResType)); + rc = VERR_NOT_IMPLEMENTED; + } + + return rc; +} + + +/** + * Create D3D/OpenGL texture object for the specified surface. + * + * Surfaces are created when needed. + * + * @param pThisCC The device context. + * @param pContext The context. + * @param idAssociatedContext Probably the same as pContext->id. + * @param pSurface The surface to create the texture for. + */ +static DECLCALLBACK(int) vmsvga3dBackCreateTexture(PVGASTATECC pThisCC, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext, + PVMSVGA3DSURFACE pSurface) + +{ + RT_NOREF(pThisCC, pContext, idAssociatedContext, pSurface); + + AssertFailed(); + return VINF_SUCCESS; +} + + +/* + * DX callbacks. + */ + +static DECLCALLBACK(int) vmsvga3dBackDXDefineContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + /* Allocate a backend specific context structure. */ + PVMSVGA3DBACKENDDXCONTEXT pBackendDXContext = (PVMSVGA3DBACKENDDXCONTEXT)RTMemAllocZ(sizeof(VMSVGA3DBACKENDDXCONTEXT)); + AssertPtrReturn(pBackendDXContext, VERR_NO_MEMORY); + pDXContext->pBackendDXContext = pBackendDXContext; + + LogFunc(("cid %d\n", pDXContext->cid)); + + int rc = dxDeviceCreate(pBackend, &pBackendDXContext->dxDevice); + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + LogFunc(("cid %d\n", pDXContext->cid)); + + if (pDXContext->pBackendDXContext) + { + /* Clean up context resources. */ + VMSVGA3DBACKENDDXCONTEXT *pBackendDXContext = pDXContext->pBackendDXContext; + + for (uint32_t idxShaderState = 0; idxShaderState < RT_ELEMENTS(pBackendDXContext->resources.shaderState); ++idxShaderState) + { + ID3D11Buffer **papConstantBuffer = &pBackendDXContext->resources.shaderState[idxShaderState].constantBuffers[0]; + D3D_RELEASE_ARRAY(RT_ELEMENTS(pBackendDXContext->resources.shaderState[idxShaderState].constantBuffers), papConstantBuffer); + } + + for (uint32_t i = 0; i < RT_ELEMENTS(pBackendDXContext->resources.inputAssembly.vertexBuffers); ++i) + { + D3D_RELEASE(pBackendDXContext->resources.inputAssembly.vertexBuffers[i].pBuffer); + } + + D3D_RELEASE(pBackendDXContext->resources.inputAssembly.indexBuffer.pBuffer); + + if (pBackendDXContext->dxDevice.pImmediateContext) + dxDeviceFlush(&pBackendDXContext->dxDevice); /* Make sure that any pending draw calls are finished. */ + + if (pBackendDXContext->paRenderTargetView) + { + for (uint32_t i = 0; i < pBackendDXContext->cRenderTargetView; ++i) + D3D_RELEASE(pBackendDXContext->paRenderTargetView[i].u.pRenderTargetView); + } + if (pBackendDXContext->paDepthStencilView) + { + for (uint32_t i = 0; i < pBackendDXContext->cDepthStencilView; ++i) + D3D_RELEASE(pBackendDXContext->paDepthStencilView[i].u.pDepthStencilView); + } + if (pBackendDXContext->paShaderResourceView) + { + for (uint32_t i = 0; i < pBackendDXContext->cShaderResourceView; ++i) + D3D_RELEASE(pBackendDXContext->paShaderResourceView[i].u.pShaderResourceView); + } + if (pBackendDXContext->paElementLayout) + { + for (uint32_t i = 0; i < pBackendDXContext->cElementLayout; ++i) + D3D_RELEASE(pBackendDXContext->paElementLayout[i].pElementLayout); + } + if (pBackendDXContext->papBlendState) + D3D_RELEASE_ARRAY(pBackendDXContext->cBlendState, pBackendDXContext->papBlendState); + if (pBackendDXContext->papDepthStencilState) + D3D_RELEASE_ARRAY(pBackendDXContext->cDepthStencilState, pBackendDXContext->papDepthStencilState); + if (pBackendDXContext->papRasterizerState) + D3D_RELEASE_ARRAY(pBackendDXContext->cRasterizerState, pBackendDXContext->papRasterizerState); + if (pBackendDXContext->papSamplerState) + D3D_RELEASE_ARRAY(pBackendDXContext->cSamplerState, pBackendDXContext->papSamplerState); + if (pBackendDXContext->paQuery) + { + for (uint32_t i = 0; i < pBackendDXContext->cQuery; ++i) + dxDestroyQuery(&pBackendDXContext->paQuery[i]); + } + if (pBackendDXContext->paShader) + { + for (uint32_t i = 0; i < pBackendDXContext->cShader; ++i) + dxDestroyShader(&pBackendDXContext->paShader[i]); + } + if (pBackendDXContext->paStreamOutput) + { + for (uint32_t i = 0; i < pBackendDXContext->cStreamOutput; ++i) + dxDestroyStreamOutput(&pBackendDXContext->paStreamOutput[i]); + } + if (pBackendDXContext->paUnorderedAccessView) + { + for (uint32_t i = 0; i < pBackendDXContext->cUnorderedAccessView; ++i) + D3D_RELEASE(pBackendDXContext->paUnorderedAccessView[i].u.pUnorderedAccessView); + } + + RTMemFreeZ(pBackendDXContext->papBlendState, sizeof(pBackendDXContext->papBlendState[0]) * pBackendDXContext->cBlendState); + RTMemFreeZ(pBackendDXContext->papDepthStencilState, sizeof(pBackendDXContext->papDepthStencilState[0]) * pBackendDXContext->cDepthStencilState); + RTMemFreeZ(pBackendDXContext->papSamplerState, sizeof(pBackendDXContext->papSamplerState[0]) * pBackendDXContext->cSamplerState); + RTMemFreeZ(pBackendDXContext->papRasterizerState, sizeof(pBackendDXContext->papRasterizerState[0]) * pBackendDXContext->cRasterizerState); + RTMemFreeZ(pBackendDXContext->paElementLayout, sizeof(pBackendDXContext->paElementLayout[0]) * pBackendDXContext->cElementLayout); + RTMemFreeZ(pBackendDXContext->paRenderTargetView, sizeof(pBackendDXContext->paRenderTargetView[0]) * pBackendDXContext->cRenderTargetView); + RTMemFreeZ(pBackendDXContext->paDepthStencilView, sizeof(pBackendDXContext->paDepthStencilView[0]) * pBackendDXContext->cDepthStencilView); + RTMemFreeZ(pBackendDXContext->paShaderResourceView, sizeof(pBackendDXContext->paShaderResourceView[0]) * pBackendDXContext->cShaderResourceView); + RTMemFreeZ(pBackendDXContext->paQuery, sizeof(pBackendDXContext->paQuery[0]) * pBackendDXContext->cQuery); + RTMemFreeZ(pBackendDXContext->paShader, sizeof(pBackendDXContext->paShader[0]) * pBackendDXContext->cShader); + RTMemFreeZ(pBackendDXContext->paStreamOutput, sizeof(pBackendDXContext->paStreamOutput[0]) * pBackendDXContext->cStreamOutput); + RTMemFreeZ(pBackendDXContext->paUnorderedAccessView, sizeof(pBackendDXContext->paUnorderedAccessView[0]) * pBackendDXContext->cUnorderedAccessView); + + /* Destroy backend surfaces which belong to this context. */ + /** @todo The context should have a list of surfaces (and also shared resources). */ + /** @todo This should not be needed in fSingleDevice mode. */ + for (uint32_t sid = 0; sid < pThisCC->svga.p3dState->cSurfaces; ++sid) + { + PVMSVGA3DSURFACE const pSurface = pThisCC->svga.p3dState->papSurfaces[sid]; + if ( pSurface + && pSurface->id == sid) + { + if (pSurface->idAssociatedContext == pDXContext->cid) + { + if (pSurface->pBackendSurface) + vmsvga3dBackSurfaceDestroy(pThisCC, true, pSurface); + } + else if (pSurface->idAssociatedContext == DX_CID_BACKEND) + { + /* May have shared resources in this context. */ + if (pSurface->pBackendSurface) + { + DXSHAREDTEXTURE *pSharedTexture = (DXSHAREDTEXTURE *)RTAvlU32Get(&pSurface->pBackendSurface->SharedTextureTree, pDXContext->cid); + if (pSharedTexture) + { + Assert(pSharedTexture->sid == sid); + RTAvlU32Remove(&pSurface->pBackendSurface->SharedTextureTree, pDXContext->cid); + D3D_RELEASE(pSharedTexture->pTexture); + RTMemFreeZ(pSharedTexture, sizeof(*pSharedTexture)); + } + } + } + } + } + + dxDeviceDestroy(pBackend, &pBackendDXContext->dxDevice); + + RTMemFreeZ(pBackendDXContext, sizeof(*pBackendDXContext)); + pDXContext->pBackendDXContext = NULL; + } + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBindContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend, pDXContext); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSwitchContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + if (!pBackend->fSingleDevice) + return VINF_NOT_IMPLEMENTED; /* Not required. */ + + /* The new context state will be applied by the generic DX code. */ + RT_NOREF(pDXContext); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXReadbackContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend, pDXContext); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXInvalidateContext(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetSingleConstantBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t slot, SVGA3dShaderType type, SVGA3dSurfaceId sid, uint32_t offsetInBytes, uint32_t sizeInBytes) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + if (sid == SVGA_ID_INVALID) + { + uint32_t const idxShaderState = type - SVGA3D_SHADERTYPE_MIN; + D3D_RELEASE(pDXContext->pBackendDXContext->resources.shaderState[idxShaderState].constantBuffers[slot]); + return VINF_SUCCESS; + } + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + rc = vmsvga3dMipmapLevel(pSurface, 0, 0, &pMipLevel); + AssertRCReturn(rc, rc); + + uint32_t const cbSurface = pMipLevel->cbSurface; + ASSERT_GUEST_RETURN( offsetInBytes < cbSurface + && sizeInBytes <= cbSurface - offsetInBytes, VERR_INVALID_PARAMETER); + + /* Constant buffers are created on demand. */ + Assert(pSurface->pBackendSurface == NULL); + + /* Upload the current data, if any. */ + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_SUBRESOURCE_DATA initialData; + if (pMipLevel->pSurfaceData) + { + initialData.pSysMem = (uint8_t *)pMipLevel->pSurfaceData + offsetInBytes; + initialData.SysMemPitch = sizeInBytes; + initialData.SysMemSlicePitch = sizeInBytes; + + pInitialData = &initialData; + +#ifdef LOG_ENABLED + if (LogIs8Enabled()) + { + float *pValuesF = (float *)initialData.pSysMem; + for (unsigned i = 0; i < sizeInBytes / sizeof(float) / 4; ++i) + { + Log(("ConstantF[%d]: " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR "\n", + i, FLOAT_FMT_ARGS(pValuesF[i*4 + 0]), FLOAT_FMT_ARGS(pValuesF[i*4 + 1]), FLOAT_FMT_ARGS(pValuesF[i*4 + 2]), FLOAT_FMT_ARGS(pValuesF[i*4 + 3]))); + } + } +#endif + } + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = sizeInBytes; + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + bd.StructureByteStride = 0; + + ID3D11Buffer *pBuffer = 0; + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pBuffer); + if (SUCCEEDED(hr)) + { + uint32_t const idxShaderState = type - SVGA3D_SHADERTYPE_MIN; + ID3D11Buffer **ppOldBuffer = &pDXContext->pBackendDXContext->resources.shaderState[idxShaderState].constantBuffers[slot]; + LogFunc(("constant buffer: [%u][%u]: sid = %u, %u, %u (%p -> %p)\n", + idxShaderState, slot, sid, offsetInBytes, sizeInBytes, *ppOldBuffer, pBuffer)); + D3D_RELEASE(*ppOldBuffer); + *ppOldBuffer = pBuffer; + } + + return VINF_SUCCESS; +} + +static int dxSetShaderResources(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderType type) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + +//DEBUG_BREAKPOINT_TEST(); + AssertReturn(type >= SVGA3D_SHADERTYPE_MIN && type < SVGA3D_SHADERTYPE_MAX, VERR_INVALID_PARAMETER); + uint32_t const idxShaderState = type - SVGA3D_SHADERTYPE_MIN; + uint32_t const *pSRIds = &pDXContext->svgaDXContext.shaderState[idxShaderState].shaderResources[0]; + ID3D11ShaderResourceView *papShaderResourceView[SVGA3D_DX_MAX_SRVIEWS]; + for (uint32_t i = 0; i < SVGA3D_DX_MAX_SRVIEWS; ++i) + { + SVGA3dShaderResourceViewId shaderResourceViewId = pSRIds[i]; + if (shaderResourceViewId != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN(shaderResourceViewId < pDXContext->pBackendDXContext->cShaderResourceView, VERR_INVALID_PARAMETER); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paShaderResourceView[shaderResourceViewId]; + Assert(pDXView->u.pShaderResourceView); + papShaderResourceView[i] = pDXView->u.pShaderResourceView; + } + else + papShaderResourceView[i] = NULL; + } + + dxShaderResourceViewSet(pDevice, type, 0, SVGA3D_DX_MAX_SRVIEWS, papShaderResourceView); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetShaderResources(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t startView, SVGA3dShaderType type, uint32_t cShaderResourceViewId, SVGA3dShaderResourceViewId const *paShaderResourceViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(startView, type, cShaderResourceViewId, paShaderResourceViewId); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderId shaderId, SVGA3dShaderType type) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(shaderId, type); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetSamplers(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t startSampler, SVGA3dShaderType type, uint32_t cSamplerId, SVGA3dSamplerId const *paSamplerId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + ID3D11SamplerState *papSamplerState[SVGA3D_DX_MAX_SAMPLERS]; + for (uint32_t i = 0; i < cSamplerId; ++i) + { + SVGA3dSamplerId samplerId = paSamplerId[i]; + if (samplerId != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN(samplerId < pDXContext->pBackendDXContext->cSamplerState, VERR_INVALID_PARAMETER); + papSamplerState[i] = pDXContext->pBackendDXContext->papSamplerState[samplerId]; + } + else + papSamplerState[i] = NULL; + } + + dxSamplerSet(pDevice, type, startSampler, cSamplerId, papSamplerState); + return VINF_SUCCESS; +} + + +static void vboxDXMatchShaderInput(DXSHADER *pDXShader, DXSHADER *pDXShaderPrior) +{ + /* For each input generic attribute of the shader find corresponding entry in the prior shader. */ + for (uint32_t i = 0; i < pDXShader->shaderInfo.cInputSignature; ++i) + { + SVGA3dDXSignatureEntry const *pSignatureEntry = &pDXShader->shaderInfo.aInputSignature[i]; + DXShaderAttributeSemantic *pSemantic = &pDXShader->shaderInfo.aInputSemantic[i]; + + if (pSignatureEntry->semanticName != SVGADX_SIGNATURE_SEMANTIC_NAME_UNDEFINED) + continue; + + int iMatch = -1; + for (uint32_t iPrior = 0; iPrior < pDXShaderPrior->shaderInfo.cOutputSignature; ++iPrior) + { + SVGA3dDXSignatureEntry const *pPriorSignatureEntry = &pDXShaderPrior->shaderInfo.aOutputSignature[iPrior]; + + if (pPriorSignatureEntry->semanticName != SVGADX_SIGNATURE_SEMANTIC_NAME_UNDEFINED) + continue; + + if (pPriorSignatureEntry->registerIndex == pSignatureEntry->registerIndex) + { + iMatch = iPrior; + if (pPriorSignatureEntry->mask == pSignatureEntry->mask) + break; /* Exact match, no need to continue search. */ + } + } + + if (iMatch >= 0) + { + SVGA3dDXSignatureEntry const *pPriorSignatureEntry = &pDXShaderPrior->shaderInfo.aOutputSignature[iMatch]; + DXShaderAttributeSemantic const *pPriorSemantic = &pDXShaderPrior->shaderInfo.aOutputSemantic[iMatch]; + + Assert(pPriorSignatureEntry->registerIndex == pSignatureEntry->registerIndex); + Assert((pPriorSignatureEntry->mask & pSignatureEntry->mask) == pSignatureEntry->mask); + RT_NOREF(pPriorSignatureEntry); + + pSemantic->SemanticIndex = pPriorSemantic->SemanticIndex; + } + } +} + + +static void vboxDXMatchShaderSignatures(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, DXSHADER *pDXShader) +{ + SVGA3dShaderId const shaderIdVS = pDXContext->svgaDXContext.shaderState[SVGA3D_SHADERTYPE_VS - SVGA3D_SHADERTYPE_MIN].shaderId; + SVGA3dShaderId const shaderIdHS = pDXContext->svgaDXContext.shaderState[SVGA3D_SHADERTYPE_HS - SVGA3D_SHADERTYPE_MIN].shaderId; + SVGA3dShaderId const shaderIdDS = pDXContext->svgaDXContext.shaderState[SVGA3D_SHADERTYPE_DS - SVGA3D_SHADERTYPE_MIN].shaderId; + SVGA3dShaderId const shaderIdGS = pDXContext->svgaDXContext.shaderState[SVGA3D_SHADERTYPE_GS - SVGA3D_SHADERTYPE_MIN].shaderId; + SVGA3dShaderId const shaderIdPS = pDXContext->svgaDXContext.shaderState[SVGA3D_SHADERTYPE_PS - SVGA3D_SHADERTYPE_MIN].shaderId; + + /* Try to fix the input semantic indices. Output is usually not changed. */ + switch (pDXShader->enmShaderType) + { + case SVGA3D_SHADERTYPE_VS: + { + /* Match input to input layout, which sets generic semantic indices to the source registerIndex (dxCreateInputLayout). */ + for (uint32_t i = 0; i < pDXShader->shaderInfo.cInputSignature; ++i) + { + SVGA3dDXSignatureEntry const *pSignatureEntry = &pDXShader->shaderInfo.aInputSignature[i]; + DXShaderAttributeSemantic *pSemantic = &pDXShader->shaderInfo.aInputSemantic[i]; + + if (pSignatureEntry->semanticName != SVGADX_SIGNATURE_SEMANTIC_NAME_UNDEFINED) + continue; + + pSemantic->SemanticIndex = pSignatureEntry->registerIndex; + } + break; + } + case SVGA3D_SHADERTYPE_HS: + { + /* Input of a HS shader is the output of VS. */ + DXSHADER *pDXShaderPrior; + if (shaderIdVS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdVS]; + else + pDXShaderPrior = NULL; + + if (pDXShaderPrior) + vboxDXMatchShaderInput(pDXShader, pDXShaderPrior); + + break; + } + case SVGA3D_SHADERTYPE_DS: + { + /* Input of a DS shader is the output of HS. */ + DXSHADER *pDXShaderPrior; + if (shaderIdHS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdHS]; + else + pDXShaderPrior = NULL; + + if (pDXShaderPrior) + vboxDXMatchShaderInput(pDXShader, pDXShaderPrior); + + break; + } + case SVGA3D_SHADERTYPE_GS: + { + /* Input signature of a GS shader is the output of DS or VS. */ + DXSHADER *pDXShaderPrior; + if (shaderIdDS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdDS]; + else if (shaderIdVS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdVS]; + else + pDXShaderPrior = NULL; + + if (pDXShaderPrior) + { + /* If GS shader does not have input signature (Windows guest can do that), + * then assign the prior shader signature as GS input. + */ + if (pDXShader->shaderInfo.cInputSignature == 0) + { + pDXShader->shaderInfo.cInputSignature = pDXShaderPrior->shaderInfo.cOutputSignature; + memcpy(pDXShader->shaderInfo.aInputSignature, + pDXShaderPrior->shaderInfo.aOutputSignature, + pDXShaderPrior->shaderInfo.cOutputSignature * sizeof(SVGA3dDXSignatureEntry)); + memcpy(pDXShader->shaderInfo.aInputSemantic, + pDXShaderPrior->shaderInfo.aOutputSemantic, + pDXShaderPrior->shaderInfo.cOutputSignature * sizeof(DXShaderAttributeSemantic)); + } + else + vboxDXMatchShaderInput(pDXShader, pDXShaderPrior); + } + + /* Output signature of a GS shader is the input of the pixel shader. */ + if (shaderIdPS != SVGA3D_INVALID_ID) + { + /* If GS shader does not have output signature (Windows guest can do that), + * then assign the PS shader signature as GS output. + */ + if (pDXShader->shaderInfo.cOutputSignature == 0) + { + DXSHADER const *pDXShaderPosterior = &pDXContext->pBackendDXContext->paShader[shaderIdPS]; + pDXShader->shaderInfo.cOutputSignature = pDXShaderPosterior->shaderInfo.cInputSignature; + memcpy(pDXShader->shaderInfo.aOutputSignature, + pDXShaderPosterior->shaderInfo.aInputSignature, + pDXShaderPosterior->shaderInfo.cInputSignature * sizeof(SVGA3dDXSignatureEntry)); + memcpy(pDXShader->shaderInfo.aOutputSemantic, + pDXShaderPosterior->shaderInfo.aInputSemantic, + pDXShaderPosterior->shaderInfo.cInputSignature * sizeof(DXShaderAttributeSemantic)); + } + } + + SVGA3dStreamOutputId const soid = pDXContext->svgaDXContext.streamOut.soid; + if (soid != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN_VOID(soid < pDXContext->pBackendDXContext->cStreamOutput); + + /* Set semantic names and indices for SO declaration entries according to the shader output. */ + SVGACOTableDXStreamOutputEntry const *pStreamOutputEntry = &pDXContext->cot.paStreamOutput[soid]; + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[soid]; + + if (pDXStreamOutput->cDeclarationEntry == 0) + { + int rc = dxDefineStreamOutput(pThisCC, pDXContext, soid, pStreamOutputEntry, pDXShader); + AssertRCReturnVoid(rc); +#ifdef LOG_ENABLED + Log6(("Stream output declaration:\n\n")); + Log6(("Stream SemanticName SemanticIndex StartComponent ComponentCount OutputSlot\n")); + Log6(("------ -------------- ------------- -------------- -------------- ----------\n")); + for (unsigned i = 0; i < pDXStreamOutput->cDeclarationEntry; ++i) + { + D3D11_SO_DECLARATION_ENTRY *p = &pDXStreamOutput->aDeclarationEntry[i]; + Log6(("%d %-14s %d %d %d %d\n", + p->Stream, p->SemanticName, p->SemanticIndex, p->StartComponent, p->ComponentCount, p->OutputSlot)); + } + Log6(("\n")); +#endif + + } + } + break; + } + case SVGA3D_SHADERTYPE_PS: + { + /* Input of a PS shader is the output of GS, DS or VS. */ + DXSHADER *pDXShaderPrior; + if (shaderIdGS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdGS]; + else if (shaderIdDS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdDS]; + else if (shaderIdVS != SVGA3D_INVALID_ID) + pDXShaderPrior = &pDXContext->pBackendDXContext->paShader[shaderIdVS]; + else + pDXShaderPrior = NULL; + + if (pDXShaderPrior) + vboxDXMatchShaderInput(pDXShader, pDXShaderPrior); + break; + } + default: + break; + } + + /* Intermediate shaders normally have both input and output signatures. However it is ok if they do not. + * Just catch this unusual case in order to see if everything is fine. + */ + Assert( ( pDXShader->enmShaderType == SVGA3D_SHADERTYPE_VS + || pDXShader->enmShaderType == SVGA3D_SHADERTYPE_PS + || pDXShader->enmShaderType == SVGA3D_SHADERTYPE_CS) + || (pDXShader->shaderInfo.cInputSignature && pDXShader->shaderInfo.cOutputSignature)); +} + + +static void vboxDXUpdateVSInputSignature(PVMSVGA3DDXCONTEXT pDXContext, DXSHADER *pDXShader) +{ + SVGA3dElementLayoutId const elementLayoutId = pDXContext->svgaDXContext.inputAssembly.layoutId; + if (elementLayoutId != SVGA3D_INVALID_ID) + { + SVGACOTableDXElementLayoutEntry const *pElementLayout = &pDXContext->cot.paElementLayout[elementLayoutId]; + for (uint32_t i = 0; i < RT_MIN(pElementLayout->numDescs, pDXShader->shaderInfo.cInputSignature); ++i) + { + SVGA3dInputElementDesc const *pElementDesc = &pElementLayout->descs[i]; + SVGA3dDXSignatureEntry *pSignatureEntry = &pDXShader->shaderInfo.aInputSignature[i]; + pSignatureEntry->componentType = DXShaderComponentTypeFromFormat(pElementDesc->format); + } + } +} + + +static void dxCreateInputLayout(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dElementLayoutId elementLayoutId, DXSHADER *pDXShader) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturnVoid(pDevice->pDevice); + + SVGACOTableDXElementLayoutEntry const *pEntry = &pDXContext->cot.paElementLayout[elementLayoutId]; + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + + if (pDXElementLayout->cElementDesc == 0) + { + /* Semantic name is not interpreted by D3D, therefore arbitrary names can be used + * if they are consistent between the element layout and shader input signature. + * "In general, data passed between pipeline stages is completely generic and is not uniquely + * interpreted by the system; arbitrary semantics are allowed ..." + * + * However D3D runtime insists that "SemanticName string ("POSITIO1") cannot end with a number." + * + * System-Value semantics ("SV_*") between shaders require proper names of course. + * But they are irrelevant for input attributes. + */ + pDXElementLayout->cElementDesc = pEntry->numDescs; + for (uint32_t i = 0; i < pEntry->numDescs; ++i) + { + D3D11_INPUT_ELEMENT_DESC *pDst = &pDXElementLayout->aElementDesc[i]; + SVGA3dInputElementDesc const *pSrc = &pEntry->descs[i]; + pDst->SemanticName = "ATTRIB"; + pDst->SemanticIndex = pSrc->inputRegister; + pDst->Format = vmsvgaDXSurfaceFormat2Dxgi(pSrc->format); + Assert(pDst->Format != DXGI_FORMAT_UNKNOWN); + pDst->InputSlot = pSrc->inputSlot; + pDst->AlignedByteOffset = pSrc->alignedByteOffset; + pDst->InputSlotClass = (D3D11_INPUT_CLASSIFICATION)pSrc->inputSlotClass; + pDst->InstanceDataStepRate = pSrc->instanceDataStepRate; + } + } + + HRESULT hr = pDevice->pDevice->CreateInputLayout(pDXElementLayout->aElementDesc, + pDXElementLayout->cElementDesc, + pDXShader->pvDXBC, + pDXShader->cbDXBC, + &pDXElementLayout->pElementLayout); + Assert(SUCCEEDED(hr)); RT_NOREF(hr); +} + + +static void dxSetConstantBuffers(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ +//DEBUG_BREAKPOINT_TEST(); + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + VMSVGA3DBACKENDDXCONTEXT *pBackendDXContext = pDXContext->pBackendDXContext; + + AssertCompile(RT_ELEMENTS(pBackendDXContext->resources.shaderState[0].constantBuffers) == SVGA3D_DX_MAX_CONSTBUFFERS); + + for (uint32_t idxShaderState = 0; idxShaderState < SVGA3D_NUM_SHADERTYPE; ++idxShaderState) + { + SVGA3dShaderType const shaderType = (SVGA3dShaderType)(idxShaderState + SVGA3D_SHADERTYPE_MIN); + for (uint32_t idxSlot = 0; idxSlot < SVGA3D_DX_MAX_CONSTBUFFERS; ++idxSlot) + { + ID3D11Buffer **pBufferContext = &pBackendDXContext->resources.shaderState[idxShaderState].constantBuffers[idxSlot]; + ID3D11Buffer **pBufferPipeline = &pBackend->resources.shaderState[idxShaderState].constantBuffers[idxSlot]; + if (*pBufferContext != *pBufferPipeline) + { + LogFunc(("constant buffer: [%u][%u]: %p -> %p\n", + idxShaderState, idxSlot, *pBufferPipeline, *pBufferContext)); + dxConstantBufferSet(pDXDevice, idxSlot, shaderType, *pBufferContext); + + if (*pBufferContext) + (*pBufferContext)->AddRef(); + D3D_RELEASE(*pBufferPipeline); + *pBufferPipeline = *pBufferContext; + } + } + } +} + +static void dxSetVertexBuffers(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ +//DEBUG_BREAKPOINT_TEST(); + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + VMSVGA3DBACKENDDXCONTEXT *pBackendDXContext = pDXContext->pBackendDXContext; + + AssertCompile(RT_ELEMENTS(pBackendDXContext->resources.inputAssembly.vertexBuffers) == SVGA3D_DX_MAX_VERTEXBUFFERS); + + ID3D11Buffer *paResources[SVGA3D_DX_MAX_VERTEXBUFFERS]; + UINT paStride[SVGA3D_DX_MAX_VERTEXBUFFERS]; + UINT paOffset[SVGA3D_DX_MAX_VERTEXBUFFERS]; + + int32_t idxMaxSlot = -1; + for (uint32_t i = 0; i < SVGA3D_DX_MAX_VERTEXBUFFERS; ++i) + { + DXBOUNDVERTEXBUFFER *pBufferContext = &pBackendDXContext->resources.inputAssembly.vertexBuffers[i]; + DXBOUNDVERTEXBUFFER *pBufferPipeline = &pBackend->resources.inputAssembly.vertexBuffers[i]; + if ( pBufferContext->pBuffer != pBufferPipeline->pBuffer + || pBufferContext->stride != pBufferPipeline->stride + || pBufferContext->offset != pBufferPipeline->offset) + { + LogFunc(("vertex buffer: [%u]: sid = %u, %p (stride %d, off %d) -> %p (stride %d, off %d)\n", + i, pDXContext->svgaDXContext.inputAssembly.vertexBuffers[i].bufferId, + pBufferPipeline->pBuffer, pBufferPipeline->stride, pBufferPipeline->offset, + pBufferContext->pBuffer, pBufferContext->stride, pBufferContext->offset)); + + if (pBufferContext->pBuffer != pBufferPipeline->pBuffer) + { + if (pBufferContext->pBuffer) + pBufferContext->pBuffer->AddRef(); + D3D_RELEASE(pBufferPipeline->pBuffer); + } + *pBufferPipeline = *pBufferContext; + + idxMaxSlot = i; + } +#ifdef LOG_ENABLED + else if (pBufferContext->pBuffer) + { + LogFunc(("vertex buffer: [%u]: sid = %u, %p (stride %d, off %d)\n", + i, pDXContext->svgaDXContext.inputAssembly.vertexBuffers[i].bufferId, + pBufferContext->pBuffer, pBufferContext->stride, pBufferContext->offset)); + } +#endif + + paResources[i] = pBufferContext->pBuffer; + if (pBufferContext->pBuffer) + { + paStride[i] = pBufferContext->stride; + paOffset[i] = pBufferContext->offset; + } + else + { + paStride[i] = 0; + paOffset[i] = 0; + } + } + + LogFunc(("idxMaxSlot = %d\n", idxMaxSlot)); + if (idxMaxSlot >= 0) + pDXDevice->pImmediateContext->IASetVertexBuffers(0, idxMaxSlot + 1, paResources, paStride, paOffset); +} + +static void dxSetIndexBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ +//DEBUG_BREAKPOINT_TEST(); + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + VMSVGA3DBACKENDDXCONTEXT *pBackendDXContext = pDXContext->pBackendDXContext; + + DXBOUNDINDEXBUFFER *pBufferContext = &pBackendDXContext->resources.inputAssembly.indexBuffer; + DXBOUNDINDEXBUFFER *pBufferPipeline = &pBackend->resources.inputAssembly.indexBuffer; + if ( pBufferContext->pBuffer != pBufferPipeline->pBuffer + || pBufferContext->indexBufferOffset != pBufferPipeline->indexBufferOffset + || pBufferContext->indexBufferFormat != pBufferPipeline->indexBufferFormat) + { + LogFunc(("index_buffer: sid = %u, %p -> %p\n", + pDXContext->svgaDXContext.inputAssembly.indexBufferSid, pBufferPipeline->pBuffer, pBufferContext->pBuffer)); + + if (pBufferContext->pBuffer != pBufferPipeline->pBuffer) + { + if (pBufferContext->pBuffer) + pBufferContext->pBuffer->AddRef(); + D3D_RELEASE(pBufferPipeline->pBuffer); + } + *pBufferPipeline = *pBufferContext; + + pDXDevice->pImmediateContext->IASetIndexBuffer(pBufferContext->pBuffer, pBufferContext->indexBufferFormat, pBufferContext->indexBufferOffset); + } +} + +#ifdef LOG_ENABLED +static void dxDbgLogVertexElement(DXGI_FORMAT Format, void const *pvElementData) +{ + switch (Format) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + float const *pValues = (float const *)pvElementData; + Log8(("{ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " },", + FLOAT_FMT_ARGS(pValues[0]), FLOAT_FMT_ARGS(pValues[1]), FLOAT_FMT_ARGS(pValues[2]), FLOAT_FMT_ARGS(pValues[3]))); + break; + } + case DXGI_FORMAT_R32G32B32_FLOAT: + { + float const *pValues = (float const *)pvElementData; + Log8(("{ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " },", + FLOAT_FMT_ARGS(pValues[0]), FLOAT_FMT_ARGS(pValues[1]), FLOAT_FMT_ARGS(pValues[2]))); + break; + } + case DXGI_FORMAT_R32G32_FLOAT: + { + float const *pValues = (float const *)pvElementData; + Log8(("{ " FLOAT_FMT_STR ", " FLOAT_FMT_STR " },", + FLOAT_FMT_ARGS(pValues[0]), FLOAT_FMT_ARGS(pValues[1]))); + break; + } + case DXGI_FORMAT_R16G16_FLOAT: + { + uint16_t const *pValues = (uint16_t const *)pvElementData; + Log8(("{ f16 " FLOAT_FMT_STR ", " FLOAT_FMT_STR " },", + FLOAT_FMT_ARGS(float16ToFloat(pValues[0])), FLOAT_FMT_ARGS(float16ToFloat(pValues[1])))); + break; + } + case DXGI_FORMAT_R32G32_SINT: + { + int32_t const *pValues = (int32_t const *)pvElementData; + Log8(("{ %d, %d },", + pValues[0], pValues[1])); + break; + } + case DXGI_FORMAT_R32G32_UINT: + { + uint32_t const *pValues = (uint32_t const *)pvElementData; + Log8(("{ %u, %u },", + pValues[0], pValues[1])); + break; + } + case DXGI_FORMAT_R32_SINT: + { + int32_t const *pValues = (int32_t const *)pvElementData; + Log8(("{ %d },", + pValues[0])); + break; + } + case DXGI_FORMAT_R32_UINT: + { + uint32_t const *pValues = (uint32_t const *)pvElementData; + Log8(("{ %u },", + pValues[0])); + break; + } + case DXGI_FORMAT_R16G16_SINT: + { + int16_t const *pValues = (int16_t const *)pvElementData; + Log8(("{ s %d, %d },", + pValues[0], pValues[1])); + break; + } + case DXGI_FORMAT_R16G16_UINT: + { + uint16_t const *pValues = (uint16_t const *)pvElementData; + Log8(("{ u %u, %u },", + pValues[0], pValues[1])); + break; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + uint8_t const *pValues = (uint8_t const *)pvElementData; + Log8(("{ 8unorm %u, %u, %u, %u },", + pValues[0], pValues[1], pValues[2], pValues[3])); + break; + } + case DXGI_FORMAT_R8G8_UNORM: + { + uint8_t const *pValues = (uint8_t const *)pvElementData; + Log8(("{ 8unorm %u, %u },", + pValues[0], pValues[1])); + break; + } + default: + Log8(("{ ??? DXGI_FORMAT %d },", + Format)); + AssertFailed(); + } +} + + +static void dxDbgDumpVertexData(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t vertexCount, uint32_t startVertexLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + for (uint32_t iSlot = 0; iSlot < SVGA3D_DX_MAX_VERTEXBUFFERS; ++iSlot) + { + DXBOUNDVERTEXBUFFER *pBufferPipeline = &pBackend->resources.inputAssembly.vertexBuffers[iSlot]; + uint32_t const sid = pDXContext->svgaDXContext.inputAssembly.vertexBuffers[iSlot].bufferId; + if (sid == SVGA3D_INVALID_ID) + { + Assert(pBufferPipeline->pBuffer == 0); + continue; + } + + Assert(pBufferPipeline->pBuffer); + + SVGA3dSurfaceImageId image; + image.sid = sid; + image.face = 0; + image.mipmap = 0; + + VMSVGA3D_MAPPED_SURFACE map; + int rc = vmsvga3dBackSurfaceMap(pThisCC, &image, NULL, VMSVGA3D_SURFACE_MAP_READ, &map); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + uint8_t const *pu8VertexData = (uint8_t *)map.pvData; + pu8VertexData += pBufferPipeline->offset; + pu8VertexData += startVertexLocation * pBufferPipeline->stride; + + SVGA3dElementLayoutId const elementLayoutId = pDXContext->svgaDXContext.inputAssembly.layoutId; + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + Assert(pDXElementLayout->cElementDesc > 0); + + Log8(("Vertex buffer dump: sid = %u, vertexCount %u, startVertexLocation %d, offset = %d, stride = %d:\n", + sid, vertexCount, startVertexLocation, pBufferPipeline->offset, pBufferPipeline->stride)); + + for (uint32_t v = 0; v < vertexCount; ++v) + { + Log8(("slot[%u] v%u { ", iSlot, startVertexLocation + v)); + + for (uint32_t iElement = 0; iElement < pDXElementLayout->cElementDesc; ++iElement) + { + D3D11_INPUT_ELEMENT_DESC *pElement = &pDXElementLayout->aElementDesc[iElement]; + if (pElement->InputSlot == iSlot) + dxDbgLogVertexElement(pElement->Format, pu8VertexData + pElement->AlignedByteOffset); + } + + Log8((" }\n")); + + if (pBufferPipeline->stride == 0) + break; + + pu8VertexData += pBufferPipeline->stride; + } + + vmsvga3dBackSurfaceUnmap(pThisCC, &image, &map, /* fWritten = */ false); + } + } +} + + +static void dxDbgDumpIndexedVertexData(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t indexCount, uint32_t startIndexLocation, int32_t baseVertexLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + SVGA3dSurfaceImageId image; + + DXBOUNDINDEXBUFFER *pIB = &pBackend->resources.inputAssembly.indexBuffer; + uint32_t const sidIB = pDXContext->svgaDXContext.inputAssembly.indexBufferSid; + if (sidIB == SVGA3D_INVALID_ID) + { + Assert(pIB->pBuffer == 0); + return; + } + + Assert(pIB->pBuffer); + UINT const BytesPerIndex = pIB->indexBufferFormat == DXGI_FORMAT_R16_UINT ? 2 : 4; + + void *pvIndexBuffer; + uint32_t cbIndexBuffer; + int rc = dxReadBuffer(pDXDevice, pIB->pBuffer, pIB->indexBufferOffset + startIndexLocation * BytesPerIndex, indexCount * BytesPerIndex, &pvIndexBuffer, &cbIndexBuffer); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + uint8_t const *pu8IndexData = (uint8_t *)pvIndexBuffer; + + for (uint32_t iSlot = 0; iSlot < SVGA3D_DX_MAX_VERTEXBUFFERS; ++iSlot) + { + DXBOUNDVERTEXBUFFER *pVB = &pBackend->resources.inputAssembly.vertexBuffers[iSlot]; + uint32_t const sidVB = pDXContext->svgaDXContext.inputAssembly.vertexBuffers[iSlot].bufferId; + if (sidVB == SVGA3D_INVALID_ID) + { + Assert(pVB->pBuffer == 0); + continue; + } + + Assert(pVB->pBuffer); + + image.sid = sidVB; + image.face = 0; + image.mipmap = 0; + + VMSVGA3D_MAPPED_SURFACE mapVB; + rc = vmsvga3dBackSurfaceMap(pThisCC, &image, NULL, VMSVGA3D_SURFACE_MAP_READ, &mapVB); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + uint8_t const *pu8VertexData = (uint8_t *)mapVB.pvData; + pu8VertexData += pVB->offset; + pu8VertexData += baseVertexLocation * pVB->stride; + + SVGA3dElementLayoutId const elementLayoutId = pDXContext->svgaDXContext.inputAssembly.layoutId; + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + Assert(pDXElementLayout->cElementDesc > 0); + + Log8(("Vertex buffer dump: sid = %u, indexCount %u, startIndexLocation %d, baseVertexLocation %d, offset = %d, stride = %d:\n", + sidVB, indexCount, startIndexLocation, baseVertexLocation, pVB->offset, pVB->stride)); + + for (uint32_t i = 0; i < indexCount; ++i) + { + uint32_t Index; + if (BytesPerIndex == 2) + Index = ((uint16_t *)pu8IndexData)[i]; + else + Index = ((uint32_t *)pu8IndexData)[i]; + + Log8(("slot[%u] v%u { ", iSlot, Index)); + + for (uint32_t iElement = 0; iElement < pDXElementLayout->cElementDesc; ++iElement) + { + D3D11_INPUT_ELEMENT_DESC *pElement = &pDXElementLayout->aElementDesc[iElement]; + if (pElement->InputSlotClass != D3D11_INPUT_PER_VERTEX_DATA) + continue; + + if (pElement->InputSlot == iSlot) + { + uint8_t const *pu8Vertex = pu8VertexData + Index * pVB->stride; + dxDbgLogVertexElement(pElement->Format, pu8Vertex + pElement->AlignedByteOffset); + } + } + + Log8((" }\n")); + + if (pVB->stride == 0) + break; + } + + vmsvga3dBackSurfaceUnmap(pThisCC, &image, &mapVB, /* fWritten = */ false); + } + } + + RTMemFree(pvIndexBuffer); + } +} + + +static void dxDbgDumpInstanceData(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t instanceCount, uint32_t startInstanceLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + SVGA3dSurfaceImageId image; + + /* + * Dump per-instance data. + */ + for (uint32_t iInstance = 0; iInstance < instanceCount; ++iInstance) + { + for (uint32_t iSlot = 0; iSlot < SVGA3D_DX_MAX_VERTEXBUFFERS; ++iSlot) + { + DXBOUNDVERTEXBUFFER *pVB = &pBackend->resources.inputAssembly.vertexBuffers[iSlot]; + uint32_t const sidVB = pDXContext->svgaDXContext.inputAssembly.vertexBuffers[iSlot].bufferId; + if (sidVB == SVGA3D_INVALID_ID) + { + Assert(pVB->pBuffer == 0); + continue; + } + + Assert(pVB->pBuffer); + + image.sid = sidVB; + image.face = 0; + image.mipmap = 0; + + VMSVGA3D_MAPPED_SURFACE mapVB; + int rc = vmsvga3dBackSurfaceMap(pThisCC, &image, NULL, VMSVGA3D_SURFACE_MAP_READ, &mapVB); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + uint8_t const *pu8VertexData = (uint8_t *)mapVB.pvData; + pu8VertexData += pVB->offset; + pu8VertexData += startInstanceLocation * pVB->stride; + + SVGA3dElementLayoutId const elementLayoutId = pDXContext->svgaDXContext.inputAssembly.layoutId; + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + Assert(pDXElementLayout->cElementDesc > 0); + + Log8(("Instance data dump: sid = %u, iInstance %u, startInstanceLocation %d, offset = %d, stride = %d:\n", + sidVB, iInstance, startInstanceLocation, pVB->offset, pVB->stride)); + + Log8(("slot[%u] i%u { ", iSlot, iInstance)); + for (uint32_t iElement = 0; iElement < pDXElementLayout->cElementDesc; ++iElement) + { + D3D11_INPUT_ELEMENT_DESC *pElement = &pDXElementLayout->aElementDesc[iElement]; + if (pElement->InputSlotClass != D3D11_INPUT_PER_INSTANCE_DATA) + continue; + + if (pElement->InputSlot == iSlot) + { + uint8_t const *pu8Vertex = pu8VertexData + iInstance * pVB->stride; + dxDbgLogVertexElement(pElement->Format, pu8Vertex + pElement->AlignedByteOffset); + } + } + Log8((" }\n")); + + vmsvga3dBackSurfaceUnmap(pThisCC, &image, &mapVB, /* fWritten = */ false); + } + } + } +} + +static void dxDbgDumpVertices_Draw(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t vertexCount, uint32_t startVertexLocation) +{ + dxDbgDumpVertexData(pThisCC, pDXContext, vertexCount, startVertexLocation); +} + + +static void dxDbgDumpVertices_DrawIndexed(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t indexCount, uint32_t startIndexLocation, int32_t baseVertexLocation) +{ + dxDbgDumpIndexedVertexData(pThisCC, pDXContext, indexCount, startIndexLocation, baseVertexLocation); +} + + +static void dxDbgDumpVertices_DrawInstanced(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + uint32_t vertexCountPerInstance, uint32_t instanceCount, + uint32_t startVertexLocation, uint32_t startInstanceLocation) +{ + dxDbgDumpVertexData(pThisCC, pDXContext, vertexCountPerInstance, startVertexLocation); + dxDbgDumpInstanceData(pThisCC, pDXContext, instanceCount, startInstanceLocation); +} + + +static void dxDbgDumpVertices_DrawIndexedInstanced(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + uint32_t indexCountPerInstance, uint32_t instanceCount, + uint32_t startIndexLocation, int32_t baseVertexLocation, + uint32_t startInstanceLocation) +{ + dxDbgDumpIndexedVertexData(pThisCC, pDXContext, indexCountPerInstance, startIndexLocation, baseVertexLocation); + dxDbgDumpInstanceData(pThisCC, pDXContext, instanceCount, startInstanceLocation); +} +#endif + + +static void dxSetupPipeline(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + /* Make sure that any draw operations on shader resource views have finished. */ + AssertCompile(RT_ELEMENTS(pDXContext->svgaDXContext.shaderState) == SVGA3D_NUM_SHADERTYPE); + AssertCompile(RT_ELEMENTS(pDXContext->svgaDXContext.shaderState[0].shaderResources) == SVGA3D_DX_MAX_SRVIEWS); + + int rc; + + /* Unbind render target views because they mught be (re-)used as shader resource views. */ + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + pDXDevice->pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL); + for (unsigned i = 0; i < SVGA3D_DX11_1_MAX_UAVIEWS; ++i) + { + ID3D11UnorderedAccessView *pNullUA = 0; + pDXDevice->pImmediateContext->CSSetUnorderedAccessViews(i, 1, &pNullUA, NULL); + } + + dxSetConstantBuffers(pThisCC, pDXContext); + dxSetVertexBuffers(pThisCC, pDXContext); + dxSetIndexBuffer(pThisCC, pDXContext); + + /* + * Shader resources + */ + + /* Make sure that the shader resource views exist. */ + for (uint32_t idxShaderState = 0; idxShaderState < SVGA3D_NUM_SHADERTYPE; ++idxShaderState) + { + for (uint32_t idxSR = 0; idxSR < SVGA3D_DX_MAX_SRVIEWS; ++idxSR) + { + SVGA3dShaderResourceViewId const shaderResourceViewId = pDXContext->svgaDXContext.shaderState[idxShaderState].shaderResources[idxSR]; + if (shaderResourceViewId != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN_VOID(shaderResourceViewId < pDXContext->pBackendDXContext->cShaderResourceView); + + SVGACOTableDXSRViewEntry const *pSRViewEntry = dxGetShaderResourceViewEntry(pDXContext, shaderResourceViewId); + AssertContinue(pSRViewEntry != NULL); + + uint32_t const sid = pSRViewEntry->sid; + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + if (RT_FAILURE(rc)) + { + AssertMsgFailed(("sid = %u, rc = %Rrc\n", sid, rc)); + continue; + } + + /* The guest might have invalidated the surface in which case pSurface->pBackendSurface is NULL. */ + /** @todo This is not needed for "single DX device" mode. */ + if (pSurface->pBackendSurface) + { + /* Wait for the surface to finish drawing. */ + dxSurfaceWait(pThisCC->svga.p3dState, pSurface, pDXContext->cid); + } + + /* If a view has not been created yet, do it now. */ + if (!pDXContext->pBackendDXContext->paShaderResourceView[shaderResourceViewId].u.pView) + { +//DEBUG_BREAKPOINT_TEST(); + LogFunc(("Re-creating SRV: sid=%u srvid = %u\n", sid, shaderResourceViewId)); + rc = dxDefineShaderResourceView(pThisCC, pDXContext, shaderResourceViewId, pSRViewEntry); + AssertContinue(RT_SUCCESS(rc)); + } + + LogFunc(("srv[%d][%d] sid = %u, srvid = %u, format = %s(%d)\n", idxShaderState, idxSR, sid, shaderResourceViewId, vmsvgaLookupEnum((int)pSRViewEntry->format, &g_SVGA3dSurfaceFormat2String), pSRViewEntry->format)); + +#ifdef DUMP_BITMAPS + SVGA3dSurfaceImageId image; + image.sid = sid; + image.face = 0; + image.mipmap = 0; + VMSVGA3D_MAPPED_SURFACE map; + int rc2 = vmsvga3dSurfaceMap(pThisCC, &image, NULL, VMSVGA3D_SURFACE_MAP_READ, &map); + if (RT_SUCCESS(rc2)) + { + vmsvga3dMapWriteBmpFile(&map, "sr-"); + vmsvga3dSurfaceUnmap(pThisCC, &image, &map, /* fWritten = */ false); + } + else + Log(("Map failed %Rrc\n", rc)); +#endif + } + } + + /* Set shader resources. */ + rc = dxSetShaderResources(pThisCC, pDXContext, (SVGA3dShaderType)(idxShaderState + SVGA3D_SHADERTYPE_MIN)); + AssertRC(rc); + } + + /* + * Compute shader unordered access views + */ + + for (uint32_t idxUA = 0; idxUA < SVGA3D_DX11_1_MAX_UAVIEWS; ++idxUA) + { + SVGA3dUAViewId const uaViewId = pDXContext->svgaDXContext.csuaViewIds[idxUA]; + if (uaViewId != SVGA3D_INVALID_ID) + { +//DEBUG_BREAKPOINT_TEST(); + ASSERT_GUEST_RETURN_VOID(uaViewId < pDXContext->pBackendDXContext->cUnorderedAccessView); + + SVGACOTableDXUAViewEntry const *pUAViewEntry = dxGetUnorderedAccessViewEntry(pDXContext, uaViewId); + AssertContinue(pUAViewEntry != NULL); + + uint32_t const sid = pUAViewEntry->sid; + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + AssertRCReturnVoid(rc); + + /* The guest might have invalidated the surface in which case pSurface->pBackendSurface is NULL. */ + /** @todo This is not needed for "single DX device" mode. */ + if (pSurface->pBackendSurface) + { + /* Wait for the surface to finish drawing. */ + dxSurfaceWait(pThisCC->svga.p3dState, pSurface, pDXContext->cid); + } + + /* If a view has not been created yet, do it now. */ + if (!pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId].u.pView) + { + LogFunc(("Re-creating UAV: sid=%u uaid = %u\n", sid, uaViewId)); + rc = dxDefineUnorderedAccessView(pThisCC, pDXContext, uaViewId, pUAViewEntry); + AssertContinue(RT_SUCCESS(rc)); + } + + LogFunc(("csuav[%d] sid = %u, uaid = %u\n", idxUA, sid, uaViewId)); + } + } + + /* Set views. */ + rc = dxSetCSUnorderedAccessViews(pThisCC, pDXContext); + AssertRC(rc); + + /* + * Render targets and unordered access views. + */ + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturnVoid(pDevice->pDevice); + + /* Make sure that the render target views exist. Similar to SRVs. */ + if (pDXContext->svgaDXContext.renderState.depthStencilViewId != SVGA3D_INVALID_ID) + { + uint32_t const viewId = pDXContext->svgaDXContext.renderState.depthStencilViewId; + + ASSERT_GUEST_RETURN_VOID(viewId < pDXContext->pBackendDXContext->cDepthStencilView); + + SVGACOTableDXDSViewEntry const *pDSViewEntry = dxGetDepthStencilViewEntry(pDXContext, viewId); + AssertReturnVoid(pDSViewEntry != NULL); + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pDSViewEntry->sid, &pSurface); + AssertRCReturnVoid(rc); + + /* If a view has not been created yet, do it now. */ + if (!pDXContext->pBackendDXContext->paDepthStencilView[viewId].u.pView) + { +//DEBUG_BREAKPOINT_TEST(); + LogFunc(("Re-creating DSV: sid=%u dsvid = %u\n", pDSViewEntry->sid, viewId)); + rc = dxDefineDepthStencilView(pThisCC, pDXContext, viewId, pDSViewEntry); + AssertReturnVoid(RT_SUCCESS(rc)); + } + + LogFunc(("dsv sid = %u, dsvid = %u\n", pDSViewEntry->sid, viewId)); + } + + for (uint32_t i = 0; i < SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS; ++i) + { + if (pDXContext->svgaDXContext.renderState.renderTargetViewIds[i] != SVGA3D_INVALID_ID) + { + uint32_t const viewId = pDXContext->svgaDXContext.renderState.renderTargetViewIds[i]; + + ASSERT_GUEST_RETURN_VOID(viewId < pDXContext->pBackendDXContext->cRenderTargetView); + + SVGACOTableDXRTViewEntry const *pRTViewEntry = dxGetRenderTargetViewEntry(pDXContext, viewId); + AssertReturnVoid(pRTViewEntry != NULL); + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pRTViewEntry->sid, &pSurface); + AssertRCReturnVoid(rc); + + /* If a view has not been created yet, do it now. */ + if (!pDXContext->pBackendDXContext->paRenderTargetView[viewId].u.pView) + { +//DEBUG_BREAKPOINT_TEST(); + LogFunc(("Re-creating RTV: sid=%u rtvid = %u\n", pRTViewEntry->sid, viewId)); + rc = dxDefineRenderTargetView(pThisCC, pDXContext, viewId, pRTViewEntry); + AssertReturnVoid(RT_SUCCESS(rc)); + } + + LogFunc(("rtv sid = %u, rtvid = %u, format = %s(%d)\n", pRTViewEntry->sid, viewId, vmsvgaLookupEnum((int)pRTViewEntry->format, &g_SVGA3dSurfaceFormat2String), pRTViewEntry->format)); + } + } + + for (uint32_t idxUA = 0; idxUA < SVGA3D_DX11_1_MAX_UAVIEWS; ++idxUA) + { + SVGA3dUAViewId const uaViewId = pDXContext->svgaDXContext.uaViewIds[idxUA]; + if (uaViewId != SVGA3D_INVALID_ID) + { +//DEBUG_BREAKPOINT_TEST(); + ASSERT_GUEST_RETURN_VOID(uaViewId < pDXContext->pBackendDXContext->cUnorderedAccessView); + + SVGACOTableDXUAViewEntry const *pUAViewEntry = dxGetUnorderedAccessViewEntry(pDXContext, uaViewId); + AssertContinue(pUAViewEntry != NULL); + + uint32_t const sid = pUAViewEntry->sid; + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + AssertRCReturnVoid(rc); + + /* The guest might have invalidated the surface in which case pSurface->pBackendSurface is NULL. */ + /** @todo This is not needed for "single DX device" mode. */ + if (pSurface->pBackendSurface) + { + /* Wait for the surface to finish drawing. */ + dxSurfaceWait(pThisCC->svga.p3dState, pSurface, pDXContext->cid); + } + + /* If a view has not been created yet, do it now. */ + if (!pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId].u.pView) + { + LogFunc(("Re-creating UAV: sid=%u uaid = %u\n", sid, uaViewId)); + rc = dxDefineUnorderedAccessView(pThisCC, pDXContext, uaViewId, pUAViewEntry); + AssertContinue(RT_SUCCESS(rc)); + } + + LogFunc(("uav[%d] sid = %u, uaid = %u\n", idxUA, sid, uaViewId)); + } + } + + /* Set render targets. */ + rc = dxSetRenderTargets(pThisCC, pDXContext); + AssertRC(rc); + + /* + * Shaders + */ + + for (uint32_t idxShaderState = 0; idxShaderState < SVGA3D_NUM_SHADERTYPE; ++idxShaderState) + { + DXSHADER *pDXShader; + SVGA3dShaderType const shaderType = (SVGA3dShaderType)(idxShaderState + SVGA3D_SHADERTYPE_MIN); + SVGA3dShaderId const shaderId = pDXContext->svgaDXContext.shaderState[idxShaderState].shaderId; + + if (shaderId != SVGA3D_INVALID_ID) + { + pDXShader = &pDXContext->pBackendDXContext->paShader[shaderId]; + if (pDXShader->pShader == NULL) + { + /* Create a new shader. */ + + /* Apply resource types to a pixel shader. */ + if (shaderType == SVGA3D_SHADERTYPE_PS) /* Others too? */ + { + VGPU10_RESOURCE_DIMENSION aResourceDimension[SVGA3D_DX_MAX_SRVIEWS]; + RT_ZERO(aResourceDimension); + VGPU10_RESOURCE_RETURN_TYPE aResourceReturnType[SVGA3D_DX_MAX_SRVIEWS]; + RT_ZERO(aResourceReturnType); + uint32_t cResources = 0; + + for (uint32_t idxSR = 0; idxSR < SVGA3D_DX_MAX_SRVIEWS; ++idxSR) + { + SVGA3dShaderResourceViewId const shaderResourceViewId = pDXContext->svgaDXContext.shaderState[idxShaderState].shaderResources[idxSR]; + if (shaderResourceViewId != SVGA3D_INVALID_ID) + { + SVGACOTableDXSRViewEntry const *pSRViewEntry = dxGetShaderResourceViewEntry(pDXContext, shaderResourceViewId); + AssertContinue(pSRViewEntry != NULL); + + PVMSVGA3DSURFACE pSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pSRViewEntry->sid, &pSurface); + AssertRCReturnVoid(rc); + + aResourceReturnType[idxSR] = DXShaderResourceReturnTypeFromFormat(pSRViewEntry->format); + + switch (pSRViewEntry->resourceDimension) + { + case SVGA3D_RESOURCE_BUFFEREX: + case SVGA3D_RESOURCE_BUFFER: + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_BUFFER; + break; + case SVGA3D_RESOURCE_TEXTURE1D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE1D; + else + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE1DARRAY; + break; + case SVGA3D_RESOURCE_TEXTURE2D: + if (pSurface->surfaceDesc.numArrayElements <= 1) + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE2D; + else + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE2DARRAY; + break; + case SVGA3D_RESOURCE_TEXTURE3D: + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE3D; + break; + case SVGA3D_RESOURCE_TEXTURECUBE: + if (pSurface->surfaceDesc.numArrayElements <= 6) + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURECUBE; + else + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURECUBEARRAY; + break; + default: + ASSERT_GUEST_FAILED(); + aResourceDimension[idxSR] = VGPU10_RESOURCE_DIMENSION_TEXTURE2D; + } + + cResources = idxSR + 1; + + /* Update componentType of the pixel shader output signature to correspond to the bound resources. */ + if (idxSR < pDXShader->shaderInfo.cOutputSignature) + { + SVGA3dDXSignatureEntry *pSignatureEntry = &pDXShader->shaderInfo.aOutputSignature[idxSR]; + pSignatureEntry->componentType = DXShaderComponentTypeFromFormat(pSRViewEntry->format); + } + } + } + + rc = DXShaderUpdateResources(&pDXShader->shaderInfo, aResourceDimension, aResourceReturnType, cResources); + AssertRC(rc); /* Ignore rc because the shader will most likely work anyway. */ + } + + if (shaderType == SVGA3D_SHADERTYPE_VS) + { + /* Update componentType of the vertex shader input signature to correspond to the input declaration. */ + vboxDXUpdateVSInputSignature(pDXContext, pDXShader); + } + + vboxDXMatchShaderSignatures(pThisCC, pDXContext, pDXShader); + + rc = DXShaderCreateDXBC(&pDXShader->shaderInfo, &pDXShader->pvDXBC, &pDXShader->cbDXBC); + if (RT_SUCCESS(rc)) + { +#ifdef LOG_ENABLED + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + if (pBackend->pfnD3DDisassemble && LogIs6Enabled()) + { + ID3D10Blob *pBlob = 0; + HRESULT hr2 = pBackend->pfnD3DDisassemble(pDXShader->pvDXBC, pDXShader->cbDXBC, 0, NULL, &pBlob); + if (SUCCEEDED(hr2) && pBlob && pBlob->GetBufferSize()) + Log6(("%s\n", pBlob->GetBufferPointer())); + else + AssertFailed(); + D3D_RELEASE(pBlob); + } + LogFunc(("Shader: set cid=%u shid=%u type=%d, GuestSignatures %d\n", pDXContext->cid, shaderId, pDXShader->enmShaderType, pDXShader->shaderInfo.fGuestSignatures)); +#endif + + HRESULT hr = dxShaderCreate(pThisCC, pDXContext, pDXShader); + if (FAILED(hr)) + rc = VERR_INVALID_STATE; + } + } + + LogFunc(("Shader: cid=%u shid=%u type=%d, GuestSignatures %d, %Rrc\n", pDXContext->cid, shaderId, pDXShader->enmShaderType, pDXShader->shaderInfo.fGuestSignatures, rc)); + } + else + pDXShader = NULL; + + if (RT_SUCCESS(rc)) + dxShaderSet(pThisCC, pDXContext, shaderType, pDXShader); + + AssertRC(rc); + } + + /* + * InputLayout + */ + SVGA3dElementLayoutId const elementLayoutId = pDXContext->svgaDXContext.inputAssembly.layoutId; + ID3D11InputLayout *pInputLayout = NULL; + if (elementLayoutId != SVGA3D_INVALID_ID) + { + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + if (!pDXElementLayout->pElementLayout) + { + uint32_t const idxShaderState = SVGA3D_SHADERTYPE_VS - SVGA3D_SHADERTYPE_MIN; + uint32_t const shid = pDXContext->svgaDXContext.shaderState[idxShaderState].shaderId; + if (shid < pDXContext->pBackendDXContext->cShader) + { + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[shid]; + if (pDXShader->pvDXBC) + dxCreateInputLayout(pThisCC, pDXContext, elementLayoutId, pDXShader); + else + LogRelMax(16, ("VMSVGA: DX shader bytecode is not available in DXSetInputLayout: shid = %u\n", shid)); + } + else + LogRelMax(16, ("VMSVGA: DX shader is not set in DXSetInputLayout: shid = 0x%x\n", shid)); + } + + pInputLayout = pDXElementLayout->pElementLayout; + + LogFunc(("Input layout id %u\n", elementLayoutId)); + } + + pDevice->pImmediateContext->IASetInputLayout(pInputLayout); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDraw(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t vertexCount, uint32_t startVertexLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + +#ifdef LOG_ENABLED + if (LogIs8Enabled()) + dxDbgDumpVertices_Draw(pThisCC, pDXContext, vertexCount, startVertexLocation); +#endif + + if (pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN) + pDevice->pImmediateContext->Draw(vertexCount, startVertexLocation); + else + { + /* + * Emulate SVGA3D_PRIMITIVE_TRIANGLEFAN using an indexed draw of a triangle list. + */ + + /* Make sure that 16 bit indices are enough. */ + if (vertexCount > 65535) + { + LogRelMax(1, ("VMSVGA: ignore Draw(TRIANGLEFAN, %u)\n", vertexCount)); + return VERR_NOT_SUPPORTED; + } + + /* Generate indices. */ + UINT const IndexCount = 3 * (vertexCount - 2); /* 3_per_triangle * num_triangles */ + UINT const cbAlloc = IndexCount * sizeof(USHORT); + USHORT *paIndices = (USHORT *)RTMemAlloc(cbAlloc); + AssertReturn(paIndices, VERR_NO_MEMORY); + USHORT iVertex = 1; + for (UINT i = 0; i < IndexCount; i+= 3) + { + paIndices[i] = 0; + paIndices[i + 1] = iVertex; + ++iVertex; + paIndices[i + 2] = iVertex; + } + + D3D11_SUBRESOURCE_DATA InitData; + InitData.pSysMem = paIndices; + InitData.SysMemPitch = cbAlloc; + InitData.SysMemSlicePitch = cbAlloc; + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = cbAlloc; + bd.Usage = D3D11_USAGE_IMMUTABLE; + bd.BindFlags = D3D11_BIND_INDEX_BUFFER; + //bd.CPUAccessFlags = 0; + //bd.MiscFlags = 0; + //bd.StructureByteStride = 0; + + ID3D11Buffer *pIndexBuffer = 0; + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer); + Assert(SUCCEEDED(hr));RT_NOREF(hr); + + /* Save the current index buffer. */ + ID3D11Buffer *pSavedIndexBuffer = 0; + DXGI_FORMAT SavedFormat = DXGI_FORMAT_UNKNOWN; + UINT SavedOffset = 0; + pDevice->pImmediateContext->IAGetIndexBuffer(&pSavedIndexBuffer, &SavedFormat, &SavedOffset); + + /* Set up the device state. */ + pDevice->pImmediateContext->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R16_UINT, 0); + pDevice->pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + UINT const StartIndexLocation = 0; + INT const BaseVertexLocation = startVertexLocation; + pDevice->pImmediateContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + + /* Restore the device state. */ + pDevice->pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + pDevice->pImmediateContext->IASetIndexBuffer(pSavedIndexBuffer, SavedFormat, SavedOffset); + D3D_RELEASE(pSavedIndexBuffer); + + /* Cleanup. */ + D3D_RELEASE(pIndexBuffer); + RTMemFree(paIndices); + } + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + +static int dxReadBuffer(DXDEVICE *pDevice, ID3D11Buffer *pBuffer, UINT Offset, UINT Bytes, void **ppvData, uint32_t *pcbData) +{ + D3D11_BUFFER_DESC desc; + RT_ZERO(desc); + pBuffer->GetDesc(&desc); + + AssertReturn( Offset < desc.ByteWidth + && Bytes <= desc.ByteWidth - Offset, VERR_INVALID_STATE); + + void *pvData = RTMemAlloc(Bytes); + if (!pvData) + return VERR_NO_MEMORY; + + *ppvData = pvData; + *pcbData = Bytes; + +#ifdef DX_COMMON_STAGING_BUFFER + int rc = dxStagingBufferRealloc(pDevice, Bytes); + if (RT_SUCCESS(rc)) + { + /* Copy 'Bytes' bytes starting at 'Offset' from the buffer to the start of staging buffer. */ + ID3D11Resource *pDstResource = pDevice->pStagingBuffer; + UINT DstSubresource = 0; + UINT DstX = 0; + UINT DstY = 0; + UINT DstZ = 0; + ID3D11Resource *pSrcResource = pBuffer; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + SrcBox.left = Offset; + SrcBox.top = 0; + SrcBox.front = 0; + SrcBox.right = Offset + Bytes; + SrcBox.bottom = 1; + SrcBox.back = 1; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + UINT const Subresource = 0; /* Buffers have only one subresource. */ + HRESULT hr = pDevice->pImmediateContext->Map(pDevice->pStagingBuffer, Subresource, + D3D11_MAP_READ, /* MapFlags = */ 0, &mappedResource); + if (SUCCEEDED(hr)) + { + memcpy(pvData, mappedResource.pData, Bytes); + + /* Unmap the staging buffer. */ + pDevice->pImmediateContext->Unmap(pDevice->pStagingBuffer, Subresource); + } + else + AssertFailedStmt(rc = VERR_NOT_SUPPORTED); + + } +#else + uint32_t const cbAlloc = Bytes; + + D3D11_SUBRESOURCE_DATA *pInitialData = NULL; + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = Bytes; + bd.Usage = D3D11_USAGE_STAGING; + //bd.BindFlags = 0; /* No bind flags are allowed for staging resources. */ + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; + + int rc = VINF_SUCCESS; + ID3D11Buffer *pStagingBuffer; + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, pInitialData, &pStagingBuffer); + if (SUCCEEDED(hr)) + { + /* Copy from the buffer to the staging buffer. */ + ID3D11Resource *pDstResource = pStagingBuffer; + UINT DstSubresource = 0; + UINT DstX = 0; + UINT DstY = 0; + UINT DstZ = 0; + ID3D11Resource *pSrcResource = pBuffer; + UINT SrcSubresource = 0; + D3D11_BOX SrcBox; + SrcBox.left = Offset; + SrcBox.top = 0; + SrcBox.front = 0; + SrcBox.right = Offset + Bytes; + SrcBox.bottom = 1; + SrcBox.back = 1; + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + UINT const Subresource = 0; /* Buffers have only one subresource. */ + hr = pDevice->pImmediateContext->Map(pStagingBuffer, Subresource, + D3D11_MAP_READ, /* MapFlags = */ 0, &mappedResource); + if (SUCCEEDED(hr)) + { + memcpy(pvData, mappedResource.pData, Bytes); + + /* Unmap the staging buffer. */ + pDevice->pImmediateContext->Unmap(pStagingBuffer, Subresource); + } + else + AssertFailedStmt(rc = VERR_NOT_SUPPORTED); + + D3D_RELEASE(pStagingBuffer); + } + else + { + rc = VERR_NO_MEMORY; + } +#endif + + if (RT_FAILURE(rc)) + { + RTMemFree(*ppvData); + *ppvData = NULL; + *pcbData = 0; + } + + return rc; +} + + +static int dxDrawIndexedTriangleFan(DXDEVICE *pDevice, uint32_t IndexCountTF, uint32_t StartIndexLocationTF, int32_t BaseVertexLocationTF) +{ + /* + * Emulate an indexed SVGA3D_PRIMITIVE_TRIANGLEFAN using an indexed draw of triangle list. + */ + + /* Make sure that 16 bit indices are enough. */ + if (IndexCountTF > 65535) + { + LogRelMax(1, ("VMSVGA: ignore DrawIndexed(TRIANGLEFAN, %u)\n", IndexCountTF)); + return VERR_NOT_SUPPORTED; + } + + /* Save the current index buffer. */ + ID3D11Buffer *pSavedIndexBuffer = 0; + DXGI_FORMAT SavedFormat = DXGI_FORMAT_UNKNOWN; + UINT SavedOffset = 0; + pDevice->pImmediateContext->IAGetIndexBuffer(&pSavedIndexBuffer, &SavedFormat, &SavedOffset); + + AssertReturn( SavedFormat == DXGI_FORMAT_R16_UINT + || SavedFormat == DXGI_FORMAT_R32_UINT, VERR_NOT_SUPPORTED); + + /* How many bytes are used by triangle fan indices. */ + UINT const BytesPerIndexTF = SavedFormat == DXGI_FORMAT_R16_UINT ? 2 : 4; + UINT const BytesTF = BytesPerIndexTF * IndexCountTF; + + /* Read the current index buffer content to obtain indices. */ + void *pvDataTF; + uint32_t cbDataTF; + int rc = dxReadBuffer(pDevice, pSavedIndexBuffer, StartIndexLocationTF, BytesTF, &pvDataTF, &cbDataTF); + AssertRCReturn(rc, rc); + AssertReturnStmt(cbDataTF >= BytesPerIndexTF, RTMemFree(pvDataTF), VERR_INVALID_STATE); + + /* Generate indices for triangle list. */ + UINT const IndexCount = 3 * (IndexCountTF - 2); /* 3_per_triangle * num_triangles */ + UINT const cbAlloc = IndexCount * sizeof(USHORT); + USHORT *paIndices = (USHORT *)RTMemAlloc(cbAlloc); + AssertReturnStmt(paIndices, RTMemFree(pvDataTF), VERR_NO_MEMORY); + + USHORT iVertex = 1; + if (BytesPerIndexTF == 2) + { + USHORT *paIndicesTF = (USHORT *)pvDataTF; + for (UINT i = 0; i < IndexCount; i+= 3) + { + paIndices[i] = paIndicesTF[0]; + AssertBreakStmt(iVertex < IndexCountTF, rc = VERR_INVALID_STATE); + paIndices[i + 1] = paIndicesTF[iVertex]; + ++iVertex; + AssertBreakStmt(iVertex < IndexCountTF, rc = VERR_INVALID_STATE); + paIndices[i + 2] = paIndicesTF[iVertex]; + } + } + else + { + UINT *paIndicesTF = (UINT *)pvDataTF; + for (UINT i = 0; i < IndexCount; i+= 3) + { + paIndices[i] = paIndicesTF[0]; + AssertBreakStmt(iVertex < IndexCountTF, rc = VERR_INVALID_STATE); + paIndices[i + 1] = paIndicesTF[iVertex]; + ++iVertex; + AssertBreakStmt(iVertex < IndexCountTF, rc = VERR_INVALID_STATE); + paIndices[i + 2] = paIndicesTF[iVertex]; + } + } + + D3D11_SUBRESOURCE_DATA InitData; + InitData.pSysMem = paIndices; + InitData.SysMemPitch = cbAlloc; + InitData.SysMemSlicePitch = cbAlloc; + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = cbAlloc; + bd.Usage = D3D11_USAGE_IMMUTABLE; + bd.BindFlags = D3D11_BIND_INDEX_BUFFER; + //bd.CPUAccessFlags = 0; + //bd.MiscFlags = 0; + //bd.StructureByteStride = 0; + + ID3D11Buffer *pIndexBuffer = 0; + HRESULT hr = pDevice->pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer); + Assert(SUCCEEDED(hr));RT_NOREF(hr); + + /* Set up the device state. */ + pDevice->pImmediateContext->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R16_UINT, 0); + pDevice->pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + UINT const StartIndexLocation = 0; + INT const BaseVertexLocation = BaseVertexLocationTF; + pDevice->pImmediateContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + + /* Restore the device state. */ + pDevice->pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + pDevice->pImmediateContext->IASetIndexBuffer(pSavedIndexBuffer, SavedFormat, SavedOffset); + D3D_RELEASE(pSavedIndexBuffer); + + /* Cleanup. */ + D3D_RELEASE(pIndexBuffer); + RTMemFree(paIndices); + RTMemFree(pvDataTF); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawIndexed(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t indexCount, uint32_t startIndexLocation, int32_t baseVertexLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + +#ifdef LOG_ENABLED + if (LogIs8Enabled()) + dxDbgDumpVertices_DrawIndexed(pThisCC, pDXContext, indexCount, startIndexLocation, baseVertexLocation); +#endif + + if (pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN) + pDevice->pImmediateContext->DrawIndexed(indexCount, startIndexLocation, baseVertexLocation); + else + { + dxDrawIndexedTriangleFan(pDevice, indexCount, startIndexLocation, baseVertexLocation); + } + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawInstanced(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + +#ifdef LOG_ENABLED + if (LogIs8Enabled()) + dxDbgDumpVertices_DrawInstanced(pThisCC, pDXContext, vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation); +#endif + + Assert(pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN); + + pDevice->pImmediateContext->DrawInstanced(vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation); + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawIndexedInstanced(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + +#ifdef LOG_ENABLED + if (LogIs8Enabled()) + dxDbgDumpVertices_DrawIndexedInstanced(pThisCC, pDXContext, indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); +#endif + + Assert(pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN); + + pDevice->pImmediateContext->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawAuto(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + + Assert(pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN); + + pDevice->pImmediateContext->DrawAuto(); + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetInputLayout(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dElementLayoutId elementLayoutId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(elementLayoutId); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetVertexBuffers(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t startBuffer, uint32_t cVertexBuffer, SVGA3dVertexBuffer const *paVertexBuffer) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + for (uint32_t i = 0; i < cVertexBuffer; ++i) + { + uint32_t const idxVertexBuffer = startBuffer + i; + + /* Get corresponding resource. Create the buffer if does not yet exist. */ + if (paVertexBuffer[i].sid != SVGA_ID_INVALID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, paVertexBuffer[i].sid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource and initialize it with the current surface data. */ + rc = vmsvga3dBackSurfaceCreateBuffer(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + Assert(pSurface->pBackendSurface->u.pBuffer); + + DXBOUNDVERTEXBUFFER *pBoundBuffer = &pDXContext->pBackendDXContext->resources.inputAssembly.vertexBuffers[idxVertexBuffer]; + if ( pBoundBuffer->pBuffer != pSurface->pBackendSurface->u.pBuffer + || pBoundBuffer->stride != paVertexBuffer[i].stride + || pBoundBuffer->offset != paVertexBuffer[i].offset) + { + LogFunc(("vertex buffer: [%u]: sid = %u, offset %u, stride %u (%p -> %p)\n", + idxVertexBuffer, paVertexBuffer[i].sid, paVertexBuffer[i].offset, paVertexBuffer[i].stride, pBoundBuffer->pBuffer, pSurface->pBackendSurface->u.pBuffer)); + + if (pBoundBuffer->pBuffer != pSurface->pBackendSurface->u.pBuffer) + { + D3D_RELEASE(pBoundBuffer->pBuffer); + pBoundBuffer->pBuffer = pSurface->pBackendSurface->u.pBuffer; + pBoundBuffer->pBuffer->AddRef(); + } + pBoundBuffer->stride = paVertexBuffer[i].stride; + pBoundBuffer->offset = paVertexBuffer[i].offset; + } + } + else + { + DXBOUNDVERTEXBUFFER *pBoundBuffer = &pDXContext->pBackendDXContext->resources.inputAssembly.vertexBuffers[idxVertexBuffer]; + D3D_RELEASE(pBoundBuffer->pBuffer); + pBoundBuffer->stride = 0; + pBoundBuffer->offset = 0; + } + } + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetIndexBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceId sid, SVGA3dSurfaceFormat format, uint32_t offset) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Get corresponding resource. Create the buffer if does not yet exist. */ + if (sid != SVGA_ID_INVALID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource and initialize it with the current surface data. */ + rc = vmsvga3dBackSurfaceCreateBuffer(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + DXGI_FORMAT const enmDxgiFormat = vmsvgaDXSurfaceFormat2Dxgi(format); + AssertReturn(enmDxgiFormat == DXGI_FORMAT_R16_UINT || enmDxgiFormat == DXGI_FORMAT_R32_UINT, VERR_INVALID_PARAMETER); + + DXBOUNDINDEXBUFFER *pBoundBuffer = &pDXContext->pBackendDXContext->resources.inputAssembly.indexBuffer; + if ( pBoundBuffer->pBuffer != pSurface->pBackendSurface->u.pBuffer + || pBoundBuffer->indexBufferOffset != offset + || pBoundBuffer->indexBufferFormat != enmDxgiFormat) + { + LogFunc(("index_buffer: sid = %u, offset %u, (%p -> %p)\n", + sid, offset, pBoundBuffer->pBuffer, pSurface->pBackendSurface->u.pBuffer)); + + if (pBoundBuffer->pBuffer != pSurface->pBackendSurface->u.pBuffer) + { + D3D_RELEASE(pBoundBuffer->pBuffer); + pBoundBuffer->pBuffer = pSurface->pBackendSurface->u.pBuffer; + pBoundBuffer->pBuffer->AddRef(); + } + pBoundBuffer->indexBufferOffset = offset; + pBoundBuffer->indexBufferFormat = enmDxgiFormat; + } + } + else + { + DXBOUNDINDEXBUFFER *pBoundBuffer = &pDXContext->pBackendDXContext->resources.inputAssembly.indexBuffer; + D3D_RELEASE(pBoundBuffer->pBuffer); + pBoundBuffer->indexBufferOffset = 0; + pBoundBuffer->indexBufferFormat = DXGI_FORMAT_UNKNOWN; + } + + return VINF_SUCCESS; +} + +static D3D11_PRIMITIVE_TOPOLOGY dxTopology(SVGA3dPrimitiveType primitiveType) +{ + static D3D11_PRIMITIVE_TOPOLOGY const aD3D11PrimitiveTopology[SVGA3D_PRIMITIVE_MAX] = + { + D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, + D3D11_PRIMITIVE_TOPOLOGY_LINELIST, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, /* SVGA3D_PRIMITIVE_TRIANGLEFAN: No FAN in D3D11. */ + D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST, + D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST, + }; + return aD3D11PrimitiveTopology[primitiveType]; +} + +static DECLCALLBACK(int) vmsvga3dBackDXSetTopology(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dPrimitiveType topology) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + D3D11_PRIMITIVE_TOPOLOGY const enmTopology = dxTopology(topology); + pDevice->pImmediateContext->IASetPrimitiveTopology(enmTopology); + return VINF_SUCCESS; +} + + +static int dxSetRenderTargets(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + UINT UAVStartSlot = 0; + UINT NumUAVs = 0; + ID3D11UnorderedAccessView *apUnorderedAccessViews[SVGA3D_DX11_1_MAX_UAVIEWS]; + UINT aUAVInitialCounts[SVGA3D_DX11_1_MAX_UAVIEWS]; + for (uint32_t idxUA = 0; idxUA < SVGA3D_DX11_1_MAX_UAVIEWS; ++idxUA) + { + SVGA3dUAViewId const uaViewId = pDXContext->svgaDXContext.uaViewIds[idxUA]; + if (uaViewId != SVGA3D_INVALID_ID) + { + if (NumUAVs == 0) + UAVStartSlot = idxUA; + NumUAVs = idxUA - UAVStartSlot + 1; + apUnorderedAccessViews[idxUA] = pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId].u.pUnorderedAccessView; + + SVGACOTableDXUAViewEntry const *pEntry = dxGetUnorderedAccessViewEntry(pDXContext, uaViewId); + aUAVInitialCounts[idxUA] = pEntry->structureCount; + } + else + { + apUnorderedAccessViews[idxUA] = NULL; + aUAVInitialCounts[idxUA] = (UINT)-1; + } + } + + UINT NumRTVs = 0; + ID3D11RenderTargetView *apRenderTargetViews[SVGA3D_MAX_RENDER_TARGETS]; + RT_ZERO(apRenderTargetViews); + for (uint32_t i = 0; i < pDXContext->cRenderTargets; ++i) + { + SVGA3dRenderTargetViewId const renderTargetViewId = pDXContext->svgaDXContext.renderState.renderTargetViewIds[i]; + if (renderTargetViewId != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN(renderTargetViewId < pDXContext->pBackendDXContext->cRenderTargetView, VERR_INVALID_PARAMETER); + apRenderTargetViews[i] = pDXContext->pBackendDXContext->paRenderTargetView[renderTargetViewId].u.pRenderTargetView; + ++NumRTVs; + } + } + + /* RTVs are followed by UAVs. */ + Assert(NumUAVs == 0 || NumRTVs <= pDXContext->svgaDXContext.uavSpliceIndex); + + ID3D11DepthStencilView *pDepthStencilView = NULL; + SVGA3dDepthStencilViewId const depthStencilViewId = pDXContext->svgaDXContext.renderState.depthStencilViewId; + if (depthStencilViewId != SVGA_ID_INVALID) + pDepthStencilView = pDXContext->pBackendDXContext->paDepthStencilView[depthStencilViewId].u.pDepthStencilView; + + pDevice->pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(NumRTVs, + apRenderTargetViews, + pDepthStencilView, + pDXContext->svgaDXContext.uavSpliceIndex, + NumUAVs, + apUnorderedAccessViews, + aUAVInitialCounts); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetRenderTargets(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilViewId depthStencilViewId, uint32_t cRenderTargetViewId, SVGA3dRenderTargetViewId const *paRenderTargetViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(depthStencilViewId, cRenderTargetViewId, paRenderTargetViewId); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetBlendState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dBlendStateId blendId, float const blendFactor[4], uint32_t sampleMask) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + if (blendId != SVGA3D_INVALID_ID) + { + ID3D11BlendState1 *pBlendState = pDXContext->pBackendDXContext->papBlendState[blendId]; + pDevice->pImmediateContext->OMSetBlendState(pBlendState, blendFactor, sampleMask); + } + else + pDevice->pImmediateContext->OMSetBlendState(NULL, NULL, 0); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetDepthStencilState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilStateId depthStencilId, uint32_t stencilRef) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + if (depthStencilId != SVGA3D_INVALID_ID) + { + ID3D11DepthStencilState *pDepthStencilState = pDXContext->pBackendDXContext->papDepthStencilState[depthStencilId]; + pDevice->pImmediateContext->OMSetDepthStencilState(pDepthStencilState, stencilRef); + } + else + pDevice->pImmediateContext->OMSetDepthStencilState(NULL, 0); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetRasterizerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRasterizerStateId rasterizerId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(pBackend); + + if (rasterizerId != SVGA3D_INVALID_ID) + { + ID3D11RasterizerState1 *pRasterizerState = pDXContext->pBackendDXContext->papRasterizerState[rasterizerId]; + pDevice->pImmediateContext->RSSetState(pRasterizerState); + } + else + pDevice->pImmediateContext->RSSetState(NULL); + + return VINF_SUCCESS; +} + + +typedef struct VGPU10QUERYINFO +{ + SVGA3dQueryType svgaQueryType; + uint32_t cbDataVMSVGA; + D3D11_QUERY dxQueryType; + uint32_t cbDataD3D11; +} VGPU10QUERYINFO; + +static VGPU10QUERYINFO const *dxQueryInfo(SVGA3dQueryType type) +{ + static VGPU10QUERYINFO const aQueryInfo[SVGA3D_QUERYTYPE_MAX] = + { + { SVGA3D_QUERYTYPE_OCCLUSION, sizeof(SVGADXOcclusionQueryResult), + D3D11_QUERY_OCCLUSION, sizeof(UINT64) }, + { SVGA3D_QUERYTYPE_TIMESTAMP, sizeof(SVGADXTimestampQueryResult), + D3D11_QUERY_TIMESTAMP, sizeof(UINT64) }, + { SVGA3D_QUERYTYPE_TIMESTAMPDISJOINT, sizeof(SVGADXTimestampDisjointQueryResult), + D3D11_QUERY_TIMESTAMP_DISJOINT, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT) }, + { SVGA3D_QUERYTYPE_PIPELINESTATS, sizeof(SVGADXPipelineStatisticsQueryResult), + D3D11_QUERY_PIPELINE_STATISTICS, sizeof(D3D11_QUERY_DATA_PIPELINE_STATISTICS) }, + { SVGA3D_QUERYTYPE_OCCLUSIONPREDICATE, sizeof(SVGADXOcclusionPredicateQueryResult), + D3D11_QUERY_OCCLUSION_PREDICATE, sizeof(BOOL) }, + { SVGA3D_QUERYTYPE_STREAMOUTPUTSTATS, sizeof(SVGADXStreamOutStatisticsQueryResult), + D3D11_QUERY_SO_STATISTICS, sizeof(D3D11_QUERY_DATA_SO_STATISTICS) }, + { SVGA3D_QUERYTYPE_STREAMOVERFLOWPREDICATE, sizeof(SVGADXStreamOutPredicateQueryResult), + D3D11_QUERY_SO_OVERFLOW_PREDICATE, sizeof(BOOL) }, + { SVGA3D_QUERYTYPE_OCCLUSION64, sizeof(SVGADXOcclusion64QueryResult), + D3D11_QUERY_OCCLUSION, sizeof(UINT64) }, + { SVGA3D_QUERYTYPE_SOSTATS_STREAM0, sizeof(SVGADXStreamOutStatisticsQueryResult), + D3D11_QUERY_SO_STATISTICS_STREAM0, sizeof(D3D11_QUERY_DATA_SO_STATISTICS) }, + { SVGA3D_QUERYTYPE_SOSTATS_STREAM1, sizeof(SVGADXStreamOutStatisticsQueryResult), + D3D11_QUERY_SO_STATISTICS_STREAM1, sizeof(D3D11_QUERY_DATA_SO_STATISTICS) }, + { SVGA3D_QUERYTYPE_SOSTATS_STREAM2, sizeof(SVGADXStreamOutStatisticsQueryResult), + D3D11_QUERY_SO_STATISTICS_STREAM2, sizeof(D3D11_QUERY_DATA_SO_STATISTICS) }, + { SVGA3D_QUERYTYPE_SOSTATS_STREAM3, sizeof(SVGADXStreamOutStatisticsQueryResult), + D3D11_QUERY_SO_STATISTICS_STREAM3, sizeof(D3D11_QUERY_DATA_SO_STATISTICS) }, + { SVGA3D_QUERYTYPE_SOP_STREAM0, sizeof(SVGADXStreamOutPredicateQueryResult), + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0, sizeof(BOOL) }, + { SVGA3D_QUERYTYPE_SOP_STREAM1, sizeof(SVGADXStreamOutPredicateQueryResult), + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1, sizeof(BOOL) }, + { SVGA3D_QUERYTYPE_SOP_STREAM2, sizeof(SVGADXStreamOutPredicateQueryResult), + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2, sizeof(BOOL) }, + { SVGA3D_QUERYTYPE_SOP_STREAM3, sizeof(SVGADXStreamOutPredicateQueryResult), + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3, sizeof(BOOL) }, + }; + + ASSERT_GUEST_RETURN(type < RT_ELEMENTS(aQueryInfo), NULL); + return &aQueryInfo[type]; +} + +static int dxDefineQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, SVGACOTableDXQueryEntry const *pEntry) +{ + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + VGPU10QUERYINFO const *pQueryInfo = dxQueryInfo((SVGA3dQueryType)pEntry->type); + if (!pQueryInfo) + return VERR_INVALID_PARAMETER; + + D3D11_QUERY_DESC desc; + desc.Query = pQueryInfo->dxQueryType; + desc.MiscFlags = 0; + if (pEntry->flags & SVGA3D_DXQUERY_FLAG_PREDICATEHINT) + desc.MiscFlags |= (UINT)D3D11_QUERY_MISC_PREDICATEHINT; + + HRESULT hr = pDXDevice->pDevice->CreateQuery(&desc, &pDXQuery->pQuery); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + return VINF_SUCCESS; +} + + +static int dxDestroyQuery(DXQUERY *pDXQuery) +{ + D3D_RELEASE(pDXQuery->pQuery); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, SVGACOTableDXQueryEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineQuery(pThisCC, pDXContext, queryId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + dxDestroyQuery(pDXQuery); + + return VINF_SUCCESS; +} + + +/** @todo queryId makes pDXQuery redundant */ +static int dxBeginQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, DXQUERY *pDXQuery) +{ + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + /* Begin is disabled for some queries. */ + SVGACOTableDXQueryEntry *pEntry = &pDXContext->cot.paQuery[queryId]; + if (pEntry->type == SVGA3D_QUERYTYPE_TIMESTAMP) + return VINF_SUCCESS; + + pDXDevice->pImmediateContext->Begin(pDXQuery->pQuery); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBeginQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + int rc = dxBeginQuery(pThisCC, pDXContext, queryId, pDXQuery); + return rc; +} + + +static int dxGetQueryResult(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, + SVGADXQueryResultUnion *pQueryResult, uint32_t *pcbOut) +{ + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + typedef union _DXQUERYRESULT + { + UINT64 occlusion; + UINT64 timestamp; + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timestampDisjoint; + D3D11_QUERY_DATA_PIPELINE_STATISTICS pipelineStatistics; + BOOL occlusionPredicate; + D3D11_QUERY_DATA_SO_STATISTICS soStatistics; + BOOL soOverflowPredicate; + } DXQUERYRESULT; + + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + SVGACOTableDXQueryEntry *pEntry = &pDXContext->cot.paQuery[queryId]; + VGPU10QUERYINFO const *pQueryInfo = dxQueryInfo((SVGA3dQueryType)pEntry->type); + if (!pQueryInfo) + return VERR_INVALID_PARAMETER; + + DXQUERYRESULT dxQueryResult; + while (pDXDevice->pImmediateContext->GetData(pDXQuery->pQuery, &dxQueryResult, pQueryInfo->cbDataD3D11, 0) != S_OK) + { + RTThreadYield(); + } + + /* Copy back the result. */ + switch (pEntry->type) + { + case SVGA3D_QUERYTYPE_OCCLUSION: + pQueryResult->occ.samplesRendered = (uint32_t)dxQueryResult.occlusion; + break; + case SVGA3D_QUERYTYPE_TIMESTAMP: + pQueryResult->ts.timestamp = dxQueryResult.timestamp; + break; + case SVGA3D_QUERYTYPE_TIMESTAMPDISJOINT: + pQueryResult->tsDisjoint.realFrequency = dxQueryResult.timestampDisjoint.Frequency; + pQueryResult->tsDisjoint.disjoint = dxQueryResult.timestampDisjoint.Disjoint; + break; + case SVGA3D_QUERYTYPE_PIPELINESTATS: + pQueryResult->pipelineStats.inputAssemblyVertices = dxQueryResult.pipelineStatistics.IAVertices; + pQueryResult->pipelineStats.inputAssemblyPrimitives = dxQueryResult.pipelineStatistics.IAPrimitives; + pQueryResult->pipelineStats.vertexShaderInvocations = dxQueryResult.pipelineStatistics.VSInvocations; + pQueryResult->pipelineStats.geometryShaderInvocations = dxQueryResult.pipelineStatistics.GSInvocations; + pQueryResult->pipelineStats.geometryShaderPrimitives = dxQueryResult.pipelineStatistics.GSPrimitives; + pQueryResult->pipelineStats.clipperInvocations = dxQueryResult.pipelineStatistics.CInvocations; + pQueryResult->pipelineStats.clipperPrimitives = dxQueryResult.pipelineStatistics.CPrimitives; + pQueryResult->pipelineStats.pixelShaderInvocations = dxQueryResult.pipelineStatistics.PSInvocations; + pQueryResult->pipelineStats.hullShaderInvocations = dxQueryResult.pipelineStatistics.HSInvocations; + pQueryResult->pipelineStats.domainShaderInvocations = dxQueryResult.pipelineStatistics.DSInvocations; + pQueryResult->pipelineStats.computeShaderInvocations = dxQueryResult.pipelineStatistics.CSInvocations; + break; + case SVGA3D_QUERYTYPE_OCCLUSIONPREDICATE: + pQueryResult->occPred.anySamplesRendered = dxQueryResult.occlusionPredicate; + break; + case SVGA3D_QUERYTYPE_STREAMOUTPUTSTATS: + case SVGA3D_QUERYTYPE_SOSTATS_STREAM0: + case SVGA3D_QUERYTYPE_SOSTATS_STREAM1: + case SVGA3D_QUERYTYPE_SOSTATS_STREAM2: + case SVGA3D_QUERYTYPE_SOSTATS_STREAM3: + pQueryResult->soStats.numPrimitivesWritten = dxQueryResult.soStatistics.NumPrimitivesWritten; + pQueryResult->soStats.numPrimitivesRequired = dxQueryResult.soStatistics.PrimitivesStorageNeeded; + break; + case SVGA3D_QUERYTYPE_STREAMOVERFLOWPREDICATE: + case SVGA3D_QUERYTYPE_SOP_STREAM0: + case SVGA3D_QUERYTYPE_SOP_STREAM1: + case SVGA3D_QUERYTYPE_SOP_STREAM2: + case SVGA3D_QUERYTYPE_SOP_STREAM3: + pQueryResult->soPred.overflowed = dxQueryResult.soOverflowPredicate; + break; + case SVGA3D_QUERYTYPE_OCCLUSION64: + pQueryResult->occ64.samplesRendered = dxQueryResult.occlusion; + break; + } + + *pcbOut = pQueryInfo->cbDataVMSVGA; + return VINF_SUCCESS; +} + +static int dxEndQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, + SVGADXQueryResultUnion *pQueryResult, uint32_t *pcbOut) +{ + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + pDXDevice->pImmediateContext->End(pDXQuery->pQuery); + + /** @todo Consider issuing QueryEnd and getting data later in FIFO thread loop. */ + return dxGetQueryResult(pThisCC, pDXContext, queryId, pQueryResult, pcbOut); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXEndQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + SVGA3dQueryId queryId, SVGADXQueryResultUnion *pQueryResult, uint32_t *pcbOut) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + int rc = dxEndQuery(pThisCC, pDXContext, queryId, pQueryResult, pcbOut); + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetPredication(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dQueryId queryId, uint32_t predicateValue) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDXDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDXDevice->pDevice, VERR_INVALID_STATE); + + if (queryId != SVGA3D_INVALID_ID) + { + DEBUG_BREAKPOINT_TEST(); + DXQUERY *pDXQuery = &pDXContext->pBackendDXContext->paQuery[queryId]; + SVGACOTableDXQueryEntry *pEntry = &pDXContext->cot.paQuery[queryId]; + + VGPU10QUERYINFO const *pQueryInfo = dxQueryInfo((SVGA3dQueryType)pEntry->type); + if (!pQueryInfo) + return VERR_INVALID_PARAMETER; + + D3D_RELEASE(pDXQuery->pQuery); + + D3D11_QUERY_DESC desc; + desc.Query = pQueryInfo->dxQueryType; + desc.MiscFlags = 0; + if (pEntry->flags & SVGA3D_DXQUERY_FLAG_PREDICATEHINT) + desc.MiscFlags |= (UINT)D3D11_QUERY_MISC_PREDICATEHINT; + + HRESULT hr = pDXDevice->pDevice->CreatePredicate(&desc, &pDXQuery->pPredicate); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + pDXDevice->pImmediateContext->SetPredication(pDXQuery->pPredicate, RT_BOOL(predicateValue)); + } + else + pDXDevice->pImmediateContext->SetPredication(NULL, FALSE); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetSOTargets(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t cSOTarget, SVGA3dSoTarget const *paSoTarget) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* For each paSoTarget[i]: + * If the stream outout buffer object does not exist then create it. + * If the surface has been updated by the guest then update the buffer object. + * Use SOSetTargets to set the buffers. + */ + + ID3D11Buffer *paResource[SVGA3D_DX_MAX_SOTARGETS]; + UINT paOffset[SVGA3D_DX_MAX_SOTARGETS]; + + /* Always re-bind all 4 SO targets. They can be NULL. */ + for (uint32_t i = 0; i < SVGA3D_DX_MAX_SOTARGETS; ++i) + { + /* Get corresponding resource. Create the buffer if does not yet exist. */ + if (i < cSOTarget && paSoTarget[i].sid != SVGA_ID_INVALID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, paSoTarget[i].sid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + rc = vmsvga3dBackSurfaceCreateSoBuffer(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + /** @todo How paSoTarget[i].sizeInBytes is used? Maybe when the buffer is created? */ + paResource[i] = pSurface->pBackendSurface->u.pBuffer; + paOffset[i] = paSoTarget[i].offset; + } + else + { + paResource[i] = NULL; + paOffset[i] = 0; + } + } + + pDevice->pImmediateContext->SOSetTargets(SVGA3D_DX_MAX_SOTARGETS, paResource, paOffset); + + pDXContext->pBackendDXContext->cSOTarget = cSOTarget; + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetViewports(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t cViewport, SVGA3dViewport const *paViewport) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(pBackend); + + /* D3D11_VIEWPORT is identical to SVGA3dViewport. */ + D3D11_VIEWPORT *pViewports = (D3D11_VIEWPORT *)paViewport; + + pDevice->pImmediateContext->RSSetViewports(cViewport, pViewports); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetScissorRects(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t cRect, SVGASignedRect const *paRect) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* D3D11_RECT is identical to SVGASignedRect. */ + D3D11_RECT *pRects = (D3D11_RECT *)paRect; + + pDevice->pImmediateContext->RSSetScissorRects(cRect, pRects); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXClearRenderTargetView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId, SVGA3dRGBAFloat const *pRGBA) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paRenderTargetView[renderTargetViewId]; + if (!pDXView->u.pRenderTargetView) + { +//DEBUG_BREAKPOINT_TEST(); + /* (Re-)create the render target view, because a creation of a view is deferred until a draw or a clear call. */ + SVGACOTableDXRTViewEntry const *pEntry = &pDXContext->cot.paRTView[renderTargetViewId]; + int rc = dxDefineRenderTargetView(pThisCC, pDXContext, renderTargetViewId, pEntry); + AssertRCReturn(rc, rc); + } + pDevice->pImmediateContext->ClearRenderTargetView(pDXView->u.pRenderTargetView, pRGBA->value); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackVBDXClearRenderTargetViewRegion(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId, + SVGA3dRGBAFloat const *pColor, uint32_t cRect, SVGASignedRect const *paRect) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paRenderTargetView[renderTargetViewId]; + if (!pDXView->u.pRenderTargetView) + { + /* (Re-)create the render target view, because a creation of a view is deferred until a draw or a clear call. */ + SVGACOTableDXRTViewEntry const *pEntry = &pDXContext->cot.paRTView[renderTargetViewId]; + int rc = dxDefineRenderTargetView(pThisCC, pDXContext, renderTargetViewId, pEntry); + AssertRCReturn(rc, rc); + } + pDevice->pImmediateContext->ClearView(pDXView->u.pRenderTargetView, pColor->value, (D3D11_RECT *)paRect, cRect); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXClearDepthStencilView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t flags, SVGA3dDepthStencilViewId depthStencilViewId, float depth, uint8_t stencil) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paDepthStencilView[depthStencilViewId]; + if (!pDXView->u.pDepthStencilView) + { +//DEBUG_BREAKPOINT_TEST(); + /* (Re-)create the depth stencil view, because a creation of a view is deferred until a draw or a clear call. */ + SVGACOTableDXDSViewEntry const *pEntry = &pDXContext->cot.paDSView[depthStencilViewId]; + int rc = dxDefineDepthStencilView(pThisCC, pDXContext, depthStencilViewId, pEntry); + AssertRCReturn(rc, rc); + } + pDevice->pImmediateContext->ClearDepthStencilView(pDXView->u.pDepthStencilView, flags, depth, stencil); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPredCopyRegion(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceId dstSid, uint32_t dstSubResource, SVGA3dSurfaceId srcSid, uint32_t srcSubResource, SVGA3dCopyBox const *pBox) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSrcSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, srcSid, &pSrcSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DSURFACE pDstSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, dstSid, &pDstSurface); + AssertRCReturn(rc, rc); + + if (pSrcSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSrcSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSrcSurface); + AssertRCReturn(rc, rc); + } + + if (pDstSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pDstSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pDstSurface); + AssertRCReturn(rc, rc); + } + + LogFunc(("cid %d: src cid %d%s -> dst cid %d%s\n", + pDXContext->cid, pSrcSurface->idAssociatedContext, + (pSrcSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "", + pDstSurface->idAssociatedContext, + (pDstSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "")); + + /* Clip the box. */ + /** @todo Use [src|dst]SubResource to index p[Src|Dst]Surface->paMipmapLevels array directly. */ + uint32_t iSrcFace; + uint32_t iSrcMipmap; + vmsvga3dCalcMipmapAndFace(pSrcSurface->cLevels, srcSubResource, &iSrcMipmap, &iSrcFace); + + uint32_t iDstFace; + uint32_t iDstMipmap; + vmsvga3dCalcMipmapAndFace(pDstSurface->cLevels, dstSubResource, &iDstMipmap, &iDstFace); + + PVMSVGA3DMIPMAPLEVEL pSrcMipLevel; + rc = vmsvga3dMipmapLevel(pSrcSurface, iSrcFace, iSrcMipmap, &pSrcMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + PVMSVGA3DMIPMAPLEVEL pDstMipLevel; + rc = vmsvga3dMipmapLevel(pDstSurface, iDstFace, iDstMipmap, &pDstMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + SVGA3dCopyBox clipBox = *pBox; + vmsvgaR3ClipCopyBox(&pSrcMipLevel->mipmapSize, &pDstMipLevel->mipmapSize, &clipBox); + + UINT DstSubresource = dstSubResource; + UINT DstX = clipBox.x; + UINT DstY = clipBox.y; + UINT DstZ = clipBox.z; + + UINT SrcSubresource = srcSubResource; + D3D11_BOX SrcBox; + SrcBox.left = clipBox.srcx; + SrcBox.top = clipBox.srcy; + SrcBox.front = clipBox.srcz; + SrcBox.right = clipBox.srcx + clipBox.w; + SrcBox.bottom = clipBox.srcy + clipBox.h; + SrcBox.back = clipBox.srcz + clipBox.d; + + ID3D11Resource *pDstResource; + ID3D11Resource *pSrcResource; + + pDstResource = dxResource(pThisCC->svga.p3dState, pDstSurface, pDXContext); + pSrcResource = dxResource(pThisCC->svga.p3dState, pSrcSurface, pDXContext); + + pDevice->pImmediateContext->CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox); + +#ifdef DUMP_BITMAPS + SVGA3dSurfaceImageId image; + image.sid = pDstSurface->id; + image.face = 0; + image.mipmap = 0; + VMSVGA3D_MAPPED_SURFACE map; + int rc2 = vmsvga3dSurfaceMap(pThisCC, &image, NULL, VMSVGA3D_SURFACE_MAP_READ, &map); + if (RT_SUCCESS(rc2)) + { + vmsvga3dMapWriteBmpFile(&map, "copyregion-"); + vmsvga3dSurfaceUnmap(pThisCC, &image, &map, /* fWritten = */ false); + } + else + Log(("Map failed %Rrc\n", rc)); +#endif + + pDstSurface->pBackendSurface->cidDrawing = pDXContext->cid; + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPredCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceId dstSid, SVGA3dSurfaceId srcSid) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSrcSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, srcSid, &pSrcSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DSURFACE pDstSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, dstSid, &pDstSurface); + AssertRCReturn(rc, rc); + + if (pSrcSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSrcSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSrcSurface); + AssertRCReturn(rc, rc); + } + + if (pDstSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pDstSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pDstSurface); + AssertRCReturn(rc, rc); + } + + LogFunc(("cid %d: src cid %d%s -> dst cid %d%s\n", + pDXContext->cid, pSrcSurface->idAssociatedContext, + (pSrcSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "", + pDstSurface->idAssociatedContext, + (pDstSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "")); + + ID3D11Resource *pDstResource = dxResource(pThisCC->svga.p3dState, pDstSurface, pDXContext); + ID3D11Resource *pSrcResource = dxResource(pThisCC->svga.p3dState, pSrcSurface, pDXContext); + + pDevice->pImmediateContext->CopyResource(pDstResource, pSrcResource); + + pDstSurface->pBackendSurface->cidDrawing = pDXContext->cid; + return VINF_SUCCESS; +} + + +#include "shaders/d3d11blitter.hlsl.vs.h" +#include "shaders/d3d11blitter.hlsl.ps.h" + +#define HTEST(stmt) \ + hr = stmt; \ + AssertReturn(SUCCEEDED(hr), hr) + + +static void BlitRelease(D3D11BLITTER *pBlitter) +{ + D3D_RELEASE(pBlitter->pVertexShader); + D3D_RELEASE(pBlitter->pPixelShader); + D3D_RELEASE(pBlitter->pSamplerState); + D3D_RELEASE(pBlitter->pRasterizerState); + D3D_RELEASE(pBlitter->pBlendState); + RT_ZERO(*pBlitter); +} + + +static HRESULT BlitInit(D3D11BLITTER *pBlitter, ID3D11Device1 *pDevice, ID3D11DeviceContext1 *pImmediateContext) +{ + HRESULT hr; + + RT_ZERO(*pBlitter); + + pBlitter->pDevice = pDevice; + pBlitter->pImmediateContext = pImmediateContext; + + HTEST(pBlitter->pDevice->CreateVertexShader(g_vs_blitter, sizeof(g_vs_blitter), NULL, &pBlitter->pVertexShader)); + HTEST(pBlitter->pDevice->CreatePixelShader(g_ps_blitter, sizeof(g_ps_blitter), NULL, &pBlitter->pPixelShader)); + + D3D11_SAMPLER_DESC SamplerDesc; + SamplerDesc.Filter = D3D11_FILTER_ANISOTROPIC; + SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + SamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + SamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + SamplerDesc.MipLODBias = 0.0f; + SamplerDesc.MaxAnisotropy = 4; + SamplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + SamplerDesc.BorderColor[0] = 0.0f; + SamplerDesc.BorderColor[1] = 0.0f; + SamplerDesc.BorderColor[2] = 0.0f; + SamplerDesc.BorderColor[3] = 0.0f; + SamplerDesc.MinLOD = 0.0f; + SamplerDesc.MaxLOD = 0.0f; + HTEST(pBlitter->pDevice->CreateSamplerState(&SamplerDesc, &pBlitter->pSamplerState)); + + D3D11_RASTERIZER_DESC1 RasterizerDesc; + RasterizerDesc.FillMode = D3D11_FILL_SOLID; + RasterizerDesc.CullMode = D3D11_CULL_NONE; + RasterizerDesc.FrontCounterClockwise = FALSE; + RasterizerDesc.DepthBias = 0; + RasterizerDesc.DepthBiasClamp = 0.0f; + RasterizerDesc.SlopeScaledDepthBias = 0.0f; + RasterizerDesc.DepthClipEnable = FALSE; + RasterizerDesc.ScissorEnable = FALSE; + RasterizerDesc.MultisampleEnable = FALSE; + RasterizerDesc.AntialiasedLineEnable = FALSE; + RasterizerDesc.ForcedSampleCount = 0; + HTEST(pBlitter->pDevice->CreateRasterizerState1(&RasterizerDesc, &pBlitter->pRasterizerState)); + + D3D11_BLEND_DESC1 BlendDesc; + BlendDesc.AlphaToCoverageEnable = FALSE; + BlendDesc.IndependentBlendEnable = FALSE; + for (unsigned i = 0; i < RT_ELEMENTS(BlendDesc.RenderTarget); ++i) + { + BlendDesc.RenderTarget[i].BlendEnable = FALSE; + BlendDesc.RenderTarget[i].LogicOpEnable = FALSE; + BlendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_COLOR; + BlendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ZERO; + BlendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + BlendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + BlendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO; + BlendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + BlendDesc.RenderTarget[i].LogicOp = D3D11_LOGIC_OP_CLEAR; + BlendDesc.RenderTarget[i].RenderTargetWriteMask = 0xF; + } + HTEST(pBlitter->pDevice->CreateBlendState1(&BlendDesc, &pBlitter->pBlendState)); + + return S_OK; +} + + +static HRESULT BlitFromTexture(D3D11BLITTER *pBlitter, ID3D11RenderTargetView *pDstRenderTargetView, + float cDstWidth, float cDstHeight, D3D11_RECT const &rectDst, + ID3D11ShaderResourceView *pSrcShaderResourceView) +{ + HRESULT hr; + + /* + * Save pipeline state. + */ + struct + { + D3D11_PRIMITIVE_TOPOLOGY Topology; + ID3D11InputLayout *pInputLayout; + ID3D11Buffer *pConstantBuffer; + ID3D11VertexShader *pVertexShader; + ID3D11HullShader *pHullShader; + ID3D11DomainShader *pDomainShader; + ID3D11GeometryShader *pGeometryShader; + ID3D11ShaderResourceView *pShaderResourceView; + ID3D11PixelShader *pPixelShader; + ID3D11SamplerState *pSamplerState; + ID3D11RasterizerState *pRasterizerState; + ID3D11BlendState *pBlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + ID3D11RenderTargetView *apRenderTargetView[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + ID3D11DepthStencilView *pDepthStencilView; + UINT NumViewports; + D3D11_VIEWPORT aViewport[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + } SavedState; + + pBlitter->pImmediateContext->IAGetPrimitiveTopology(&SavedState.Topology); + pBlitter->pImmediateContext->IAGetInputLayout(&SavedState.pInputLayout); + pBlitter->pImmediateContext->VSGetConstantBuffers(0, 1, &SavedState.pConstantBuffer); + pBlitter->pImmediateContext->VSGetShader(&SavedState.pVertexShader, NULL, NULL); + pBlitter->pImmediateContext->HSGetShader(&SavedState.pHullShader, NULL, NULL); + pBlitter->pImmediateContext->DSGetShader(&SavedState.pDomainShader, NULL, NULL); + pBlitter->pImmediateContext->GSGetShader(&SavedState.pGeometryShader, NULL, NULL); + pBlitter->pImmediateContext->PSGetShaderResources(0, 1, &SavedState.pShaderResourceView); + pBlitter->pImmediateContext->PSGetShader(&SavedState.pPixelShader, NULL, NULL); + pBlitter->pImmediateContext->PSGetSamplers(0, 1, &SavedState.pSamplerState); + pBlitter->pImmediateContext->RSGetState(&SavedState.pRasterizerState); + pBlitter->pImmediateContext->OMGetBlendState(&SavedState.pBlendState, SavedState.BlendFactor, &SavedState.SampleMask); + pBlitter->pImmediateContext->OMGetRenderTargets(RT_ELEMENTS(SavedState.apRenderTargetView), SavedState.apRenderTargetView, &SavedState.pDepthStencilView); + SavedState.NumViewports = RT_ELEMENTS(SavedState.aViewport); + pBlitter->pImmediateContext->RSGetViewports(&SavedState.NumViewports, &SavedState.aViewport[0]); + + /* + * Setup pipeline for the blitter. + */ + + /* Render target is first. + * If the source texture is bound as a render target, then this call will unbind it + * and allow to use it as the shader resource. + */ + pBlitter->pImmediateContext->OMSetRenderTargets(1, &pDstRenderTargetView, NULL); + + /* Input assembler. */ + pBlitter->pImmediateContext->IASetInputLayout(NULL); + pBlitter->pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + /* Constant buffer. */ + struct + { + float scaleX; + float scaleY; + float offsetX; + float offsetY; + } VSConstantBuffer; + VSConstantBuffer.scaleX = (float)(rectDst.right - rectDst.left) / cDstWidth; + VSConstantBuffer.scaleY = (float)(rectDst.bottom - rectDst.top) / cDstHeight; + VSConstantBuffer.offsetX = (float)(rectDst.right + rectDst.left) / cDstWidth - 1.0f; + VSConstantBuffer.offsetY = -((float)(rectDst.bottom + rectDst.top) / cDstHeight - 1.0f); + + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = &VSConstantBuffer; + initialData.SysMemPitch = sizeof(VSConstantBuffer); + initialData.SysMemSlicePitch = sizeof(VSConstantBuffer); + + D3D11_BUFFER_DESC bd; + RT_ZERO(bd); + bd.ByteWidth = sizeof(VSConstantBuffer); + bd.Usage = D3D11_USAGE_IMMUTABLE; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + ID3D11Buffer *pConstantBuffer; + HTEST(pBlitter->pDevice->CreateBuffer(&bd, &initialData, &pConstantBuffer)); + pBlitter->pImmediateContext->VSSetConstantBuffers(0, 1, &pConstantBuffer); + D3D_RELEASE(pConstantBuffer); /* xSSetConstantBuffers "will hold a reference to the interfaces passed in." */ + + /* Vertex shader. */ + pBlitter->pImmediateContext->VSSetShader(pBlitter->pVertexShader, NULL, 0); + + /* Unused shaders. */ + pBlitter->pImmediateContext->HSSetShader(NULL, NULL, 0); + pBlitter->pImmediateContext->DSSetShader(NULL, NULL, 0); + pBlitter->pImmediateContext->GSSetShader(NULL, NULL, 0); + + /* Shader resource view. */ + pBlitter->pImmediateContext->PSSetShaderResources(0, 1, &pSrcShaderResourceView); + + /* Pixel shader. */ + pBlitter->pImmediateContext->PSSetShader(pBlitter->pPixelShader, NULL, 0); + + /* Sampler. */ + pBlitter->pImmediateContext->PSSetSamplers(0, 1, &pBlitter->pSamplerState); + + /* Rasterizer. */ + pBlitter->pImmediateContext->RSSetState(pBlitter->pRasterizerState); + + /* Blend state. */ + static FLOAT const BlendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + pBlitter->pImmediateContext->OMSetBlendState(pBlitter->pBlendState, BlendFactor, 0xffffffff); + + /* Viewport. */ + D3D11_VIEWPORT Viewport; + Viewport.TopLeftX = 0; + Viewport.TopLeftY = 0; + Viewport.Width = cDstWidth; + Viewport.Height = cDstHeight; + Viewport.MinDepth = 0.0f; + Viewport.MaxDepth = 1.0f; + pBlitter->pImmediateContext->RSSetViewports(1, &Viewport); + + /* Draw. */ + pBlitter->pImmediateContext->Draw(4, 0); + + /* + * Restore pipeline state. + */ + pBlitter->pImmediateContext->IASetPrimitiveTopology(SavedState.Topology); + pBlitter->pImmediateContext->IASetInputLayout(SavedState.pInputLayout); + D3D_RELEASE(SavedState.pInputLayout); + pBlitter->pImmediateContext->VSSetConstantBuffers(0, 1, &SavedState.pConstantBuffer); + D3D_RELEASE(SavedState.pConstantBuffer); + pBlitter->pImmediateContext->VSSetShader(SavedState.pVertexShader, NULL, 0); + D3D_RELEASE(SavedState.pVertexShader); + + pBlitter->pImmediateContext->HSSetShader(SavedState.pHullShader, NULL, 0); + D3D_RELEASE(SavedState.pHullShader); + pBlitter->pImmediateContext->DSSetShader(SavedState.pDomainShader, NULL, 0); + D3D_RELEASE(SavedState.pDomainShader); + pBlitter->pImmediateContext->GSSetShader(SavedState.pGeometryShader, NULL, 0); + D3D_RELEASE(SavedState.pGeometryShader); + + pBlitter->pImmediateContext->PSSetShaderResources(0, 1, &SavedState.pShaderResourceView); + D3D_RELEASE(SavedState.pShaderResourceView); + pBlitter->pImmediateContext->PSSetShader(SavedState.pPixelShader, NULL, 0); + D3D_RELEASE(SavedState.pPixelShader); + pBlitter->pImmediateContext->PSSetSamplers(0, 1, &SavedState.pSamplerState); + D3D_RELEASE(SavedState.pSamplerState); + pBlitter->pImmediateContext->RSSetState(SavedState.pRasterizerState); + D3D_RELEASE(SavedState.pRasterizerState); + pBlitter->pImmediateContext->OMSetBlendState(SavedState.pBlendState, SavedState.BlendFactor, SavedState.SampleMask); + D3D_RELEASE(SavedState.pBlendState); + pBlitter->pImmediateContext->OMSetRenderTargets(RT_ELEMENTS(SavedState.apRenderTargetView), SavedState.apRenderTargetView, SavedState.pDepthStencilView); + D3D_RELEASE_ARRAY(RT_ELEMENTS(SavedState.apRenderTargetView), SavedState.apRenderTargetView); + D3D_RELEASE(SavedState.pDepthStencilView); + pBlitter->pImmediateContext->RSSetViewports(SavedState.NumViewports, &SavedState.aViewport[0]); + + return S_OK; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPresentBlt(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + SVGA3dSurfaceId dstSid, uint32_t dstSubResource, SVGA3dBox const *pBoxDst, + SVGA3dSurfaceId srcSid, uint32_t srcSubResource, SVGA3dBox const *pBoxSrc, + SVGA3dDXPresentBltMode mode) +{ + RT_NOREF(mode); + + ASSERT_GUEST_RETURN(pBoxDst->z == 0 && pBoxDst->d == 1, VERR_INVALID_PARAMETER); + ASSERT_GUEST_RETURN(pBoxSrc->z == 0 && pBoxSrc->d == 1, VERR_INVALID_PARAMETER); + + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + PVMSVGA3DSURFACE pSrcSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, srcSid, &pSrcSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DSURFACE pDstSurface; + rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, dstSid, &pDstSurface); + AssertRCReturn(rc, rc); + + if (pSrcSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSrcSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSrcSurface); + AssertRCReturn(rc, rc); + } + + if (pDstSurface->pBackendSurface == NULL) + { + /* Create the resource. */ + if (pSrcSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pDstSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pDstSurface); + AssertRCReturn(rc, rc); + } + + LogFunc(("cid %d: src cid %d%s -> dst cid %d%s\n", + pDXContext->cid, pSrcSurface->idAssociatedContext, + (pSrcSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "", + pDstSurface->idAssociatedContext, + (pDstSurface->f.surfaceFlags & SVGA3D_SURFACE_SCREENTARGET) ? " st" : "")); + + /* Clip the box. */ + /** @todo Use [src|dst]SubResource to index p[Src|Dst]Surface->paMipmapLevels array directly. */ + uint32_t iSrcFace; + uint32_t iSrcMipmap; + vmsvga3dCalcMipmapAndFace(pSrcSurface->cLevels, srcSubResource, &iSrcMipmap, &iSrcFace); + + uint32_t iDstFace; + uint32_t iDstMipmap; + vmsvga3dCalcMipmapAndFace(pDstSurface->cLevels, dstSubResource, &iDstMipmap, &iDstFace); + + PVMSVGA3DMIPMAPLEVEL pSrcMipLevel; + rc = vmsvga3dMipmapLevel(pSrcSurface, iSrcFace, iSrcMipmap, &pSrcMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + PVMSVGA3DMIPMAPLEVEL pDstMipLevel; + rc = vmsvga3dMipmapLevel(pDstSurface, iDstFace, iDstMipmap, &pDstMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + SVGA3dBox clipBoxSrc = *pBoxSrc; + vmsvgaR3ClipBox(&pSrcMipLevel->mipmapSize, &clipBoxSrc); + + SVGA3dBox clipBoxDst = *pBoxDst; + vmsvgaR3ClipBox(&pDstMipLevel->mipmapSize, &clipBoxDst); + + ID3D11Resource *pDstResource = dxResource(pThisCC->svga.p3dState, pDstSurface, pDXContext); + ID3D11Resource *pSrcResource = dxResource(pThisCC->svga.p3dState, pSrcSurface, pDXContext); + + D3D11_RENDER_TARGET_VIEW_DESC RTVDesc; + RT_ZERO(RTVDesc); + RTVDesc.Format = vmsvgaDXSurfaceFormat2Dxgi(pDstSurface->format);; + RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + RTVDesc.Texture2D.MipSlice = dstSubResource; + + ID3D11RenderTargetView *pDstRenderTargetView; + HRESULT hr = pDevice->pDevice->CreateRenderTargetView(pDstResource, &RTVDesc, &pDstRenderTargetView); + AssertReturn(SUCCEEDED(hr), VERR_NOT_SUPPORTED); + + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + RT_ZERO(SRVDesc); + SRVDesc.Format = vmsvgaDXSurfaceFormat2Dxgi(pSrcSurface->format); + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Texture2D.MostDetailedMip = srcSubResource; + SRVDesc.Texture2D.MipLevels = 1; + + ID3D11ShaderResourceView *pSrcShaderResourceView; + hr = pDevice->pDevice->CreateShaderResourceView(pSrcResource, &SRVDesc, &pSrcShaderResourceView); + AssertReturnStmt(SUCCEEDED(hr), D3D_RELEASE(pDstRenderTargetView), VERR_NOT_SUPPORTED); + + D3D11_RECT rectDst; + rectDst.left = pBoxDst->x; + rectDst.top = pBoxDst->y; + rectDst.right = pBoxDst->x + pBoxDst->w; + rectDst.bottom = pBoxDst->y + pBoxDst->h; + + BlitFromTexture(&pDevice->Blitter, pDstRenderTargetView, (float)pDstMipLevel->mipmapSize.width, (float)pDstMipLevel->mipmapSize.height, + rectDst, pSrcShaderResourceView); + + D3D_RELEASE(pSrcShaderResourceView); + D3D_RELEASE(pDstRenderTargetView); + + pDstSurface->pBackendSurface->cidDrawing = pDXContext->cid; + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXGenMips(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderResourceViewId shaderResourceViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + ID3D11ShaderResourceView *pShaderResourceView = pDXContext->pBackendDXContext->paShaderResourceView[shaderResourceViewId].u.pShaderResourceView; + AssertReturn(pShaderResourceView, VERR_INVALID_STATE); + + SVGACOTableDXSRViewEntry const *pSRViewEntry = dxGetShaderResourceViewEntry(pDXContext, shaderResourceViewId); + AssertReturn(pSRViewEntry, VERR_INVALID_STATE); + + uint32_t const sid = pSRViewEntry->sid; + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, sid, &pSurface); + AssertRCReturn(rc, rc); + AssertReturn(pSurface->pBackendSurface, VERR_INVALID_STATE); + + pDevice->pImmediateContext->GenerateMips(pShaderResourceView); + + pSurface->pBackendSurface->cidDrawing = pDXContext->cid; + return VINF_SUCCESS; +} + + +static int dxDefineShaderResourceView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderResourceViewId shaderResourceViewId, SVGACOTableDXSRViewEntry const *pEntry) +{ + /* Get corresponding resource for pEntry->sid. Create the surface if does not yet exist. */ + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pEntry->sid, &pSurface); + AssertRCReturn(rc, rc); + + ID3D11ShaderResourceView *pShaderResourceView; + DXVIEW *pView = &pDXContext->pBackendDXContext->paShaderResourceView[shaderResourceViewId]; + Assert(pView->u.pView == NULL); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the actual texture or buffer. */ + /** @todo One function to create all resources from surfaces. */ + if (pSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSurface); + + AssertRCReturn(rc, rc); + } + + HRESULT hr = dxShaderResourceViewCreate(pThisCC, pDXContext, pEntry, pSurface, &pShaderResourceView); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + return dxViewInit(pView, pSurface, pDXContext, shaderResourceViewId, VMSVGA3D_VIEWTYPE_SHADERRESOURCE, pShaderResourceView); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineShaderResourceView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderResourceViewId shaderResourceViewId, SVGACOTableDXSRViewEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /** @todo Probably not necessary because SRVs are defined in setupPipeline. */ + return dxDefineShaderResourceView(pThisCC, pDXContext, shaderResourceViewId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyShaderResourceView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderResourceViewId shaderResourceViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxViewDestroy(&pDXContext->pBackendDXContext->paShaderResourceView[shaderResourceViewId]); +} + + +static int dxDefineRenderTargetView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId, SVGACOTableDXRTViewEntry const *pEntry) +{ + /* Get corresponding resource for pEntry->sid. Create the surface if does not yet exist. */ + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pEntry->sid, &pSurface); + AssertRCReturn(rc, rc); + + DXVIEW *pView = &pDXContext->pBackendDXContext->paRenderTargetView[renderTargetViewId]; + Assert(pView->u.pView == NULL); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the actual texture. */ + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + ID3D11RenderTargetView *pRenderTargetView; + HRESULT hr = dxRenderTargetViewCreate(pThisCC, pDXContext, pEntry, pSurface, &pRenderTargetView); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + return dxViewInit(pView, pSurface, pDXContext, renderTargetViewId, VMSVGA3D_VIEWTYPE_RENDERTARGET, pRenderTargetView); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineRenderTargetView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId, SVGACOTableDXRTViewEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + return dxDefineRenderTargetView(pThisCC, pDXContext, renderTargetViewId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyRenderTargetView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRenderTargetViewId renderTargetViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxViewDestroy(&pDXContext->pBackendDXContext->paRenderTargetView[renderTargetViewId]); +} + + +static int dxDefineDepthStencilView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilViewId depthStencilViewId, SVGACOTableDXDSViewEntry const *pEntry) +{ + /* Get corresponding resource for pEntry->sid. Create the surface if does not yet exist. */ + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pEntry->sid, &pSurface); + AssertRCReturn(rc, rc); + + DXVIEW *pView = &pDXContext->pBackendDXContext->paDepthStencilView[depthStencilViewId]; + Assert(pView->u.pView == NULL); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the actual texture. */ + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + ID3D11DepthStencilView *pDepthStencilView; + HRESULT hr = dxDepthStencilViewCreate(pThisCC, pDXContext, pEntry, pSurface, &pDepthStencilView); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + return dxViewInit(pView, pSurface, pDXContext, depthStencilViewId, VMSVGA3D_VIEWTYPE_DEPTHSTENCIL, pDepthStencilView); +} + +static DECLCALLBACK(int) vmsvga3dBackDXDefineDepthStencilView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilViewId depthStencilViewId, SVGACOTableDXDSViewEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + return dxDefineDepthStencilView(pThisCC, pDXContext, depthStencilViewId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyDepthStencilView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilViewId depthStencilViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxViewDestroy(&pDXContext->pBackendDXContext->paDepthStencilView[depthStencilViewId]); +} + + +static int dxDefineElementLayout(PVMSVGA3DDXCONTEXT pDXContext, SVGA3dElementLayoutId elementLayoutId, SVGACOTableDXElementLayoutEntry const *pEntry) +{ + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + D3D_RELEASE(pDXElementLayout->pElementLayout); + pDXElementLayout->cElementDesc = 0; + RT_ZERO(pDXElementLayout->aElementDesc); + + RT_NOREF(pEntry); + + return VINF_SUCCESS; +} + + +static int dxDestroyElementLayout(DXELEMENTLAYOUT *pDXElementLayout) +{ + D3D_RELEASE(pDXElementLayout->pElementLayout); + pDXElementLayout->cElementDesc = 0; + RT_ZERO(pDXElementLayout->aElementDesc); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineElementLayout(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dElementLayoutId elementLayoutId, SVGACOTableDXElementLayoutEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(pBackend); + + /* Not much can be done here because ID3D11Device::CreateInputLayout requires + * a pShaderBytecodeWithInputSignature which is not known at this moment. + * InputLayout object will be created in setupPipeline. + */ + + Assert(elementLayoutId == pEntry->elid); + + return dxDefineElementLayout(pDXContext, elementLayoutId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyElementLayout(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dElementLayoutId elementLayoutId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXELEMENTLAYOUT *pDXElementLayout = &pDXContext->pBackendDXContext->paElementLayout[elementLayoutId]; + dxDestroyElementLayout(pDXElementLayout); + + return VINF_SUCCESS; +} + + +static int dxDefineBlendState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + SVGA3dBlendStateId blendId, SVGACOTableDXBlendStateEntry const *pEntry) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + HRESULT hr = dxBlendStateCreate(pDevice, pEntry, &pDXContext->pBackendDXContext->papBlendState[blendId]); + if (SUCCEEDED(hr)) + return VINF_SUCCESS; + return VERR_INVALID_STATE; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineBlendState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, + SVGA3dBlendStateId blendId, SVGACOTableDXBlendStateEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineBlendState(pThisCC, pDXContext, blendId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyBlendState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dBlendStateId blendId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + D3D_RELEASE(pDXContext->pBackendDXContext->papBlendState[blendId]); + return VINF_SUCCESS; +} + + +static int dxDefineDepthStencilState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilStateId depthStencilId, SVGACOTableDXDepthStencilEntry const *pEntry) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + HRESULT hr = dxDepthStencilStateCreate(pDevice, pEntry, &pDXContext->pBackendDXContext->papDepthStencilState[depthStencilId]); + if (SUCCEEDED(hr)) + return VINF_SUCCESS; + return VERR_INVALID_STATE; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineDepthStencilState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilStateId depthStencilId, SVGACOTableDXDepthStencilEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineDepthStencilState(pThisCC, pDXContext, depthStencilId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyDepthStencilState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dDepthStencilStateId depthStencilId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + D3D_RELEASE(pDXContext->pBackendDXContext->papDepthStencilState[depthStencilId]); + return VINF_SUCCESS; +} + + +static int dxDefineRasterizerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRasterizerStateId rasterizerId, SVGACOTableDXRasterizerStateEntry const *pEntry) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + HRESULT hr = dxRasterizerStateCreate(pDevice, pEntry, &pDXContext->pBackendDXContext->papRasterizerState[rasterizerId]); + if (SUCCEEDED(hr)) + return VINF_SUCCESS; + return VERR_INVALID_STATE; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineRasterizerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRasterizerStateId rasterizerId, SVGACOTableDXRasterizerStateEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineRasterizerState(pThisCC, pDXContext, rasterizerId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyRasterizerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dRasterizerStateId rasterizerId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + D3D_RELEASE(pDXContext->pBackendDXContext->papRasterizerState[rasterizerId]); + return VINF_SUCCESS; +} + + +static int dxDefineSamplerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSamplerId samplerId, SVGACOTableDXSamplerEntry const *pEntry) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + HRESULT hr = dxSamplerStateCreate(pDevice, pEntry, &pDXContext->pBackendDXContext->papSamplerState[samplerId]); + if (SUCCEEDED(hr)) + return VINF_SUCCESS; + return VERR_INVALID_STATE; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineSamplerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSamplerId samplerId, SVGACOTableDXSamplerEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineSamplerState(pThisCC, pDXContext, samplerId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroySamplerState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSamplerId samplerId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + D3D_RELEASE(pDXContext->pBackendDXContext->papSamplerState[samplerId]); + return VINF_SUCCESS; +} + + +static int dxDefineShader(PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderId shaderId, SVGACOTableDXShaderEntry const *pEntry) +{ + /** @todo A common approach for creation of COTable backend objects: runtime, empty DX COTable, live DX COTable. */ + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[shaderId]; + Assert(pDXShader->enmShaderType == SVGA3D_SHADERTYPE_INVALID); + + /* Init the backend shader structure, if the shader has not been created yet. */ + pDXShader->enmShaderType = pEntry->type; + pDXShader->pShader = NULL; + pDXShader->soid = SVGA_ID_INVALID; + + return VINF_SUCCESS; +} + + +static int dxDestroyShader(DXSHADER *pDXShader) +{ + pDXShader->enmShaderType = SVGA3D_SHADERTYPE_INVALID; + DXShaderFree(&pDXShader->shaderInfo); + D3D_RELEASE(pDXShader->pShader); + RTMemFree(pDXShader->pvDXBC); + pDXShader->pvDXBC = NULL; + pDXShader->cbDXBC = 0; + pDXShader->soid = SVGA_ID_INVALID; + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderId shaderId, SVGACOTableDXShaderEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxDefineShader(pDXContext, shaderId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderId shaderId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[shaderId]; + dxDestroyShader(pDXShader); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBindShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dShaderId shaderId, DXShaderInfo const *pShaderInfo) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(pBackend); + + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[shaderId]; + if (pDXShader->pvDXBC) + { + /* New DXBC code and new shader must be created. */ + D3D_RELEASE(pDXShader->pShader); + RTMemFree(pDXShader->pvDXBC); + pDXShader->pvDXBC = NULL; + pDXShader->cbDXBC = 0; + } + + pDXShader->shaderInfo = *pShaderInfo; + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineStreamOutput(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dStreamOutputId soid, SVGACOTableDXStreamOutputEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[soid]; + dxDestroyStreamOutput(pDXStreamOutput); + + RT_NOREF(pEntry); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyStreamOutput(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dStreamOutputId soid) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[soid]; + dxDestroyStreamOutput(pDXStreamOutput); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetStreamOutput(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dStreamOutputId soid) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend, pDXContext, soid); + + return VINF_SUCCESS; +} + + +static int dxCOTableRealloc(void **ppvCOTable, uint32_t *pcCOTable, uint32_t cbEntry, uint32_t cEntries, uint32_t cValidEntries) +{ + uint32_t const cCOTableCurrent = *pcCOTable; + + if (*pcCOTable != cEntries) + { + /* Grow/shrink the array. */ + if (cEntries) + { + void *pvNew = RTMemRealloc(*ppvCOTable, cEntries * cbEntry); + AssertReturn(pvNew, VERR_NO_MEMORY); + *ppvCOTable = pvNew; + } + else + { + RTMemFree(*ppvCOTable); + *ppvCOTable = NULL; + } + + *pcCOTable = cEntries; + } + + if (*ppvCOTable) + { + uint32_t const cEntriesToKeep = RT_MIN(cCOTableCurrent, cValidEntries); + memset((uint8_t *)(*ppvCOTable) + cEntriesToKeep * cbEntry, 0, (cEntries - cEntriesToKeep) * cbEntry); + } + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vmsvga3dBackDXSetCOTable(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGACOTableType type, uint32_t cValidEntries) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + VMSVGA3DBACKENDDXCONTEXT *pBackendDXContext = pDXContext->pBackendDXContext; + + int rc = VINF_SUCCESS; + + /* + * 1) Release current backend table, if exists; + * 2) Reallocate memory for the new backend table; + * 3) If cValidEntries is not zero, then re-define corresponding backend table elements. + */ + switch (type) + { + case SVGA_COTABLE_RTVIEW: + /* Clear current entries. */ + if (pBackendDXContext->paRenderTargetView) + { + for (uint32_t i = 0; i < pBackendDXContext->cRenderTargetView; ++i) + { + DXVIEW *pDXView = &pBackendDXContext->paRenderTargetView[i]; + if (i < cValidEntries) + dxViewRemoveFromList(pDXView); /* Remove from list because DXVIEW array will be reallocated. */ + else + dxViewDestroy(pDXView); + } + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paRenderTargetView, &pBackendDXContext->cRenderTargetView, + sizeof(pBackendDXContext->paRenderTargetView[0]), pDXContext->cot.cRTView, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXRTViewEntry const *pEntry = &pDXContext->cot.paRTView[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define views which were not defined yet in backend. */ + DXVIEW *pDXView = &pBackendDXContext->paRenderTargetView[i]; + /** @todo Verify that the pEntry content still corresponds to the view. */ + if (pDXView->u.pView) + dxViewAddToList(pThisCC, pDXView); + else if (pDXView->enmViewType == VMSVGA3D_VIEWTYPE_NONE) + dxDefineRenderTargetView(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_DSVIEW: + if (pBackendDXContext->paDepthStencilView) + { + for (uint32_t i = 0; i < pBackendDXContext->cDepthStencilView; ++i) + { + DXVIEW *pDXView = &pBackendDXContext->paDepthStencilView[i]; + if (i < cValidEntries) + dxViewRemoveFromList(pDXView); /* Remove from list because DXVIEW array will be reallocated. */ + else + dxViewDestroy(pDXView); + } + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paDepthStencilView, &pBackendDXContext->cDepthStencilView, + sizeof(pBackendDXContext->paDepthStencilView[0]), pDXContext->cot.cDSView, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXDSViewEntry const *pEntry = &pDXContext->cot.paDSView[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define views which were not defined yet in backend. */ + DXVIEW *pDXView = &pBackendDXContext->paDepthStencilView[i]; + /** @todo Verify that the pEntry content still corresponds to the view. */ + if (pDXView->u.pView) + dxViewAddToList(pThisCC, pDXView); + else if (pDXView->enmViewType == VMSVGA3D_VIEWTYPE_NONE) + dxDefineDepthStencilView(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_SRVIEW: + if (pBackendDXContext->paShaderResourceView) + { + for (uint32_t i = 0; i < pBackendDXContext->cShaderResourceView; ++i) + { + DXVIEW *pDXView = &pBackendDXContext->paShaderResourceView[i]; + if (i < cValidEntries) + dxViewRemoveFromList(pDXView); /* Remove from list because DXVIEW array will be reallocated. */ + else + dxViewDestroy(pDXView); + } + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paShaderResourceView, &pBackendDXContext->cShaderResourceView, + sizeof(pBackendDXContext->paShaderResourceView[0]), pDXContext->cot.cSRView, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXSRViewEntry const *pEntry = &pDXContext->cot.paSRView[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define views which were not defined yet in backend. */ + DXVIEW *pDXView = &pBackendDXContext->paShaderResourceView[i]; + /** @todo Verify that the pEntry content still corresponds to the view. */ + if (pDXView->u.pView) + dxViewAddToList(pThisCC, pDXView); + else if (pDXView->enmViewType == VMSVGA3D_VIEWTYPE_NONE) + dxDefineShaderResourceView(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_ELEMENTLAYOUT: + if (pBackendDXContext->paElementLayout) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cElementLayout; ++i) + D3D_RELEASE(pBackendDXContext->paElementLayout[i].pElementLayout); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paElementLayout, &pBackendDXContext->cElementLayout, + sizeof(pBackendDXContext->paElementLayout[0]), pDXContext->cot.cElementLayout, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXElementLayoutEntry const *pEntry = &pDXContext->cot.paElementLayout[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + dxDefineElementLayout(pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_BLENDSTATE: + if (pBackendDXContext->papBlendState) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cBlendState; ++i) + D3D_RELEASE(pBackendDXContext->papBlendState[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->papBlendState, &pBackendDXContext->cBlendState, + sizeof(pBackendDXContext->papBlendState[0]), pDXContext->cot.cBlendState, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXBlendStateEntry const *pEntry = &pDXContext->cot.paBlendState[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + dxDefineBlendState(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_DEPTHSTENCIL: + if (pBackendDXContext->papDepthStencilState) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cDepthStencilState; ++i) + D3D_RELEASE(pBackendDXContext->papDepthStencilState[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->papDepthStencilState, &pBackendDXContext->cDepthStencilState, + sizeof(pBackendDXContext->papDepthStencilState[0]), pDXContext->cot.cDepthStencil, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXDepthStencilEntry const *pEntry = &pDXContext->cot.paDepthStencil[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + dxDefineDepthStencilState(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_RASTERIZERSTATE: + if (pBackendDXContext->papRasterizerState) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cRasterizerState; ++i) + D3D_RELEASE(pBackendDXContext->papRasterizerState[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->papRasterizerState, &pBackendDXContext->cRasterizerState, + sizeof(pBackendDXContext->papRasterizerState[0]), pDXContext->cot.cRasterizerState, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXRasterizerStateEntry const *pEntry = &pDXContext->cot.paRasterizerState[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + dxDefineRasterizerState(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_SAMPLER: + if (pBackendDXContext->papSamplerState) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cSamplerState; ++i) + D3D_RELEASE(pBackendDXContext->papSamplerState[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->papSamplerState, &pBackendDXContext->cSamplerState, + sizeof(pBackendDXContext->papSamplerState[0]), pDXContext->cot.cSampler, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXSamplerEntry const *pEntry = &pDXContext->cot.paSampler[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + dxDefineSamplerState(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_STREAMOUTPUT: + if (pBackendDXContext->paStreamOutput) + { + for (uint32_t i = cValidEntries; i < pBackendDXContext->cStreamOutput; ++i) + dxDestroyStreamOutput(&pBackendDXContext->paStreamOutput[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paStreamOutput, &pBackendDXContext->cStreamOutput, + sizeof(pBackendDXContext->paStreamOutput[0]), pDXContext->cot.cStreamOutput, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXStreamOutputEntry const *pEntry = &pDXContext->cot.paStreamOutput[i]; + /** @todo The caller must verify the COTable content using same rules as when a new entry is defined. */ + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Reset the stream output backend data. It will be re-created when a GS shader with this streamoutput + * will be set in setupPipeline. + */ + DXSTREAMOUTPUT *pDXStreamOutput = &pDXContext->pBackendDXContext->paStreamOutput[i]; + dxDestroyStreamOutput(pDXStreamOutput); + } + break; + case SVGA_COTABLE_DXQUERY: + if (pBackendDXContext->paQuery) + { + /* Destroy the no longer used entries. */ + for (uint32_t i = cValidEntries; i < pBackendDXContext->cQuery; ++i) + dxDestroyQuery(&pBackendDXContext->paQuery[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paQuery, &pBackendDXContext->cQuery, + sizeof(pBackendDXContext->paQuery[0]), pDXContext->cot.cQuery, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXQueryEntry const *pEntry = &pDXContext->cot.paQuery[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define queries which were not defined yet in backend. */ + DXQUERY *pDXQuery = &pBackendDXContext->paQuery[i]; + if ( pEntry->type != SVGA3D_QUERYTYPE_INVALID + && pDXQuery->pQuery == NULL) + dxDefineQuery(pThisCC, pDXContext, i, pEntry); + else + Assert(pEntry->type == SVGA3D_QUERYTYPE_INVALID || pDXQuery->pQuery); + } + break; + case SVGA_COTABLE_DXSHADER: + if (pBackendDXContext->paShader) + { + /* Destroy the no longer used entries. */ + for (uint32_t i = cValidEntries; i < pBackendDXContext->cShader; ++i) + dxDestroyShader(&pBackendDXContext->paShader[i]); + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paShader, &pBackendDXContext->cShader, + sizeof(pBackendDXContext->paShader[0]), pDXContext->cot.cShader, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXShaderEntry const *pEntry = &pDXContext->cot.paShader[i]; + /** @todo The caller must verify the COTable content using same rules as when a new entry is defined. */ + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define shaders which were not defined yet in backend. */ + DXSHADER *pDXShader = &pBackendDXContext->paShader[i]; + if ( pEntry->type != SVGA3D_SHADERTYPE_INVALID + && pDXShader->enmShaderType == SVGA3D_SHADERTYPE_INVALID) + dxDefineShader(pDXContext, i, pEntry); + else + Assert(pEntry->type == pDXShader->enmShaderType); + + } + break; + case SVGA_COTABLE_UAVIEW: + if (pBackendDXContext->paUnorderedAccessView) + { + for (uint32_t i = 0; i < pBackendDXContext->cUnorderedAccessView; ++i) + { + DXVIEW *pDXView = &pBackendDXContext->paUnorderedAccessView[i]; + if (i < cValidEntries) + dxViewRemoveFromList(pDXView); /* Remove from list because DXVIEW array will be reallocated. */ + else + dxViewDestroy(pDXView); + } + } + + rc = dxCOTableRealloc((void **)&pBackendDXContext->paUnorderedAccessView, &pBackendDXContext->cUnorderedAccessView, + sizeof(pBackendDXContext->paUnorderedAccessView[0]), pDXContext->cot.cUAView, cValidEntries); + AssertRCBreak(rc); + + for (uint32_t i = 0; i < cValidEntries; ++i) + { + SVGACOTableDXUAViewEntry const *pEntry = &pDXContext->cot.paUAView[i]; + if (ASMMemFirstNonZero(pEntry, sizeof(*pEntry)) == NULL) + continue; /* Skip uninitialized entry. */ + + /* Define views which were not defined yet in backend. */ + DXVIEW *pDXView = &pBackendDXContext->paUnorderedAccessView[i]; + /** @todo Verify that the pEntry content still corresponds to the view. */ + if (pDXView->u.pView) + dxViewAddToList(pThisCC, pDXView); + else if (pDXView->enmViewType == VMSVGA3D_VIEWTYPE_NONE) + dxDefineUnorderedAccessView(pThisCC, pDXContext, i, pEntry); + } + break; + case SVGA_COTABLE_MAX: break; /* Compiler warning */ + } + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBufferCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSurfaceCopyAndReadback(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXMoveQuery(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBindAllShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXHint(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBufferUpdate(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXCondBindAllShader(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackScreenCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackIntraSurfaceCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceImageId const &surface, SVGA3dCopyBox const &box) +{ + RT_NOREF(pDXContext); + + LogFunc(("sid %u\n", surface.sid)); + + PVMSVGA3DSTATE pState = pThisCC->svga.p3dState; + AssertReturn(pState, VERR_INVALID_STATE); + + PVMSVGA3DBACKEND pBackend = pState->pBackend; + + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, surface.sid, &pSurface); + AssertRCReturn(rc, rc); + + PVMSVGA3DMIPMAPLEVEL pMipLevel; + rc = vmsvga3dMipmapLevel(pSurface, surface.face, surface.mipmap, &pMipLevel); + ASSERT_GUEST_RETURN(RT_SUCCESS(rc), rc); + + /* Clip the box. */ + SVGA3dCopyBox clipBox = box; + vmsvgaR3ClipCopyBox(&pMipLevel->mipmapSize, &pMipLevel->mipmapSize, &clipBox); + + LogFunc(("surface%s cid %d\n", + pSurface->pBackendSurface ? "" : " sysmem", + pSurface ? pSurface->idAssociatedContext : SVGA_ID_INVALID)); + + if (pSurface->pBackendSurface) + { + /* Surface -> Surface. */ + DXDEVICE *pDXDevice = &pBackend->dxDevice; + + UINT DstSubresource = vmsvga3dCalcSubresource(surface.mipmap, surface.face, pSurface->cLevels); + UINT DstX = clipBox.x; + UINT DstY = clipBox.y; + UINT DstZ = clipBox.z; + + UINT SrcSubresource = DstSubresource; + D3D11_BOX SrcBox; + SrcBox.left = clipBox.srcx; + SrcBox.top = clipBox.srcy; + SrcBox.front = clipBox.srcz; + SrcBox.right = clipBox.srcx + clipBox.w; + SrcBox.bottom = clipBox.srcy + clipBox.h; + SrcBox.back = clipBox.srcz + clipBox.d; + + ID3D11Resource *pDstResource; + ID3D11Resource *pSrcResource; + pDstResource = dxResource(pState, pSurface, NULL); + pSrcResource = pDstResource; + + pDXDevice->pImmediateContext->CopySubresourceRegion1(pDstResource, DstSubresource, DstX, DstY, DstZ, + pSrcResource, SrcSubresource, &SrcBox, 0); + } + else + { + /* Memory -> Memory. */ + uint32_t const cxBlocks = (clipBox.w + pSurface->cxBlock - 1) / pSurface->cxBlock; + uint32_t const cyBlocks = (clipBox.h + pSurface->cyBlock - 1) / pSurface->cyBlock; + uint32_t const cbRow = cxBlocks * pSurface->cbBlock; + + uint8_t const *pu8Src = (uint8_t *)pMipLevel->pSurfaceData + + (clipBox.srcx / pSurface->cxBlock) * pSurface->cbBlock + + (clipBox.srcy / pSurface->cyBlock) * pMipLevel->cbSurfacePitch + + clipBox.srcz * pMipLevel->cbSurfacePlane; + + uint8_t *pu8Dst = (uint8_t *)pMipLevel->pSurfaceData + + (clipBox.x / pSurface->cxBlock) * pSurface->cbBlock + + (clipBox.y / pSurface->cyBlock) * pMipLevel->cbSurfacePitch + + clipBox.z * pMipLevel->cbSurfacePlane; + + for (uint32_t z = 0; z < clipBox.d; ++z) + { + uint8_t const *pu8PlaneSrc = pu8Src; + uint8_t *pu8PlaneDst = pu8Dst; + + for (uint32_t y = 0; y < cyBlocks; ++y) + { + memmove(pu8PlaneDst, pu8PlaneSrc, cbRow); + pu8PlaneDst += pMipLevel->cbSurfacePitch; + pu8PlaneSrc += pMipLevel->cbSurfacePitch; + } + + pu8Src += pMipLevel->cbSurfacePlane; + pu8Dst += pMipLevel->cbSurfacePlane; + } + } + + return rc; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXResolveCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPredResolveCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPredConvertRegion(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXPredConvert(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackWholeSurfaceCopy(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static int dxDefineUnorderedAccessView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId, SVGACOTableDXUAViewEntry const *pEntry) +{ + /* Get corresponding resource for pEntry->sid. Create the surface if does not yet exist. */ + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, pEntry->sid, &pSurface); + AssertRCReturn(rc, rc); + + ID3D11UnorderedAccessView *pUnorderedAccessView; + DXVIEW *pView = &pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId]; + Assert(pView->u.pView == NULL); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the actual texture or buffer. */ + /** @todo One function to create all resources from surfaces. */ + if (pSurface->format != SVGA3D_BUFFER) + rc = vmsvga3dBackSurfaceCreateTexture(pThisCC, pDXContext, pSurface); + else + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSurface); + + AssertRCReturn(rc, rc); + } + + HRESULT hr = dxUnorderedAccessViewCreate(pThisCC, pDXContext, pEntry, pSurface, &pUnorderedAccessView); + AssertReturn(SUCCEEDED(hr), VERR_INVALID_STATE); + + return dxViewInit(pView, pSurface, pDXContext, uaViewId, VMSVGA3D_VIEWTYPE_UNORDEREDACCESS, pUnorderedAccessView); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDefineUAView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId, SVGACOTableDXUAViewEntry const *pEntry) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /** @todo Probably not necessary because UAVs are defined in setupPipeline. */ + return dxDefineUnorderedAccessView(pThisCC, pDXContext, uaViewId, pEntry); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDestroyUAView(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + return dxViewDestroy(&pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId]); +} + + +static DECLCALLBACK(int) vmsvga3dBackDXClearUAViewUint(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId, uint32_t const aValues[4]) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId]; + if (!pDXView->u.pUnorderedAccessView) + { + /* (Re-)create the view, because a creation of a view is deferred until a draw or a clear call. */ + SVGACOTableDXUAViewEntry const *pEntry = dxGetUnorderedAccessViewEntry(pDXContext, uaViewId); + int rc = dxDefineUnorderedAccessView(pThisCC, pDXContext, uaViewId, pEntry); + AssertRCReturn(rc, rc); + } + pDevice->pImmediateContext->ClearUnorderedAccessViewUint(pDXView->u.pUnorderedAccessView, aValues); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXClearUAViewFloat(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId uaViewId, float const aValues[4]) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId]; + if (!pDXView->u.pUnorderedAccessView) + { + /* (Re-)create the view, because a creation of a view is deferred until a draw or a clear call. */ + SVGACOTableDXUAViewEntry const *pEntry = &pDXContext->cot.paUAView[uaViewId]; + int rc = dxDefineUnorderedAccessView(pThisCC, pDXContext, uaViewId, pEntry); + AssertRCReturn(rc, rc); + } + pDevice->pImmediateContext->ClearUnorderedAccessViewFloat(pDXView->u.pUnorderedAccessView, aValues); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXCopyStructureCount(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dUAViewId srcUAViewId, SVGA3dSurfaceId destSid, uint32_t destByteOffset) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Get corresponding resource. Create the buffer if does not yet exist. */ + ID3D11Buffer *pDstBuffer; + if (destSid != SVGA3D_INVALID_ID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, destSid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource and initialize it with the current surface data. */ + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + pDstBuffer = pSurface->pBackendSurface->u.pBuffer; + } + else + pDstBuffer = NULL; + + ID3D11UnorderedAccessView *pSrcView; + if (srcUAViewId != SVGA3D_INVALID_ID) + { + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paUnorderedAccessView[srcUAViewId]; + AssertReturn(pDXView->u.pUnorderedAccessView, VERR_INVALID_STATE); + pSrcView = pDXView->u.pUnorderedAccessView; + } + else + pSrcView = NULL; + + pDevice->pImmediateContext->CopyStructureCount(pDstBuffer, destByteOffset, pSrcView); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetUAViews(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t uavSpliceIndex, uint32_t cUAViewId, SVGA3dUAViewId const *paUAViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(uavSpliceIndex, cUAViewId, paUAViewId); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawIndexedInstancedIndirect(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceId argsBufferSid, uint32_t byteOffsetForArgs) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Get corresponding resource. Create the buffer if does not yet exist. */ + ID3D11Buffer *pBufferForArgs; + if (argsBufferSid != SVGA_ID_INVALID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, argsBufferSid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource and initialize it with the current surface data. */ + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + pBufferForArgs = pSurface->pBackendSurface->u.pBuffer; + } + else + pBufferForArgs = NULL; + + dxSetupPipeline(pThisCC, pDXContext); + + Assert(pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN); + + pDevice->pImmediateContext->DrawIndexedInstancedIndirect(pBufferForArgs, byteOffsetForArgs); + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDrawInstancedIndirect(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, SVGA3dSurfaceId argsBufferSid, uint32_t byteOffsetForArgs) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + /* Get corresponding resource. Create the buffer if does not yet exist. */ + ID3D11Buffer *pBufferForArgs; + if (argsBufferSid != SVGA_ID_INVALID) + { + PVMSVGA3DSURFACE pSurface; + int rc = vmsvga3dSurfaceFromSid(pThisCC->svga.p3dState, argsBufferSid, &pSurface); + AssertRCReturn(rc, rc); + + if (pSurface->pBackendSurface == NULL) + { + /* Create the resource and initialize it with the current surface data. */ + rc = vmsvga3dBackSurfaceCreateResource(pThisCC, pDXContext, pSurface); + AssertRCReturn(rc, rc); + } + + pBufferForArgs = pSurface->pBackendSurface->u.pBuffer; + } + else + pBufferForArgs = NULL; + + dxSetupPipeline(pThisCC, pDXContext); + + Assert(pDXContext->svgaDXContext.inputAssembly.topology != SVGA3D_PRIMITIVE_TRIANGLEFAN); + + pDevice->pImmediateContext->DrawInstancedIndirect(pBufferForArgs, byteOffsetForArgs); + + /* Note which surfaces are being drawn. */ + dxTrackRenderTargets(pThisCC, pDXContext); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDispatch(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + dxSetupPipeline(pThisCC, pDXContext); + + pDevice->pImmediateContext->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ); + +#ifdef DX_FLUSH_AFTER_DRAW + dxDeviceFlush(pDevice); +#endif + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXDispatchIndirect(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackWriteZeroSurface(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackHintZeroSurface(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXTransferToBuffer(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsBitBlt(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsTransBlt(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsStretchBlt(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsColorFill(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsAlphaBlend(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackLogicOpsClearTypeBlend(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static int dxSetCSUnorderedAccessViews(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + +//DEBUG_BREAKPOINT_TEST(); + uint32_t const *pUAIds = &pDXContext->svgaDXContext.csuaViewIds[0]; + ID3D11UnorderedAccessView *papUnorderedAccessView[SVGA3D_DX11_1_MAX_UAVIEWS]; + UINT aUAVInitialCounts[SVGA3D_DX11_1_MAX_UAVIEWS]; + for (uint32_t i = 0; i < SVGA3D_DX11_1_MAX_UAVIEWS; ++i) + { + SVGA3dUAViewId const uaViewId = pUAIds[i]; + if (uaViewId != SVGA3D_INVALID_ID) + { + ASSERT_GUEST_RETURN(uaViewId < pDXContext->pBackendDXContext->cUnorderedAccessView, VERR_INVALID_PARAMETER); + + DXVIEW *pDXView = &pDXContext->pBackendDXContext->paUnorderedAccessView[uaViewId]; + Assert(pDXView->u.pUnorderedAccessView); + papUnorderedAccessView[i] = pDXView->u.pUnorderedAccessView; + + SVGACOTableDXUAViewEntry const *pEntry = dxGetUnorderedAccessViewEntry(pDXContext, uaViewId); + aUAVInitialCounts[i] = pEntry->structureCount; + } + else + { + papUnorderedAccessView[i] = NULL; + aUAVInitialCounts[i] = (UINT)-1; + } + } + + dxCSUnorderedAccessViewSet(pDevice, 0, SVGA3D_DX11_1_MAX_UAVIEWS, papUnorderedAccessView, aUAVInitialCounts); + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetCSUAViews(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, uint32_t startIndex, uint32_t cUAViewId, SVGA3dUAViewId const *paUAViewId) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + RT_NOREF(pBackend); + + DXDEVICE *pDevice = dxDeviceFromContext(pThisCC->svga.p3dState, pDXContext); + AssertReturn(pDevice->pDevice, VERR_INVALID_STATE); + + RT_NOREF(startIndex, cUAViewId, paUAViewId); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetMinLOD(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSetShaderIface(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackSurfaceStretchBltNonMSToMS(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXBindShaderIface(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext) +{ + PVMSVGA3DBACKEND pBackend = pThisCC->svga.p3dState->pBackend; + + RT_NOREF(pBackend, pDXContext); + AssertFailed(); /** @todo Implement */ + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXLoadState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM) +{ + RT_NOREF(pThisCC); + uint32_t u32; + int rc; + + rc = pHlp->pfnSSMGetU32(pSSM, &u32); + AssertLogRelRCReturn(rc, rc); + AssertLogRelRCReturn(u32 == pDXContext->pBackendDXContext->cShader, VERR_INVALID_STATE); + + for (uint32_t i = 0; i < pDXContext->pBackendDXContext->cShader; ++i) + { + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[i]; + + rc = pHlp->pfnSSMGetU32(pSSM, &u32); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn((SVGA3dShaderType)u32 == pDXShader->enmShaderType, VERR_INVALID_STATE); + + if (pDXShader->enmShaderType == SVGA3D_SHADERTYPE_INVALID) + continue; + + pHlp->pfnSSMGetU32(pSSM, &pDXShader->soid); + + pHlp->pfnSSMGetU32(pSSM, &u32); + pDXShader->shaderInfo.enmProgramType = (VGPU10_PROGRAM_TYPE)u32; + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXShader->shaderInfo.cbBytecode); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn(pDXShader->shaderInfo.cbBytecode <= 2 * SVGA3D_MAX_SHADER_MEMORY_BYTES, VERR_INVALID_STATE); + + if (pDXShader->shaderInfo.cbBytecode) + { + pDXShader->shaderInfo.pvBytecode = RTMemAlloc(pDXShader->shaderInfo.cbBytecode); + AssertPtrReturn(pDXShader->shaderInfo.pvBytecode, VERR_NO_MEMORY); + pHlp->pfnSSMGetMem(pSSM, pDXShader->shaderInfo.pvBytecode, pDXShader->shaderInfo.cbBytecode); + } + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXShader->shaderInfo.cInputSignature); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn(pDXShader->shaderInfo.cInputSignature <= 32, VERR_INVALID_STATE); + if (pDXShader->shaderInfo.cInputSignature) + pHlp->pfnSSMGetMem(pSSM, pDXShader->shaderInfo.aInputSignature, pDXShader->shaderInfo.cInputSignature * sizeof(SVGA3dDXSignatureEntry)); + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXShader->shaderInfo.cOutputSignature); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn(pDXShader->shaderInfo.cOutputSignature <= 32, VERR_INVALID_STATE); + if (pDXShader->shaderInfo.cOutputSignature) + pHlp->pfnSSMGetMem(pSSM, pDXShader->shaderInfo.aOutputSignature, pDXShader->shaderInfo.cOutputSignature * sizeof(SVGA3dDXSignatureEntry)); + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXShader->shaderInfo.cPatchConstantSignature); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn(pDXShader->shaderInfo.cPatchConstantSignature <= 32, VERR_INVALID_STATE); + if (pDXShader->shaderInfo.cPatchConstantSignature) + pHlp->pfnSSMGetMem(pSSM, pDXShader->shaderInfo.aPatchConstantSignature, pDXShader->shaderInfo.cPatchConstantSignature * sizeof(SVGA3dDXSignatureEntry)); + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXShader->shaderInfo.cDclResource); + AssertLogRelRCReturn(rc, rc); + AssertLogRelReturn(pDXShader->shaderInfo.cDclResource <= SVGA3D_DX_MAX_SRVIEWS, VERR_INVALID_STATE); + if (pDXShader->shaderInfo.cDclResource) + pHlp->pfnSSMGetMem(pSSM, pDXShader->shaderInfo.aOffDclResource, pDXShader->shaderInfo.cDclResource * sizeof(uint32_t)); + + DXShaderGenerateSemantics(&pDXShader->shaderInfo); + } + + rc = pHlp->pfnSSMGetU32(pSSM, &pDXContext->pBackendDXContext->cSOTarget); + AssertLogRelRCReturn(rc, rc); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackDXSaveState(PVGASTATECC pThisCC, PVMSVGA3DDXCONTEXT pDXContext, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM) +{ + RT_NOREF(pThisCC); + int rc; + + pHlp->pfnSSMPutU32(pSSM, pDXContext->pBackendDXContext->cShader); + for (uint32_t i = 0; i < pDXContext->pBackendDXContext->cShader; ++i) + { + DXSHADER *pDXShader = &pDXContext->pBackendDXContext->paShader[i]; + + pHlp->pfnSSMPutU32(pSSM, (uint32_t)pDXShader->enmShaderType); + if (pDXShader->enmShaderType == SVGA3D_SHADERTYPE_INVALID) + continue; + + pHlp->pfnSSMPutU32(pSSM, pDXShader->soid); + + pHlp->pfnSSMPutU32(pSSM, (uint32_t)pDXShader->shaderInfo.enmProgramType); + + pHlp->pfnSSMPutU32(pSSM, pDXShader->shaderInfo.cbBytecode); + if (pDXShader->shaderInfo.cbBytecode) + pHlp->pfnSSMPutMem(pSSM, pDXShader->shaderInfo.pvBytecode, pDXShader->shaderInfo.cbBytecode); + + pHlp->pfnSSMPutU32(pSSM, pDXShader->shaderInfo.cInputSignature); + if (pDXShader->shaderInfo.cInputSignature) + pHlp->pfnSSMPutMem(pSSM, pDXShader->shaderInfo.aInputSignature, pDXShader->shaderInfo.cInputSignature * sizeof(SVGA3dDXSignatureEntry)); + + pHlp->pfnSSMPutU32(pSSM, pDXShader->shaderInfo.cOutputSignature); + if (pDXShader->shaderInfo.cOutputSignature) + pHlp->pfnSSMPutMem(pSSM, pDXShader->shaderInfo.aOutputSignature, pDXShader->shaderInfo.cOutputSignature * sizeof(SVGA3dDXSignatureEntry)); + + pHlp->pfnSSMPutU32(pSSM, pDXShader->shaderInfo.cPatchConstantSignature); + if (pDXShader->shaderInfo.cPatchConstantSignature) + pHlp->pfnSSMPutMem(pSSM, pDXShader->shaderInfo.aPatchConstantSignature, pDXShader->shaderInfo.cPatchConstantSignature * sizeof(SVGA3dDXSignatureEntry)); + + pHlp->pfnSSMPutU32(pSSM, pDXShader->shaderInfo.cDclResource); + if (pDXShader->shaderInfo.cDclResource) + pHlp->pfnSSMPutMem(pSSM, pDXShader->shaderInfo.aOffDclResource, pDXShader->shaderInfo.cDclResource * sizeof(uint32_t)); + } + rc = pHlp->pfnSSMPutU32(pSSM, pDXContext->pBackendDXContext->cSOTarget); + AssertLogRelRCReturn(rc, rc); + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) vmsvga3dBackQueryInterface(PVGASTATECC pThisCC, char const *pszInterfaceName, void *pvInterfaceFuncs, size_t cbInterfaceFuncs) +{ + RT_NOREF(pThisCC); + + int rc = VINF_SUCCESS; + if (RTStrCmp(pszInterfaceName, VMSVGA3D_BACKEND_INTERFACE_NAME_DX) == 0) + { + if (cbInterfaceFuncs == sizeof(VMSVGA3DBACKENDFUNCSDX)) + { + if (pvInterfaceFuncs) + { + VMSVGA3DBACKENDFUNCSDX *p = (VMSVGA3DBACKENDFUNCSDX *)pvInterfaceFuncs; + p->pfnDXSaveState = vmsvga3dBackDXSaveState; + p->pfnDXLoadState = vmsvga3dBackDXLoadState; + p->pfnDXDefineContext = vmsvga3dBackDXDefineContext; + p->pfnDXDestroyContext = vmsvga3dBackDXDestroyContext; + p->pfnDXBindContext = vmsvga3dBackDXBindContext; + p->pfnDXSwitchContext = vmsvga3dBackDXSwitchContext; + p->pfnDXReadbackContext = vmsvga3dBackDXReadbackContext; + p->pfnDXInvalidateContext = vmsvga3dBackDXInvalidateContext; + p->pfnDXSetSingleConstantBuffer = vmsvga3dBackDXSetSingleConstantBuffer; + p->pfnDXSetShaderResources = vmsvga3dBackDXSetShaderResources; + p->pfnDXSetShader = vmsvga3dBackDXSetShader; + p->pfnDXSetSamplers = vmsvga3dBackDXSetSamplers; + p->pfnDXDraw = vmsvga3dBackDXDraw; + p->pfnDXDrawIndexed = vmsvga3dBackDXDrawIndexed; + p->pfnDXDrawInstanced = vmsvga3dBackDXDrawInstanced; + p->pfnDXDrawIndexedInstanced = vmsvga3dBackDXDrawIndexedInstanced; + p->pfnDXDrawAuto = vmsvga3dBackDXDrawAuto; + p->pfnDXSetInputLayout = vmsvga3dBackDXSetInputLayout; + p->pfnDXSetVertexBuffers = vmsvga3dBackDXSetVertexBuffers; + p->pfnDXSetIndexBuffer = vmsvga3dBackDXSetIndexBuffer; + p->pfnDXSetTopology = vmsvga3dBackDXSetTopology; + p->pfnDXSetRenderTargets = vmsvga3dBackDXSetRenderTargets; + p->pfnDXSetBlendState = vmsvga3dBackDXSetBlendState; + p->pfnDXSetDepthStencilState = vmsvga3dBackDXSetDepthStencilState; + p->pfnDXSetRasterizerState = vmsvga3dBackDXSetRasterizerState; + p->pfnDXDefineQuery = vmsvga3dBackDXDefineQuery; + p->pfnDXDestroyQuery = vmsvga3dBackDXDestroyQuery; + p->pfnDXBeginQuery = vmsvga3dBackDXBeginQuery; + p->pfnDXEndQuery = vmsvga3dBackDXEndQuery; + p->pfnDXSetPredication = vmsvga3dBackDXSetPredication; + p->pfnDXSetSOTargets = vmsvga3dBackDXSetSOTargets; + p->pfnDXSetViewports = vmsvga3dBackDXSetViewports; + p->pfnDXSetScissorRects = vmsvga3dBackDXSetScissorRects; + p->pfnDXClearRenderTargetView = vmsvga3dBackDXClearRenderTargetView; + p->pfnDXClearDepthStencilView = vmsvga3dBackDXClearDepthStencilView; + p->pfnDXPredCopyRegion = vmsvga3dBackDXPredCopyRegion; + p->pfnDXPredCopy = vmsvga3dBackDXPredCopy; + p->pfnDXPresentBlt = vmsvga3dBackDXPresentBlt; + p->pfnDXGenMips = vmsvga3dBackDXGenMips; + p->pfnDXDefineShaderResourceView = vmsvga3dBackDXDefineShaderResourceView; + p->pfnDXDestroyShaderResourceView = vmsvga3dBackDXDestroyShaderResourceView; + p->pfnDXDefineRenderTargetView = vmsvga3dBackDXDefineRenderTargetView; + p->pfnDXDestroyRenderTargetView = vmsvga3dBackDXDestroyRenderTargetView; + p->pfnDXDefineDepthStencilView = vmsvga3dBackDXDefineDepthStencilView; + p->pfnDXDestroyDepthStencilView = vmsvga3dBackDXDestroyDepthStencilView; + p->pfnDXDefineElementLayout = vmsvga3dBackDXDefineElementLayout; + p->pfnDXDestroyElementLayout = vmsvga3dBackDXDestroyElementLayout; + p->pfnDXDefineBlendState = vmsvga3dBackDXDefineBlendState; + p->pfnDXDestroyBlendState = vmsvga3dBackDXDestroyBlendState; + p->pfnDXDefineDepthStencilState = vmsvga3dBackDXDefineDepthStencilState; + p->pfnDXDestroyDepthStencilState = vmsvga3dBackDXDestroyDepthStencilState; + p->pfnDXDefineRasterizerState = vmsvga3dBackDXDefineRasterizerState; + p->pfnDXDestroyRasterizerState = vmsvga3dBackDXDestroyRasterizerState; + p->pfnDXDefineSamplerState = vmsvga3dBackDXDefineSamplerState; + p->pfnDXDestroySamplerState = vmsvga3dBackDXDestroySamplerState; + p->pfnDXDefineShader = vmsvga3dBackDXDefineShader; + p->pfnDXDestroyShader = vmsvga3dBackDXDestroyShader; + p->pfnDXBindShader = vmsvga3dBackDXBindShader; + p->pfnDXDefineStreamOutput = vmsvga3dBackDXDefineStreamOutput; + p->pfnDXDestroyStreamOutput = vmsvga3dBackDXDestroyStreamOutput; + p->pfnDXSetStreamOutput = vmsvga3dBackDXSetStreamOutput; + p->pfnDXSetCOTable = vmsvga3dBackDXSetCOTable; + p->pfnDXBufferCopy = vmsvga3dBackDXBufferCopy; + p->pfnDXSurfaceCopyAndReadback = vmsvga3dBackDXSurfaceCopyAndReadback; + p->pfnDXMoveQuery = vmsvga3dBackDXMoveQuery; + p->pfnDXBindAllShader = vmsvga3dBackDXBindAllShader; + p->pfnDXHint = vmsvga3dBackDXHint; + p->pfnDXBufferUpdate = vmsvga3dBackDXBufferUpdate; + p->pfnDXCondBindAllShader = vmsvga3dBackDXCondBindAllShader; + p->pfnScreenCopy = vmsvga3dBackScreenCopy; + p->pfnIntraSurfaceCopy = vmsvga3dBackIntraSurfaceCopy; + p->pfnDXResolveCopy = vmsvga3dBackDXResolveCopy; + p->pfnDXPredResolveCopy = vmsvga3dBackDXPredResolveCopy; + p->pfnDXPredConvertRegion = vmsvga3dBackDXPredConvertRegion; + p->pfnDXPredConvert = vmsvga3dBackDXPredConvert; + p->pfnWholeSurfaceCopy = vmsvga3dBackWholeSurfaceCopy; + p->pfnDXDefineUAView = vmsvga3dBackDXDefineUAView; + p->pfnDXDestroyUAView = vmsvga3dBackDXDestroyUAView; + p->pfnDXClearUAViewUint = vmsvga3dBackDXClearUAViewUint; + p->pfnDXClearUAViewFloat = vmsvga3dBackDXClearUAViewFloat; + p->pfnDXCopyStructureCount = vmsvga3dBackDXCopyStructureCount; + p->pfnDXSetUAViews = vmsvga3dBackDXSetUAViews; + p->pfnDXDrawIndexedInstancedIndirect = vmsvga3dBackDXDrawIndexedInstancedIndirect; + p->pfnDXDrawInstancedIndirect = vmsvga3dBackDXDrawInstancedIndirect; + p->pfnDXDispatch = vmsvga3dBackDXDispatch; + p->pfnDXDispatchIndirect = vmsvga3dBackDXDispatchIndirect; + p->pfnWriteZeroSurface = vmsvga3dBackWriteZeroSurface; + p->pfnHintZeroSurface = vmsvga3dBackHintZeroSurface; + p->pfnDXTransferToBuffer = vmsvga3dBackDXTransferToBuffer; + p->pfnLogicOpsBitBlt = vmsvga3dBackLogicOpsBitBlt; + p->pfnLogicOpsTransBlt = vmsvga3dBackLogicOpsTransBlt; + p->pfnLogicOpsStretchBlt = vmsvga3dBackLogicOpsStretchBlt; + p->pfnLogicOpsColorFill = vmsvga3dBackLogicOpsColorFill; + p->pfnLogicOpsAlphaBlend = vmsvga3dBackLogicOpsAlphaBlend; + p->pfnLogicOpsClearTypeBlend = vmsvga3dBackLogicOpsClearTypeBlend; + p->pfnDXSetCSUAViews = vmsvga3dBackDXSetCSUAViews; + p->pfnDXSetMinLOD = vmsvga3dBackDXSetMinLOD; + p->pfnDXSetShaderIface = vmsvga3dBackDXSetShaderIface; + p->pfnSurfaceStretchBltNonMSToMS = vmsvga3dBackSurfaceStretchBltNonMSToMS; + p->pfnDXBindShaderIface = vmsvga3dBackDXBindShaderIface; + p->pfnVBDXClearRenderTargetViewRegion = vmsvga3dBackVBDXClearRenderTargetViewRegion; + } + } + else + { + AssertFailed(); + rc = VERR_INVALID_PARAMETER; + } + } + else if (RTStrCmp(pszInterfaceName, VMSVGA3D_BACKEND_INTERFACE_NAME_MAP) == 0) + { + if (cbInterfaceFuncs == sizeof(VMSVGA3DBACKENDFUNCSMAP)) + { + if (pvInterfaceFuncs) + { + VMSVGA3DBACKENDFUNCSMAP *p = (VMSVGA3DBACKENDFUNCSMAP *)pvInterfaceFuncs; + p->pfnSurfaceMap = vmsvga3dBackSurfaceMap; + p->pfnSurfaceUnmap = vmsvga3dBackSurfaceUnmap; + } + } + else + { + AssertFailed(); + rc = VERR_INVALID_PARAMETER; + } + } + else if (RTStrCmp(pszInterfaceName, VMSVGA3D_BACKEND_INTERFACE_NAME_GBO) == 0) + { + if (cbInterfaceFuncs == sizeof(VMSVGA3DBACKENDFUNCSGBO)) + { + if (pvInterfaceFuncs) + { + VMSVGA3DBACKENDFUNCSGBO *p = (VMSVGA3DBACKENDFUNCSGBO *)pvInterfaceFuncs; + p->pfnScreenTargetBind = vmsvga3dScreenTargetBind; + p->pfnScreenTargetUpdate = vmsvga3dScreenTargetUpdate; + } + } + else + { + AssertFailed(); + rc = VERR_INVALID_PARAMETER; + } + } + else if (RTStrCmp(pszInterfaceName, VMSVGA3D_BACKEND_INTERFACE_NAME_3D) == 0) + { + if (cbInterfaceFuncs == sizeof(VMSVGA3DBACKENDFUNCS3D)) + { + if (pvInterfaceFuncs) + { + VMSVGA3DBACKENDFUNCS3D *p = (VMSVGA3DBACKENDFUNCS3D *)pvInterfaceFuncs; + p->pfnInit = vmsvga3dBackInit; + p->pfnPowerOn = vmsvga3dBackPowerOn; + p->pfnTerminate = vmsvga3dBackTerminate; + p->pfnReset = vmsvga3dBackReset; + p->pfnQueryCaps = vmsvga3dBackQueryCaps; + p->pfnChangeMode = vmsvga3dBackChangeMode; + p->pfnCreateTexture = vmsvga3dBackCreateTexture; + p->pfnSurfaceDestroy = vmsvga3dBackSurfaceDestroy; + p->pfnSurfaceInvalidateImage = vmsvga3dBackSurfaceInvalidateImage; + p->pfnSurfaceCopy = vmsvga3dBackSurfaceCopy; + p->pfnSurfaceDMACopyBox = vmsvga3dBackSurfaceDMACopyBox; + p->pfnSurfaceStretchBlt = vmsvga3dBackSurfaceStretchBlt; + p->pfnUpdateHostScreenViewport = vmsvga3dBackUpdateHostScreenViewport; + p->pfnDefineScreen = vmsvga3dBackDefineScreen; + p->pfnDestroyScreen = vmsvga3dBackDestroyScreen; + p->pfnSurfaceBlitToScreen = vmsvga3dBackSurfaceBlitToScreen; + p->pfnSurfaceUpdateHeapBuffers = vmsvga3dBackSurfaceUpdateHeapBuffers; + } + } + else + { + AssertFailed(); + rc = VERR_INVALID_PARAMETER; + } + } + else if (RTStrCmp(pszInterfaceName, VMSVGA3D_BACKEND_INTERFACE_NAME_VGPU9) == 0) + { + if (cbInterfaceFuncs == sizeof(VMSVGA3DBACKENDFUNCSVGPU9)) + { + if (pvInterfaceFuncs) + { + VMSVGA3DBACKENDFUNCSVGPU9 *p = (VMSVGA3DBACKENDFUNCSVGPU9 *)pvInterfaceFuncs; + p->pfnContextDefine = vmsvga3dBackContextDefine; + p->pfnContextDestroy = vmsvga3dBackContextDestroy; + p->pfnSetTransform = vmsvga3dBackSetTransform; + p->pfnSetZRange = vmsvga3dBackSetZRange; + p->pfnSetRenderState = vmsvga3dBackSetRenderState; + p->pfnSetRenderTarget = vmsvga3dBackSetRenderTarget; + p->pfnSetTextureState = vmsvga3dBackSetTextureState; + p->pfnSetMaterial = vmsvga3dBackSetMaterial; + p->pfnSetLightData = vmsvga3dBackSetLightData; + p->pfnSetLightEnabled = vmsvga3dBackSetLightEnabled; + p->pfnSetViewPort = vmsvga3dBackSetViewPort; + p->pfnSetClipPlane = vmsvga3dBackSetClipPlane; + p->pfnCommandClear = vmsvga3dBackCommandClear; + p->pfnDrawPrimitives = vmsvga3dBackDrawPrimitives; + p->pfnSetScissorRect = vmsvga3dBackSetScissorRect; + p->pfnGenerateMipmaps = vmsvga3dBackGenerateMipmaps; + p->pfnShaderDefine = vmsvga3dBackShaderDefine; + p->pfnShaderDestroy = vmsvga3dBackShaderDestroy; + p->pfnShaderSet = vmsvga3dBackShaderSet; + p->pfnShaderSetConst = vmsvga3dBackShaderSetConst; + p->pfnOcclusionQueryCreate = vmsvga3dBackOcclusionQueryCreate; + p->pfnOcclusionQueryDelete = vmsvga3dBackOcclusionQueryDelete; + p->pfnOcclusionQueryBegin = vmsvga3dBackOcclusionQueryBegin; + p->pfnOcclusionQueryEnd = vmsvga3dBackOcclusionQueryEnd; + p->pfnOcclusionQueryGetData = vmsvga3dBackOcclusionQueryGetData; + } + } + else + { + AssertFailed(); + rc = VERR_INVALID_PARAMETER; + } + } + else + rc = VERR_NOT_IMPLEMENTED; + return rc; +} + + +extern VMSVGA3DBACKENDDESC const g_BackendDX = +{ + "DX", + vmsvga3dBackQueryInterface +}; |