// dx11 factory vtable hooks. patches CreateSwapChain / CreateSwapChainForHwnd // so we can install_swapchain_hooks against every newly-created swapchain. #include "d3d11_backend.h" #ifdef SPICE_D3D11 #include #include #include #include #include #include "d3d11_internal.h" namespace { using CreateSwapChain_t = HRESULT(STDMETHODCALLTYPE *)( IDXGIFactory *, IUnknown *, DXGI_SWAP_CHAIN_DESC *, IDXGISwapChain **); using CreateSwapChainForHwnd_t = HRESULT(STDMETHODCALLTYPE *)( IDXGIFactory2 *, IUnknown *, HWND, const DXGI_SWAP_CHAIN_DESC1 *, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *, IDXGIOutput *, IDXGISwapChain1 **); CreateSwapChain_t CreateSwapChain_orig = nullptr; CreateSwapChainForHwnd_t CreateSwapChainForHwnd_orig = nullptr; bool g_factory_hooked = false; bool g_factory2_hooked = false; std::mutex g_hook_mutex; HRESULT STDMETHODCALLTYPE CreateSwapChain_hook( IDXGIFactory *factory, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGISwapChain **ppSwapChain) { HRESULT res = CreateSwapChain_orig(factory, pDevice, pDesc, ppSwapChain); if (SUCCEEDED(res) && ppSwapChain && *ppSwapChain) { if (pDesc) { d3d11_hooks::note_main_hwnd(pDesc->OutputWindow); } d3d11_hooks::install_swapchain_hooks(*ppSwapChain); } return res; } HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd_hook( IDXGIFactory2 *factory, IUnknown *pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput, IDXGISwapChain1 **ppSwapChain) { HRESULT res = CreateSwapChainForHwnd_orig( factory, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); if (SUCCEEDED(res) && ppSwapChain && *ppSwapChain) { d3d11_hooks::note_main_hwnd(hWnd); d3d11_hooks::install_swapchain_hooks(*ppSwapChain); } return res; } // QI-and-hook helper: dedupes the IDXGIFactory / IDXGIFactory2 install paths. template void install_on(IUnknown *factory, bool &flag, size_t vtbl_index, void *hook, void **orig, const char *name) { if (flag) { return; } Iface *f = nullptr; if (FAILED(factory->QueryInterface(IID_PPV_ARGS(&f))) || !f) { return; } if (d3d11_hooks::hook_vtbl(f, vtbl_index, hook, orig, name)) { flag = true; } f->Release(); } } // namespace namespace d3d11_hooks { void install_factory_hooks(IUnknown *factory) { if (!factory) { return; } std::lock_guard lock(g_hook_mutex); install_on(factory, g_factory_hooked, 10, (void *) CreateSwapChain_hook, (void **) &CreateSwapChain_orig, "IDXGIFactory::CreateSwapChain"); install_on(factory, g_factory2_hooked, 15, (void *) CreateSwapChainForHwnd_hook, (void **) &CreateSwapChainForHwnd_orig, "IDXGIFactory2::CreateSwapChainForHwnd"); } } #endif // SPICE_D3D11