Browse Source

WIP experiments

swapchain
Nico de Poel 9 months ago
parent
commit
abfd3eba09
  1. 44
      src/FSR3UnityPlugin.cpp
  2. 45
      src/SwapChainTrampoline.cpp

44
src/FSR3UnityPlugin.cpp

@ -198,26 +198,28 @@ static void TestSwapChainStuff()
}
SwapChainTrampoline trampoline(swapChain4);
memcpy(swapChain4, &trampoline, sizeof(IDXGISwapChain4));
//IDXGIFactory2* dxgiFactory;
//hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
//if (!SUCCEEDED(hr))
//{
// UNITY_LOG_ERROR(s_Log, "Could not create DXGI Factory :(");
// return;
//}
//// TODO: may need to do this from an event with kUnityD3D12GraphicsQueueAccess_Allow, to allow access to GetCommandQueue()
//IDXGISwapChain1* replacementSwapChain;
//hr = dxgiFactory->CreateSwapChainForHwnd(s_GraphicsD3D12->GetCommandQueue(), hwnd, &swapChainDesc, fullscreen ? &fullScreenDesc : nullptr, nullptr, &replacementSwapChain);
//if (!SUCCEEDED(hr))
//{
// std::stringstream ss;
// ss << "Could not create replacement swapchain, error code = " << hr;
// UNITY_LOG_ERROR(s_Log, ss.str().c_str());
// return;
//}
//memcpy(swapChain4, &trampoline, sizeof(IDXGISwapChain4));
// This successfully destroys Unity's original swapchain, allowing a new one to be created below. Now to swap them out...
while (swapChain4->Release());
IDXGIFactory2* dxgiFactory;
hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
if (!SUCCEEDED(hr))
{
UNITY_LOG_ERROR(s_Log, "Could not create DXGI Factory :(");
return;
}
IDXGISwapChain1* replacementSwapChain;
hr = dxgiFactory->CreateSwapChainForHwnd(s_GraphicsD3D12->GetCommandQueue(), hwnd, &swapChainDesc, fullscreen ? &fullScreenDesc : nullptr, nullptr, &replacementSwapChain);
if (!SUCCEEDED(hr))
{
std::stringstream ss;
ss << "Could not create replacement swapchain, error code = " << hr;
UNITY_LOG_ERROR(s_Log, ss.str().c_str());
return;
}
}
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
@ -329,7 +331,7 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
s_Upscaler->InitFeature(initData);
break;
}
case BaseEventId + FSR3PluginEvent::eSwapChain:
case FSR3PluginEvent::eSwapChain:
TestSwapChainStuff();
break;
}

45
src/SwapChainTrampoline.cpp

@ -1,17 +1,56 @@
#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));
//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
@ -19,6 +58,10 @@ SwapChainTrampoline::SwapChainTrampoline(IDXGISwapChain4* 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)

Loading…
Cancel
Save