Compare commits
merge into: ndepoel:master
ndepoel:fsr2
ndepoel:master
ndepoel:swapchain
pull from: ndepoel:swapchain
ndepoel:fsr2
ndepoel:master
ndepoel:swapchain
4 Commits
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
818c146f08 |
Merge branch 'master' into swapchain
# Conflicts: # src/FSR3UnityPlugin.cpp |
6 days ago |
|
|
abfd3eba09 |
WIP experiments
|
9 months ago |
|
|
97e220af24 |
Merge branch 'master' into swapchain
# Conflicts: # src/FSR3UnityPlugin.cpp # src/FSR3UnityTypes.h |
10 months ago |
|
|
22a3c6f6d5 |
Swapchain experiments
|
10 months ago |
6 changed files with 466 additions and 2 deletions
-
4FSR3UnityPlugin.vcxproj
-
6FSR3UnityPlugin.vcxproj.filters
-
92include/SwapChainTrampoline.h
-
93src/FSR3UnityPlugin.cpp
-
3src/FSR3UnityTypes.h
-
270src/SwapChainTrampoline.cpp
@ -0,0 +1,92 @@ |
|||
#pragma once |
|||
|
|||
#include <d3d12.h> |
|||
#include <dxgi1_5.h> |
|||
|
|||
class SwapChainTrampoline : public IDXGISwapChain4 |
|||
{ |
|||
public: |
|||
SwapChainTrampoline(IDXGISwapChain4* swapChain); |
|||
|
|||
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) override; |
|||
|
|||
ULONG __stdcall AddRef(void) override; |
|||
|
|||
ULONG __stdcall Release(void) override; |
|||
|
|||
HRESULT __stdcall SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) override; |
|||
|
|||
HRESULT __stdcall SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) override; |
|||
|
|||
HRESULT __stdcall GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) override; |
|||
|
|||
HRESULT __stdcall GetParent(REFIID riid, void** ppParent) override; |
|||
|
|||
HRESULT __stdcall GetDevice(REFIID riid, void** ppDevice) override; |
|||
|
|||
HRESULT __stdcall Present(UINT SyncInterval, UINT Flags) override; |
|||
|
|||
HRESULT __stdcall GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) override; |
|||
|
|||
HRESULT __stdcall SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) override; |
|||
|
|||
HRESULT __stdcall GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) override; |
|||
|
|||
HRESULT __stdcall GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) override; |
|||
|
|||
HRESULT __stdcall ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) override; |
|||
|
|||
HRESULT __stdcall ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) override; |
|||
|
|||
HRESULT __stdcall GetContainingOutput(IDXGIOutput** ppOutput) override; |
|||
|
|||
HRESULT __stdcall GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) override; |
|||
|
|||
HRESULT __stdcall GetLastPresentCount(UINT* pLastPresentCount) override; |
|||
|
|||
HRESULT __stdcall GetDesc1(DXGI_SWAP_CHAIN_DESC1* pDesc) override; |
|||
|
|||
HRESULT __stdcall GetFullscreenDesc(DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) override; |
|||
|
|||
HRESULT __stdcall GetHwnd(HWND* pHwnd) override; |
|||
|
|||
HRESULT __stdcall GetCoreWindow(REFIID refiid, void** ppUnk) override; |
|||
|
|||
HRESULT __stdcall Present1(UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) override; |
|||
|
|||
BOOL __stdcall IsTemporaryMonoSupported(void) override; |
|||
|
|||
HRESULT __stdcall GetRestrictToOutput(IDXGIOutput** ppRestrictToOutput) override; |
|||
|
|||
HRESULT __stdcall SetBackgroundColor(const DXGI_RGBA* pColor) override; |
|||
|
|||
HRESULT __stdcall GetBackgroundColor(DXGI_RGBA* pColor) override; |
|||
|
|||
HRESULT __stdcall SetRotation(DXGI_MODE_ROTATION Rotation) override; |
|||
|
|||
HRESULT __stdcall GetRotation(DXGI_MODE_ROTATION* pRotation) override; |
|||
|
|||
HRESULT __stdcall SetSourceSize(UINT Width, UINT Height) override; |
|||
|
|||
HRESULT __stdcall GetSourceSize(UINT* pWidth, UINT* pHeight) override; |
|||
|
|||
HRESULT __stdcall SetMaximumFrameLatency(UINT MaxLatency) override; |
|||
|
|||
HRESULT __stdcall GetMaximumFrameLatency(UINT* pMaxLatency) override; |
|||
|
|||
HANDLE __stdcall GetFrameLatencyWaitableObject(void) override; |
|||
|
|||
HRESULT __stdcall SetMatrixTransform(const DXGI_MATRIX_3X2_F* pMatrix) override; |
|||
|
|||
HRESULT __stdcall GetMatrixTransform(DXGI_MATRIX_3X2_F* pMatrix) override; |
|||
|
|||
UINT __stdcall GetCurrentBackBufferIndex(void) override; |
|||
|
|||
HRESULT __stdcall CheckColorSpaceSupport(DXGI_COLOR_SPACE_TYPE ColorSpace, UINT* pColorSpaceSupport) override; |
|||
|
|||
HRESULT __stdcall SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) override; |
|||
|
|||
HRESULT __stdcall ResizeBuffers1(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT Format, UINT SwapChainFlags, const UINT* pCreationNodeMask, IUnknown* const* ppPresentQueue) override; |
|||
|
|||
HRESULT __stdcall SetHDRMetaData(DXGI_HDR_METADATA_TYPE Type, UINT Size, void* pMetaData) override; |
|||
}; |
|||
@ -0,0 +1,270 @@ |
|||
#include "SwapChainTrampoline.h"
|
|||
|
|||
#include <iostream>
|
|||
|
|||
// There can be ever only one swap chain per window, so it's safe to make this a singleton
|
|||
static IDXGISwapChain4* s_SwapChain = nullptr; |
|||
|
|||
typedef HRESULT(__stdcall IDXGISwapChain4::*PFN_QueryInterface)(REFIID riid, void** ppvObject); |
|||
PFN_QueryInterface pfQueryInterface = nullptr; |
|||
|
|||
template <class T> |
|||
intptr_t SeeBits(T func) |
|||
{ |
|||
union |
|||
{ |
|||
T ptr; |
|||
intptr_t i; |
|||
}; |
|||
ptr = func; |
|||
|
|||
return i; |
|||
} |
|||
|
|||
template <class T, class F> |
|||
size_t FindFunctionOffset(T* obj, F func) |
|||
{ |
|||
intptr_t* vtable = *(intptr_t**)obj; |
|||
int cnt = 42;// sizeof(T) / sizeof(intptr_t);
|
|||
|
|||
intptr_t funcBits = SeeBits(func); |
|||
|
|||
for (size_t offs = 0; offs < cnt; ++offs) |
|||
{ |
|||
if (vtable[offs] == funcBits) |
|||
return offs; |
|||
} |
|||
|
|||
return 0u; |
|||
} |
|||
|
|||
SwapChainTrampoline::SwapChainTrampoline(IDXGISwapChain4* swapChain) |
|||
{ |
|||
s_SwapChain = swapChain; |
|||
// TODO: copy the original swap chain's vtable (sizeof IDXGISwapChain4), then somehow call the virtual methods in that vtable using the this-pointer from ourselves...
|
|||
|
|||
//pfQueryInterface = (PFN_QueryInterface)((intptr_t)swapChain + reinterpret_cast<intptr_t>(&SwapChainTrampoline::QueryInterface));
|
|||
|
|||
/*intptr_t pfQueryInterfaceOffset = SeeBits(&SwapChainTrampoline::QueryInterface);
|
|||
intptr_t pfPresentOffset = SeeBits(&SwapChainTrampoline::Present);*/ |
|||
intptr_t pfQueryInterfaceOffset = FindFunctionOffset(this, &SwapChainTrampoline::QueryInterface); |
|||
intptr_t pfPresentOffset = FindFunctionOffset(this, &SwapChainTrampoline::Present); |
|||
|
|||
std::cout << "QueryInterface: " << pfQueryInterfaceOffset << ", Present: " << pfPresentOffset << std::endl; |
|||
|
|||
// IDEA: we could replace the original swap chain's vtable entries one-by-one with regular function pointers, including a this-pointer argument
|
|||
// Unity will then give us the this-pointer we require, no need to globally store it here
|
|||
// (We might not even require the this-pointer in the long run anyway, since we'll be forwarding to the FG swapchain)
|
|||
// Then forward the call to the original vtable function, reusing that this-pointer where necessary
|
|||
// Only thing we really need to know for sure: the offset in the vtable of each virtual function
|
|||
// This doesn't feel like it would work but try it anyway: https://stackoverflow.com/questions/5590015/detect-the-the-vtable-offset-of-a-specific-virtual-function-using-visual-c/5590181
|
|||
|
|||
// TODO: might also be able to do something with IDXGIObject::Get/SetPrivateData
|
|||
|
|||
// TODO: not sure if any of this is really necessary? If we can destroy the original swap chain, construct a new one through FFX, then plug that in here, we're already done right?
|
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::QueryInterface(REFIID riid, void** ppvObject) |
|||
{ |
|||
return s_SwapChain->QueryInterface(riid, ppvObject); |
|||
} |
|||
|
|||
ULONG __stdcall SwapChainTrampoline::AddRef(void) |
|||
{ |
|||
return s_SwapChain->AddRef(); |
|||
} |
|||
|
|||
ULONG __stdcall SwapChainTrampoline::Release(void) |
|||
{ |
|||
return s_SwapChain->Release(); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) |
|||
{ |
|||
return s_SwapChain->SetPrivateData(Name, DataSize, pData); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) |
|||
{ |
|||
return s_SwapChain->SetPrivateDataInterface(Name, pUnknown); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) |
|||
{ |
|||
return s_SwapChain->GetPrivateData(Name, pDataSize, pData); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetParent(REFIID riid, void** ppParent) |
|||
{ |
|||
return s_SwapChain->GetParent(riid, ppParent); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetDevice(REFIID riid, void** ppDevice) |
|||
{ |
|||
return s_SwapChain->GetDevice(riid, ppDevice); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::Present(UINT SyncInterval, UINT Flags) |
|||
{ |
|||
return s_SwapChain->Present(SyncInterval, Flags); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) |
|||
{ |
|||
return s_SwapChain->GetBuffer(Buffer, riid, ppSurface); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) |
|||
{ |
|||
return s_SwapChain->SetFullscreenState(Fullscreen, pTarget); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) |
|||
{ |
|||
return s_SwapChain->GetFullscreenState(pFullscreen, ppTarget); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) |
|||
{ |
|||
return s_SwapChain->GetDesc(pDesc); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) |
|||
{ |
|||
return s_SwapChain->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) |
|||
{ |
|||
return s_SwapChain->ResizeTarget(pNewTargetParameters); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetContainingOutput(IDXGIOutput** ppOutput) |
|||
{ |
|||
return s_SwapChain->GetContainingOutput(ppOutput); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) |
|||
{ |
|||
return s_SwapChain->GetFrameStatistics(pStats); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetLastPresentCount(UINT* pLastPresentCount) |
|||
{ |
|||
return s_SwapChain->GetLastPresentCount(pLastPresentCount); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetDesc1(DXGI_SWAP_CHAIN_DESC1* pDesc) |
|||
{ |
|||
return s_SwapChain->GetDesc1(pDesc); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetFullscreenDesc(DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) |
|||
{ |
|||
return s_SwapChain->GetFullscreenDesc(pDesc); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetHwnd(HWND* pHwnd) |
|||
{ |
|||
return s_SwapChain->GetHwnd(pHwnd); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetCoreWindow(REFIID refiid, void** ppUnk) |
|||
{ |
|||
return s_SwapChain->GetCoreWindow(refiid, ppUnk); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::Present1(UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) |
|||
{ |
|||
return s_SwapChain->Present1(SyncInterval, PresentFlags, pPresentParameters); |
|||
} |
|||
|
|||
BOOL __stdcall SwapChainTrampoline::IsTemporaryMonoSupported(void) |
|||
{ |
|||
return s_SwapChain->IsTemporaryMonoSupported(); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetRestrictToOutput(IDXGIOutput** ppRestrictToOutput) |
|||
{ |
|||
return s_SwapChain->GetRestrictToOutput(ppRestrictToOutput); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetBackgroundColor(const DXGI_RGBA* pColor) |
|||
{ |
|||
return s_SwapChain->SetBackgroundColor(pColor); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetBackgroundColor(DXGI_RGBA* pColor) |
|||
{ |
|||
return s_SwapChain->GetBackgroundColor(pColor); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetRotation(DXGI_MODE_ROTATION Rotation) |
|||
{ |
|||
return s_SwapChain->SetRotation(Rotation); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetRotation(DXGI_MODE_ROTATION* pRotation) |
|||
{ |
|||
return s_SwapChain->GetRotation(pRotation); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetSourceSize(UINT Width, UINT Height) |
|||
{ |
|||
return s_SwapChain->SetSourceSize(Width, Height); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetSourceSize(UINT* pWidth, UINT* pHeight) |
|||
{ |
|||
return s_SwapChain->GetSourceSize(pWidth, pHeight); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetMaximumFrameLatency(UINT MaxLatency) |
|||
{ |
|||
return s_SwapChain->SetMaximumFrameLatency(MaxLatency); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetMaximumFrameLatency(UINT* pMaxLatency) |
|||
{ |
|||
return s_SwapChain->GetMaximumFrameLatency(pMaxLatency); |
|||
} |
|||
|
|||
HANDLE __stdcall SwapChainTrampoline::GetFrameLatencyWaitableObject(void) |
|||
{ |
|||
return s_SwapChain->GetFrameLatencyWaitableObject(); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetMatrixTransform(const DXGI_MATRIX_3X2_F* pMatrix) |
|||
{ |
|||
return s_SwapChain->SetMatrixTransform(pMatrix); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::GetMatrixTransform(DXGI_MATRIX_3X2_F* pMatrix) |
|||
{ |
|||
return s_SwapChain->GetMatrixTransform(pMatrix); |
|||
} |
|||
|
|||
UINT __stdcall SwapChainTrampoline::GetCurrentBackBufferIndex(void) |
|||
{ |
|||
return s_SwapChain->GetCurrentBackBufferIndex(); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::CheckColorSpaceSupport(DXGI_COLOR_SPACE_TYPE ColorSpace, UINT* pColorSpaceSupport) |
|||
{ |
|||
return s_SwapChain->CheckColorSpaceSupport(ColorSpace, pColorSpaceSupport); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) |
|||
{ |
|||
return s_SwapChain->SetColorSpace1(ColorSpace); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::ResizeBuffers1(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT Format, UINT SwapChainFlags, const UINT* pCreationNodeMask, IUnknown* const* ppPresentQueue) |
|||
{ |
|||
return s_SwapChain->ResizeBuffers1(BufferCount, Width, Height, Format, SwapChainFlags, pCreationNodeMask, ppPresentQueue); |
|||
} |
|||
|
|||
HRESULT __stdcall SwapChainTrampoline::SetHDRMetaData(DXGI_HDR_METADATA_TYPE Type, UINT Size, void* pMetaData) |
|||
{ |
|||
return s_SwapChain->SetHDRMetaData(Type, Size, pMetaData); |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue