How would I hook into the rendering pipeline that calls a plugin method “right before” SwapChain.Present is called?
I need to do some very low level D3D11 timing stuff before and after the SwapChain.Present method is called.
Right now I’m making a hooking Launcher to do this but if UE4 already exposes the methods needed I would like to discard the Launcher in favor of a plugin.
It depends: do you want to do it in a pure plugin or is modifying the engine code OK?
For a plugin, have a look at FRHICustomPresent (RHIResources.h). You can get the viewport and call SetCustomPresent(this), which will make your Present() function the one that gets called instead of the IDXGISwapChain one. This is how the VR plugins do their rendering work, so you can have a look at those for examples.
If you literally just want change the engine to do something before present gets called, open D3D11Viewport.cpp and put whatever stuff you like in FD3D11Viewport::PresentChecked()
Ok awesome, FRHICustomPresent is what I need then.
Would this allow me to disable presenting the swapchain backbuffer in the UE4 game window and only present in a DirectMode only device? (In short, the same as hooking the D3D11 swapChain present method?)
BTW, off the top of your head do you know if the D3D11 SwapChain method being used is “Present1” or the classic “Present” method?
I’m interested because to optimize non-DirectMode Mirroring with two swap-chains I need to be using “Present1” in UE4 game window and the extended/hmd window.
One last question. Is it possible to overload the “D3D11CreateDevice” method in UE4? DirectMode typically gets the “IDXGIAdapter” the device is created with thus NVAPI methods must be invoked first.
It’s IDXGISwapChain and Present, not IDXGISwapChain1/Present1. Hope that doesn’t ruin your plans…
You can get raw pointers to both the swapchain and backbuffer with FD3D11Viewport::GetSwapChain() and FD3D11Viewport::GetBackBuffer(), though I don’t know what happens when you start messing with them. But you have the ability to override Present as well with FRHICustomPresent, so that might be enough for your needs.
D3D11CreateDevice is done in FD3D11DynamicRHI::InitD3DDevice() which isn’t overridable/customizable. There is a bit of a loophole though: the adapter index that gets chosen can be provided by an HMD plugin module. Relevant code:
int32 HmdGraphicsAdapter = IHeadMountedDisplayModule::IsAvailable() ? IHeadMountedDisplayModule::Get().GetGraphicsAdapter() : -1;
bool bUseHmdGraphicsAdapter = HmdGraphicsAdapter >= 0;
// rest of adapter enumeration here
Thus you can influence the index of the adapter that gets chosen, but not give a pointer to it. I believe what e.g. Oculus does is register their HMD as an adapter and then return the index to that one.
Is there any reason UE4 couldn’t be updated to use the newer IDXGISwapChain1 object? Unity3D is using this object but only calling Present on it (I did hooking to verify).
This issue isn’t to bad right now as I have DirectMode working but I’m interested to know if there is a reason the newer IDXGISwapChain1 isn’t being used.
On the topic of “IHeadMountedDisplayModule::Get().GetGraphicsAdapter()” this only gets not sets what Display the UE4 game window goes to.
Is there a option to select what display I want my game window to open in? This has been an issue for us as there doesn’t seem to be any command options like Unity has (aka -adapter <MyIndex>).
Also while you have my ear, I would like to point out a BUG in 4.11 idk about 4.12 yet but “GSystemResolution.ResX and GSystemResolution.ResY” report the WRONG resolution of the Editor VR game window the FIRST time you call them in the “OnBeginPlay” method in a “IHeadMountedDisplay” plugin. This forces me to create an over-sized backbuffer for our distortion mesh in the Editor when we run in what I call Embedded mode (showing the distortion in the Game window). We have special situation where this is useful in Unity but this method can’t be used in UE4 as it doesn’t support Display selection?
Hehe, you seem to be taking me for someone “in the know” I’m just a guy with too much time on his hands. I’m far from an expert on rendering (though I did write a hello world triangle in OpenGL once).
One thing I forgot to mention, there’s an r.GraphicsAdapter console/.ini cvar which has the same effect as setting the adapter index with a plugin. However the HMD adapter takes precedence if there is one. Also, as far as I know there is no way to specify cvars on the command line (there are lots of command line options including the ability to override ini filenames, but not the settings themselves). Definitely a major shortcoming of UE IMO.
As to why UE4 isn’t using Present1? Your guess is as good as mine. I thought it might be for backwards compatibility with older Windows versions, but the D3D12 RHI also uses Present.
GetGraphicsAdapter() does indeed get the adapter, not set it, hence the name But you can obviously make your plugin inherit from IHeadMountedDisplayModule and provide whatever value you want. The final D3D11CreateDevice call still gets done by the RHI though.
Nope. Hope someone proves me wrong. There is -ResX and -ResY, which I often use to put the log console on my second monitor (-ResX=1920). But it doesn’t seem to work for the game/editor.
As for your bug, I can’t really help you with that. There’s FDisplayMetrics which works perfectly to get the fullscreen resolutions of all connected monitors, but it wouldn’t work to get the size of the game area if it’s in windowed mode. The best I can come up with is to register a CVar sink with IConsoleManager for the r.setres variable. That way you’ll be notified when the window resolution changes.
Were you guys able to get this to work? My RHIViewport is null everywhere except when i get it via the Slate Renderer, and even then when i try to call SetCustomPresent, it is throwing an exception when called from the game thread, render thread, or via a timer after some time after startup.