7
$\begingroup$

In PC game development, after loading models, textures, shaders, etc in a loading screen, some games will render the models once to an off screen target to make sure the driver and gpu have done all the work required to keep there from being a hitch the first time the models render.

Does anyone know how much that actually helps? Does it only affect certain cards and drivers?

$\endgroup$
2
  • $\begingroup$ Is this per-frame? As in a prepass to fill the depth buffer? $\endgroup$
    – geometrian
    Commented Oct 18, 2015 at 5:49
  • $\begingroup$ Nope, done in the loading screen. Not talking about a depth only render! $\endgroup$
    – Alan Wolfe
    Commented Oct 18, 2015 at 14:16

1 Answer 1

11
$\begingroup$

As far as I know, this sort of thing is mainly about shader compilation. One of the main reasons why a game may experience hitches the first time something renders is that the shaders necessary to render it haven't finished compiling yet, and the driver has to finish that work before the frame can proceed.

A little bit of background. When you write shaders in HLSL, you compile them with Microsoft's HLSL compiler (fxc.exe), which outputs a hardware-independent bytecode. When you call CreateVertexShader etc. in D3D, that bytecode gets passed to the underlying driver, which ultimately compiles it into the machine code for the specific GPU you're running on.

This internal compilation step isn't trivial—it's a full-blown optimizing compiler. So it can take a little while on a complicated shader. Because of this, when you call D3D's CreateVertexShader, the driver doesn't necessarily finish compiling the shader right then and there; it may add it to a queue, then return control to the application. Meanwhile, a background thread (perhaps more than one) consumes the queue and compiles the shaders. (The driver may also have a disk cache of previously-compiled shaders, so that it doesn't have to redo all this work every time the game is launched.)

This background-thread compilation means the main game thread can get on with other work, e.g. loading other data or building a scene graph or what-have-you, so it's generally a win for overall loading times. But the consequence of it is that the shaders may not all be finished compiling when the game starts rendering. Unfortunately, there is no way with DX11 and earlier APIs for the app to tell when the shaders are done. The best you can do is to render something with the shader—this effectively makes the app wait for the compiler to finish. That's why games sometimes do this offscreen pre-rendering business.

I don't have any hard numbers handy, but qualitatively, one can reduce the impact of shader compilation by front-loading it during loading. Create all your shaders first, then the compiler will run through those while you load everything else. However, with real-time streaming (e.g. open-world games) it can still be quite difficult to ensure no hitches.

It's also worth noting that there are some cases where state changes can cause a shader recompile. Things like vertex buffer formats, render target formats, and shader linking details (e.g. re-using the same pixel shader with different vertex shaders, or with tessellation shaders) can potentially cause the driver to have to generate different versions of the shader under the hood. The details vary by vendor and hardware. This isn't necessarily a full from-scratch recompile—often it's just sticking on some prologue or epilogue code—but it's something to be aware of.

This is one place where the new APIs (DX12, Metal, and Vulkan) are in a good position to solve the problem. These APIs have "pipeline state" objects where all shader stages and all possibly relevant states are rolled up into a single object, and when you create one of these, the driver has all the information it needs to actually and completely finalize all the shaders. DX12 also makes shader caching explicit. Also, at least for NVIDIA DX12 drivers (I don't know about others), shader compilation is done fully inside the pipeline state creation method, and the app can use multiple threads itself in order to parallelize shader compilation and other work. So, the practice of offscreen pre-rendering to ensure shaders are finalized should no longer be necessary in DX12.

$\endgroup$
1
  • $\begingroup$ A few years passed since this (excellent) answer, and one can find that this shift of hitches from the first drawcall to pipeline state creation wasn't a silver bullet either, because the game may not know all the state in advance (especially a highly varied / moddable game) to create it early enough... $\endgroup$
    – RCL
    Commented Apr 22, 2020 at 3:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.