From d6e7e3e78033718463fda3b09c139fce7eea9681 Mon Sep 17 00:00:00 2001 From: Alpyne Date: Wed, 21 Jun 2023 16:49:38 +0100 Subject: [PATCH] [d3d9] Add DxvkD3D8Bridge for d3d8 interop --- src/d3d9/d3d9_bridge.cpp | 103 ++++++++++++++++++++++++++++++++++++ src/d3d9/d3d9_bridge.h | 103 ++++++++++++++++++++++++++++++++++++ src/d3d9/d3d9_device.cpp | 8 ++- src/d3d9/d3d9_device.h | 4 ++ src/d3d9/d3d9_interface.cpp | 7 +++ src/d3d9/d3d9_interface.h | 3 ++ src/d3d9/meson.build | 3 +- 7 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/d3d9/d3d9_bridge.cpp create mode 100644 src/d3d9/d3d9_bridge.h diff --git a/src/d3d9/d3d9_bridge.cpp b/src/d3d9/d3d9_bridge.cpp new file mode 100644 index 00000000..d5248e53 --- /dev/null +++ b/src/d3d9/d3d9_bridge.cpp @@ -0,0 +1,103 @@ + +#include "d3d9_device.h" +#include "d3d9_interface.h" +#include "d3d9_bridge.h" +#include "d3d9_swapchain.h" +#include "d3d9_surface.h" + +namespace dxvk { + + DxvkD3D8Bridge::DxvkD3D8Bridge(D3D9DeviceEx* pDevice) + : m_device(pDevice) { + } + + DxvkD3D8Bridge::~DxvkD3D8Bridge() { + } + + ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::AddRef() { + return m_device->AddRef(); + } + + ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::Release() { + return m_device->Release(); + } + + HRESULT STDMETHODCALLTYPE DxvkD3D8Bridge::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_device->QueryInterface(riid, ppvObject); + } + + HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint) { + auto lock = m_device->LockDevice(); + + D3D9Surface* dst = static_cast(pDestSurface); + D3D9Surface* src = static_cast(pSrcSurface); + + if (unlikely(dst == nullptr || src == nullptr)) + return D3DERR_INVALIDCALL; + + D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture(); + D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture(); + + VkOffset3D srcOffset = { 0u, 0u, 0u }; + VkOffset3D dstOffset = { 0u, 0u, 0u }; + VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource()); + VkExtent3D extent = texLevelExtent; + + srcOffset = { pSrcRect->left, + pSrcRect->top, + 0u }; + + extent = { uint32_t(pSrcRect->right - pSrcRect->left), uint32_t(pSrcRect->bottom - pSrcRect->top), 1 }; + + // TODO: Validate extents like in D3D9DeviceEx::UpdateSurface + + dstOffset = { pDestPoint->x, + pDestPoint->y, + 0u }; + + + m_device->UpdateTextureFromBuffer( + srcTextureInfo, dstTextureInfo, + src->GetSubresource(), dst->GetSubresource(), + srcOffset, extent, dstOffset + ); + + dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true); + + if (dstTextureInfo->IsAutomaticMip()) + m_device->MarkTextureMipsDirty(dstTextureInfo); + + return D3D_OK; + } + + DxvkD3D8InterfaceBridge::DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject) + : m_interface(pObject) { + } + + DxvkD3D8InterfaceBridge::~DxvkD3D8InterfaceBridge() { + } + + ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::AddRef() { + return m_interface->AddRef(); + } + + ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::Release() { + return m_interface->Release(); + } + + HRESULT STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_interface->QueryInterface(riid, ppvObject); + } + + const Config* DxvkD3D8InterfaceBridge::GetConfig() const { + return &m_interface->GetInstance()->config(); + } +} \ No newline at end of file diff --git a/src/d3d9/d3d9_bridge.h b/src/d3d9/d3d9_bridge.h new file mode 100644 index 00000000..99c53031 --- /dev/null +++ b/src/d3d9/d3d9_bridge.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include "../util/config/config.h" + +#include "../vulkan/vulkan_loader.h" + +/** + * The D3D9 bridge allows D3D8 to access DXVK internals. + * For Vulkan interop without needing DXVK internals, see d3d9_interop.h. + * + * NOTE: You must include "d3d9_include.h" or "d3d8_include.h" before this header. + */ + +/** + * \brief D3D9 device interface for D3D8 interop + */ +MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") +IDxvkD3D8Bridge : public IUnknown { + + // D3D8 keeps D3D9 objects contained in a namespace. + #ifdef DXVK_D3D9_NAMESPACE + using IDirect3DSurface9 = d3d9::IDirect3DSurface9; + #endif + + /** + * \brief Updates a D3D9 surface from a D3D9 buffer + * + * \param [in] pDestSurface Destination surface (typically in VRAM) + * \param [in] pSrcSurface Source surface (typically in system memory) + * \param [in] pSrcRect Source rectangle + * \param [in] pDestPoint Destination (top-left) point + */ + virtual HRESULT UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint) = 0; +}; + +/** + * \brief D3D9 instance interface for D3D8 interop + */ +MIDL_INTERFACE("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000") +IDxvkD3D8InterfaceBridge : public IUnknown { + /** + * \brief Retrieves the DXVK configuration + * \returns The DXVK Config object + */ + virtual const dxvk::Config* GetConfig() const = 0; +}; + +#if defined(_MSC_VER) +struct DECLSPEC_UUID("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") IDxvkD3D8Bridge; +struct DECLSPEC_UUID("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000") IDxvkD3D8InterfaceBridge; +#else +__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00); +__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00); +#endif + +namespace dxvk { + + class D3D9DeviceEx; + class D3D9InterfaceEx; + + class DxvkD3D8Bridge : public IDxvkD3D8Bridge { + public: + DxvkD3D8Bridge(D3D9DeviceEx* pDevice); + ~DxvkD3D8Bridge(); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT UpdateTextureFromBuffer( + IDirect3DSurface9* pDestSurface, + IDirect3DSurface9* pSrcSurface, + const RECT* pSrcRect, + const POINT* pDestPoint); + + private: + D3D9DeviceEx* m_device; + }; + + class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge { + public: + DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject); + ~DxvkD3D8InterfaceBridge(); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + const Config* GetConfig() const; + + protected: + D3D9InterfaceEx* m_interface; + }; +} diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 95046bc8..508c856b 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -56,7 +56,8 @@ namespace dxvk { , m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) ) , m_csChunk ( AllocCsChunk() ) , m_d3d9Interop ( this ) - , m_d3d9On12 ( this ) { + , m_d3d9On12 ( this ) + , m_d3d8Bridge ( this ) { // If we can SWVP, then we use an extended constant set // as SWVP has many more slots available than HWVP. bool canSWVP = CanSWVP(); @@ -218,6 +219,11 @@ namespace dxvk { *ppvObject = ref(this); return S_OK; } + + if (riid == __uuidof(IDxvkD3D8Bridge)) { + *ppvObject = ref(&m_d3d8Bridge); + return S_OK; + } if (riid == __uuidof(ID3D9VkInteropDevice)) { *ppvObject = ref(&m_d3d9Interop); diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index 632d3656..540e674c 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -32,6 +32,8 @@ #include #include +#include "d3d9_bridge.h" + #include #include #include @@ -127,6 +129,7 @@ namespace dxvk { friend class D3D9SwapChainEx; friend class D3D9ConstantBuffer; friend class D3D9UserDefinedAnnotation; + friend class DxvkD3D8Bridge; friend D3D9VkInteropDevice; public: @@ -1364,6 +1367,7 @@ namespace dxvk { D3D9VkInteropDevice m_d3d9Interop; D3D9On12 m_d3d9On12; + DxvkD3D8Bridge m_d3d8Bridge; }; } diff --git a/src/d3d9/d3d9_interface.cpp b/src/d3d9/d3d9_interface.cpp index e56c8b3d..690e16d1 100644 --- a/src/d3d9/d3d9_interface.cpp +++ b/src/d3d9/d3d9_interface.cpp @@ -3,6 +3,7 @@ #include "d3d9_monitor.h" #include "d3d9_caps.h" #include "d3d9_device.h" +#include "d3d9_bridge.h" #include "../util/util_singleton.h" @@ -14,6 +15,7 @@ namespace dxvk { D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended) : m_instance ( g_dxvkInstance.acquire() ) + , m_d3d8Bridge ( this ) , m_extended ( bExtended ) , m_d3d9Options ( nullptr, m_instance->config() ) , m_d3d9Interop ( this ) { @@ -86,6 +88,11 @@ namespace dxvk { return S_OK; } + if (riid == __uuidof(IDxvkD3D8InterfaceBridge)) { + *ppvObject = ref(&m_d3d8Bridge); + return S_OK; + } + if (riid == __uuidof(ID3D9VkInteropInterface)) { *ppvObject = ref(&m_d3d9Interop); return S_OK; diff --git a/src/d3d9/d3d9_interface.h b/src/d3d9/d3d9_interface.h index 55c9be91..43046f73 100644 --- a/src/d3d9/d3d9_interface.h +++ b/src/d3d9/d3d9_interface.h @@ -1,6 +1,7 @@ #pragma once #include "d3d9_adapter.h" +#include "d3d9_bridge.h" #include "d3d9_interop.h" #include "../dxvk/dxvk_instance.h" @@ -140,6 +141,8 @@ namespace dxvk { Rc m_instance; + DxvkD3D8InterfaceBridge m_d3d8Bridge; + bool m_extended; D3D9Options m_d3d9Options; diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index 8a49a9db..dd6b2316 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -45,7 +45,8 @@ d3d9_src = [ 'd3d9_mem.cpp', 'd3d9_window.cpp', 'd3d9_interop.cpp', - 'd3d9_on_12.cpp' + 'd3d9_on_12.cpp', + 'd3d9_bridge.cpp' ] d3d9_ld_args = []