Unreal Scoop: Making a “Compiling Shaders…” Screen

Unreal has a reputation amoung the ill-informed for being plagued by shader compilation stutter. As an attribute of Unreal itself, this is basically made up – devs are just not always doing what they are supposed to do pre-ship to avoid this issue. I’ll elaborate, but basically, to avoid compiling shaders during gameplay, you want to do it up-front, like during an initial loading screen, which maybe says “Compiling shaders” on it, and not let the player begin until it’s done. To do that last part properly, you need a little bit of C++. I had to do this for InFlux Redux recently, so here’s mine.

To sum up the problem in a simple, reductive way: Your game uses shaders. There are quite a lot of them. Shaders need to be compiled. You can’t ship the shaders already compiled because you don’t know what hardware the game is going to be running on (unless it’s a console, in which case Unreal does this automatically and you don’t need to know any of this). Compiling shaders takes time. In a bad case in an Unreal game, it goes like this:

  • You’re running around
  • You turn the camera, which reveals something you’ve never seen before – say, a rock
  • To draw that rock, we need a shader compiled
  • The engine goes “What? You need that rock shader? Ugh! This is the first I’m hearing about it! Why didn’t anyone tell me? Fuck it! We’ll do it live!”
  • We compile the shader, which we’re likely to feel as stutter. If this happens a lot, it sucks.

What you need to do is let the engine know up front all the shaders you’re going to need compiled – then it can compile them up front, and when you play and you see the rock, it’s fine, you had the shader ready. No stutter. That’s what this documentation page tells you how to do, and Tom Looman’s article on this is even more helpful.

Once you do that, and package a build, and the player launches it for the first time, if you let them start running around right away, it’s probably stuttery as hell for a little bit – it’s compiling every shader you’re going to need up-front. You want to not let the player play until that’s done. So! Make a loading screen widget, and keep the player looking at your loading screen until the shaders are compiled.

To know when the shaders are compiled, you need a little C++. It’s okay, we’re just making a simple Blueprint node. Use the “Add C++ To Project” menu option in the editor to make a Blueprint Function Library.

In the .h file:

UCLASS()
class YOURVIDEOGAME_API UYourFuncLib : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:

UFUNCTION(BlueprintCallable, Category = "Shaders")
static int32 NumShadersRemaining();
};

In the .cpp:

#include "YourFuncLib.h"
#include "ShaderPipelineCache.h"

int32 UYourFuncLib::NumShadersRemaining()
{
uint32 num;
num = FShaderPipelineCache::NumPrecompilesRemaining();
return num;
}

Also, you’ll need to add RenderCore to the list of dependencies in your build.cs file in Source/YourProject/YourProject.Build.cs.

Compile the project and you’ll have a new Blueprint node that returns how many shaders are left to be compiled. Tell your widget to close once that number is 0 for a few frames, and you’re good. This example just waits until it’s been half a second since this number wasn’t 0.

I also present the number to the player so they can get some sense of how long they have to wait. The number of shaders remaining sometimes jumps up, though, so some players are probably going to be more frustrated with it than without. You could always lie to them and just not change the text if the new value is greater. Fuck ’em, right.

Anyway, now the player gets a stutter-free experience! Assuming you built your PSO cache correctly. Which you did, right? Like we talked about?

I have a website with a lot more scoops like this called Unreal Scoops, by the way


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *