- I’ve integrated DLSS, FSR, and XeSS into the same project. However, they don’t work together because they require overriding the swapchain.
- I’ve tried my best to implement runtime swapchain switching, and everything works fine. It’s possible to change frame generation at runtime without a restart.
- However, if external software references the swapchain, such as some software that overlaps frame rates (like GamePP), it will 100% cause a crash.
- Another solution is to rebuild the entire window. But everything reference game window. How can I safely recreate the window at runtime? Is this a bad idea?
I would love to know the answer to this question, since I’m dealing with the same issues. Can you provide any details on how you implemented runtime swapchain switching?
Sorry for the late reply.
You need a source-built engine. Switching the swapchain at runtime requires modifying the engine source code and frame generation solutions (such as DLSS, FSR and XeSS).
The following discussion of modifications is for DX12 only.
How to use a specific frame generation
- UE provides a mechanism (swapchain provider) to customize the swapchain.
- All frame generation solutions use this mechanism. By default, UE will choose the first compatible one.
- You need a global variable to specify which swapchain provider to use. You can refer to the FD3D12Viewport::Init function for details.
- They also provide implement of IMaxTickRateHandlerModule, which also need to be handled accordingly; refer to UEngine::UpdateTimeAndHandleMaxTickRate.
How to switch frame generation at runtime
- On the game thread, force complete all task in the render thread and the RHI thread.
- Release all references to the swapchain. Call FD3D12Viewport::Init again to recreate the swapchain. You cannot recreate the swapchain without releasing all references. Because of this mechanism, you can simply test whether all references have been released.
- Note that the frame interpolation solutions also reference the swapchain and maintained some of internal state.
Thanks for the reply.
That’s pretty similar to the approach I’m attempting. I think I haven’t found all the references to the swapchain when I try to recreate with FD3D12Viewport::Init.
Do you recall if you also needed to release references to the backbuffer render targets, and recreate those too?
- Yes, the back buffer needs to be disposed.
- In addition, you should also call ClearPresentQueue, FlushRenderingCommands, and FD3D12Adapter::BlockUntilIdle. These functions are also called in the implementation of FD3D12Viewport::Resize. The Recreation of swapchain shoud do same thing as FD3D12Viewport::Resize. This is not a frequent operation, so doing extra flushes doesn’t have much impact.
- If you are using XeSS, the XeFGSwapChainContext inside XeFGRHI also references the swapchain.
- If you switch from DLSS to FSR and then back to DLSS, you may find that DLSS doesn’t work. This is because DLSS by default only creates one swapchain, so you need to carefully handle the internal data.