Using FShaderCache on GearVR

Hi,

I’m working on improving the framerate of a GearVR game that suffers from many hitches whenever the environment changes or a new object appears in the player’s field of view. The profiler shows that this is caused by OpenGL compiling and linking the shaders for the objects that just appeared.

I’d like to use Unreal Engine’s Shader Cache feature to solve that, but I’m not sure how to use the various console commands.

Our game uses OpenGL ES3.1. It contains only a few environments and doesn’t use level streaming, so ideally I’d like the engine to pre-compile all useful shaders during loadings, instead of at first use.

From what I read in the documentation I imagined I would proceed like this:

  • enabling r.UseShaderCaching and r.UseShaderDrawLog in Development Android builds of the game
  • playing through the entire game on the device to populate the cache
  • locating the shader cache file on the device and moving it to the development PC inside the Content directory.
  • enabling r.UseShaderCaching and r.UseShaderPredraw in final builds of the game
  • checking that shader-related hitches are gone.

However, I ran in to several problems.

On 4.17:

  • I found no easy way to get the mobile application to save the shader cache file on the sdcard. As we use the Launcher version of the engine, I ended up calling FShaderCache::ShutdownShaderCache() from game code, which triggers a save, then crashes the game.
  • launching the game with r.UseShaderCaching and r.UseShaderPredraw enabled crashes at startup in FShaderCache::InternalLogSamplerState(). This has been reported here: Unreal Engine Issues and Bug Tracker (UE-47553)

On 4.18 preview 4:

  • reading through the code, I can see that two console variables are overriden in FShaderCache’s constructor, so I’m not sure how the shader cache is supposed to work anymore:

      if (IsMobilePlatform(CurrentPlatform))
      {
      	// Make sure this is disabled on mobile
      	// Mobile only needs FShaderCache::bUseShaderCaching
      	FShaderCache::bUseShaderPredraw = 0;
      	FShaderCache::bUseShaderDrawLog = 0;
      }
    

What workflow would you suggest to use the shader cache on Android?

Thanks,

I’ve noticed this as well and would really appreciate a way to remove those hitches!

OK, I’ve learned a bit more.

On 4.18 preview 4, running the GearVR game with only r.UseShaderCaching enabled by default does create a shader cache file on the sdcard. When running the game a second time with the same configuration, I could notice the large hitches were gone. So it seems the caching mechanism worked and the shaders were compiled at load-time rather than on the fly!

I’m still puzzled, though: if I was able to populate and then use a shader cache using neither r.UseShaderDrawLog nor r.UseShaderPredraw, does it mean that on mobile logging and pre-draw are always active, as soon as r.UseShaderCaching is on?

The CPU cost of draw calls is really huge on GearVR, so I really don’t want the shipping version of the game paying the overhead associated with updating the shader cache every draw.

Thanks for sharing your findings, Julien. We’re also having the same issue on GearVR.

We found that running the game with r.UseShaderDrawLog=1 causes the game to shutdown/silently crash at startup (it barely passes the android initialization phase). There is no crash dump in the android log output either, which is quite odd. We’re still trying to figure this one out.

We make use of a separate engine system via the setting r.UseProgramBinaryCache=1 (see FOpenGLProgramBinaryCache::Initialize()). This properly caches the compiled shaders and removes the hitches on subsequent runs of the game. However, it does not solve the hitch that happens on “first encounter” when the shader
actually gets compiled for the first time at runtime. So this is still not a complete solution for us either.

We looked into reusing the output of this binary shader cache but it’s dependent on GPU & driver version (the filename is hashed on GL_VERSION + GL_RENDERER) so including these in the final build is not a sensible solution either (it will work only for the device+driver combinations that you have included, and will most likely break when the game is run on newer devices or driver updates).

The OpenGLProgramBinaryCache also seems to be a completely separate system from the FShaderCache mentioned above, which seems to have first been developed and tested for Mac. My guess is that it hasn’t been fully tested on Mobile/GearVR yet (we’re sitll on 4.17 though, so maybe that’s changed in 4.18).

We’re currently in touch with Epic regarding this issue so I will update this thread once we have more information.

The new 4.18 release has a fix for the issues above and worked well for us. See Epic’s CL 3612145.

So how do we get rid of the initial hitches on first play in 4.18?

Am I correct in saying the steps are as follows?:

  • enabling r.UseShaderCaching in Development Android builds of the game
  • playing through the entire game on the device to populate the cache
  • locating the shader cache file on the device and moving it to the development PC inside the Content directory.
  • enabling r.UseShaderCaching and r.UseShaderPredraw in final builds of the game
  • rebuild game in Shipping (hoping this cache file is included in the final APK)

Are there any other steps or commands required?

EDIT: tested this myself and it does indeed work as expected!! Thankyou for sharing this information :slight_smile:

Epic should really make this setting easier to find like having it in the project settings (or is it already?)