#pragma once #include "dxgi_swapchain.h" namespace dxvk { class DxgiSwapChainDispatcher : public IDXGISwapChain4 { public: DxgiSwapChainDispatcher(IDXGISwapChain4* dispatch, IUnknown* device) : m_device(device), m_dispatch(dispatch) { } virtual ~DxgiSwapChainDispatcher() { } ULONG STDMETHODCALLTYPE AddRef() { if (likely(m_dispatch != nullptr)) return m_dispatch->AddRef(); return 0; } ULONG STDMETHODCALLTYPE Release() { if (likely(m_dispatch != nullptr)) { ULONG refCount = m_dispatch->Release(); if (unlikely(!refCount)) { // Clear the underlying swap chain pointer. Helps in // use-after-free situations encountered in Divinity // Original Sin Enhanced Edition. m_dispatch = nullptr; delete this; } return refCount; } return ~0u; } HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppvObject) final { if (ppvObject == nullptr) return E_POINTER; *ppvObject = nullptr; if (riid == __uuidof(IUnknown) || riid == __uuidof(IDXGIObject) || riid == __uuidof(IDXGIDeviceSubObject) || riid == __uuidof(IDXGISwapChain) || riid == __uuidof(IDXGISwapChain1) || riid == __uuidof(IDXGISwapChain2) || riid == __uuidof(IDXGISwapChain3) || riid == __uuidof(IDXGISwapChain4)) { *ppvObject = ref(this); return S_OK; } if (logQueryInterfaceError(__uuidof(IDXGISwapChain), riid)) { Logger::warn("DxgiSwapChainDispatcher::QueryInterface: Unknown interface query"); Logger::warn(str::format(riid)); } return m_dispatch->QueryInterface(riid, ppvObject); } HRESULT STDMETHODCALLTYPE GetPrivateData( REFGUID Name, UINT* pDataSize, void* pData) final { return m_dispatch->GetPrivateData(Name, pDataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateData( REFGUID Name, UINT DataSize, const void* pData) final { return m_dispatch->SetPrivateData(Name, DataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( REFGUID Name, const IUnknown* pUnknown) final { return m_dispatch->SetPrivateDataInterface(Name, pUnknown); } HRESULT STDMETHODCALLTYPE GetParent( REFIID riid, void** ppParent) final { return m_dispatch->GetParent(riid, ppParent); } HRESULT STDMETHODCALLTYPE GetDevice( REFIID riid, void** ppDevice) final { return m_dispatch->GetDevice(riid, ppDevice); } HRESULT STDMETHODCALLTYPE GetBuffer( UINT Buffer, REFIID riid, void** ppSurface) final { return m_dispatch->GetBuffer(Buffer, riid, ppSurface); } UINT STDMETHODCALLTYPE GetCurrentBackBufferIndex() final { return m_dispatch->GetCurrentBackBufferIndex(); } HRESULT STDMETHODCALLTYPE GetContainingOutput( IDXGIOutput** ppOutput) final { return m_dispatch->GetContainingOutput(ppOutput); } HRESULT STDMETHODCALLTYPE GetDesc( DXGI_SWAP_CHAIN_DESC* pDesc) final { return m_dispatch->GetDesc(pDesc); } HRESULT STDMETHODCALLTYPE GetDesc1( DXGI_SWAP_CHAIN_DESC1* pDesc) final { return m_dispatch->GetDesc1(pDesc); } HRESULT STDMETHODCALLTYPE GetFullscreenState( BOOL* pFullscreen, IDXGIOutput** ppTarget) final { if (likely(m_dispatch != nullptr)) return m_dispatch->GetFullscreenState(pFullscreen, ppTarget); if (pFullscreen) *pFullscreen = FALSE; if (ppTarget) *ppTarget = nullptr; return S_OK; } HRESULT STDMETHODCALLTYPE GetFullscreenDesc( DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) final { return m_dispatch->GetFullscreenDesc(pDesc); } HRESULT STDMETHODCALLTYPE GetHwnd( HWND* pHwnd) final { return m_dispatch->GetHwnd(pHwnd); } HRESULT STDMETHODCALLTYPE GetCoreWindow( REFIID refiid, void** ppUnk) final { return m_dispatch->GetCoreWindow(refiid, ppUnk); } HRESULT STDMETHODCALLTYPE GetBackgroundColor( DXGI_RGBA* pColor) final { return m_dispatch->GetBackgroundColor(pColor); } HRESULT STDMETHODCALLTYPE GetRotation( DXGI_MODE_ROTATION* pRotation) final { return m_dispatch->GetRotation(pRotation); } HRESULT STDMETHODCALLTYPE GetRestrictToOutput( IDXGIOutput** ppRestrictToOutput) final { return m_dispatch->GetRestrictToOutput(ppRestrictToOutput); } HRESULT STDMETHODCALLTYPE GetFrameStatistics( DXGI_FRAME_STATISTICS* pStats) final { return m_dispatch->GetFrameStatistics(pStats); } HRESULT STDMETHODCALLTYPE GetLastPresentCount( UINT* pLastPresentCount) final { return m_dispatch->GetLastPresentCount(pLastPresentCount); } BOOL STDMETHODCALLTYPE IsTemporaryMonoSupported() final { return m_dispatch->IsTemporaryMonoSupported(); } HRESULT STDMETHODCALLTYPE Present( UINT SyncInterval, UINT Flags) final { return m_dispatch->Present(SyncInterval, Flags); } HRESULT STDMETHODCALLTYPE Present1( UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) final { return m_dispatch->Present1(SyncInterval, PresentFlags, pPresentParameters); } HRESULT STDMETHODCALLTYPE ResizeBuffers( UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) final { return m_dispatch->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); } HRESULT STDMETHODCALLTYPE ResizeBuffers1( UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT Format, UINT SwapChainFlags, const UINT* pCreationNodeMask, IUnknown* const* ppPresentQueue) final { return m_dispatch->ResizeBuffers1(BufferCount, Width, Height, Format, SwapChainFlags, pCreationNodeMask, ppPresentQueue); } HRESULT STDMETHODCALLTYPE ResizeTarget( const DXGI_MODE_DESC* pNewTargetParameters) final { return m_dispatch->ResizeTarget(pNewTargetParameters); } HRESULT STDMETHODCALLTYPE SetFullscreenState( BOOL Fullscreen, IDXGIOutput* pTarget) final { if (likely(m_dispatch != nullptr)) return m_dispatch->SetFullscreenState(Fullscreen, pTarget); return S_OK; } HRESULT STDMETHODCALLTYPE SetBackgroundColor( const DXGI_RGBA* pColor) final { return m_dispatch->SetBackgroundColor(pColor); } HRESULT STDMETHODCALLTYPE SetRotation( DXGI_MODE_ROTATION Rotation) final { return m_dispatch->SetRotation(Rotation); } HANDLE STDMETHODCALLTYPE GetFrameLatencyWaitableObject() final { return m_dispatch->GetFrameLatencyWaitableObject(); } HRESULT STDMETHODCALLTYPE GetMatrixTransform( DXGI_MATRIX_3X2_F* pMatrix) final { return m_dispatch->GetMatrixTransform(pMatrix); } HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency( UINT* pMaxLatency) final { return m_dispatch->GetMaximumFrameLatency(pMaxLatency); } HRESULT STDMETHODCALLTYPE GetSourceSize( UINT* pWidth, UINT* pHeight) final { return m_dispatch->GetSourceSize(pWidth, pHeight); } HRESULT STDMETHODCALLTYPE SetMatrixTransform( const DXGI_MATRIX_3X2_F* pMatrix) final { return m_dispatch->SetMatrixTransform(pMatrix); } HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency( UINT MaxLatency) final { return m_dispatch->SetMaximumFrameLatency(MaxLatency); } HRESULT STDMETHODCALLTYPE SetSourceSize( UINT Width, UINT Height) final { return m_dispatch->SetSourceSize(Width, Height); } HRESULT STDMETHODCALLTYPE CheckColorSpaceSupport( DXGI_COLOR_SPACE_TYPE ColorSpace, UINT* pColorSpaceSupport) final { return m_dispatch->CheckColorSpaceSupport(ColorSpace, pColorSpaceSupport); } HRESULT STDMETHODCALLTYPE SetColorSpace1( DXGI_COLOR_SPACE_TYPE ColorSpace) final { return m_dispatch->SetColorSpace1(ColorSpace); } HRESULT STDMETHODCALLTYPE SetHDRMetaData( DXGI_HDR_METADATA_TYPE Type, UINT Size, void* pMetaData) final { return m_dispatch->SetHDRMetaData(Type, Size, pMetaData); } private: // m_device is not used or reference counted, provided for compatibility with mod engines // which expect to find device pointer in the memory after swapchain interface. IUnknown* m_device; IDXGISwapChain4* m_dispatch; }; }