Lot of frame drops but weirdly only on first app run

My scene is relatively complex, probably loading about 500MB worth of meshes/textures. On the first time the app is run after install, I see noticeable FPS drops and screen tearing . Weirdly, if I quit out or if the app crashes, the next time I run it, it runs perfectly fine. I have replicated this across 10+ installs. Is there something that unity is doing on the first time the app is being run that causes these frame drops? The other weird thing is I have a fps counter and I can see it’s relatively stable ~55fps or so.
If I remove all the objects from the scene I don’t see the frame drops.

wonder if it’s due to shaders compiling on first run?

@mtschoen any ideas here? it’s a pretty uncomfortable experience for our users on the first run.

Yeah, this is a weird one. Have you tried using a super lightweight scene as a buffer between engine startup and loading your first scene? If you just show a fully black scene or maybe a lightweight logo in an otherwise empty environment for a few seconds, these load times can be spread out. Without access to your project it will be very difficult to nail down the cause here. Could be shader warmup, could be scripting initializers, could be any number of things…

If you aren’t able to share your full project, any project that replicates the issue will help. Short of that, can you make a development build and auto-attach the profiler? Seeing what it reports on that first long frame would be my first step.

Will share via DM. we tried a loading screen actually - FPS is totally fine in loading screen, but drops a lot/screen tears once the main map is loaded.

This definitely sounds like shader compilation to me, we have had to do a lot of custom work to get the shader prewarming done in a way that doesn’t totally break down / crash our app on the first time.

Do you have any resources to set this up? Tried to do this but gave up on it

The shaders thing seems likely. Do you have any thoughts? Is this a known issue?

hey @Zach_AtTRIPP,
Tried doing shader prewarming.
Steps I took.
Play through as much of the scene as possible in editor
Use the currently tracked shaders functionality to group all the shaders into a .shadervariants
Add shadervariants to preloaded shaders list

This doesn’t seem to work. I still get the stutters first time I view something. Am I missing a step here?

Likely shader compilation.

We are using an additive scene loader with a lightweight scene at launch, and if we do have a crash it happens because shaders are not preloaded and VisionOS kills the app after 2 seconds:

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: <0x27> 0 

Triggered by Thread:  0
...

7   UnityFramework                	0x0000000106d0cb0c WaitForSignal + 8 (Semaphore.h:23)
8   UnityFramework                	0x0000000106d0cb0c GfxDeviceClient::CreateGpuProgram(ShaderGpuProgramType, dynamic_array<unsigned char, 0ul> const&, CreateGpuProgramOutput&) + 372 (GfxDeviceClient.cpp:1031)
9   UnityFramework                	0x0000000106bde2a4 ShaderLab::SubProgram::Compile(ShaderLab::CompilationData&) + 988 (ShaderProgram.cpp:314)

...

Hopefully this will be improved in https://portal.productboard.com/unity/77-unity-visionos-roadmap/c/2393-performance-improvements

Is there a good way to reduce the shader compilation overhead?
Can it be moved to another thread?

The short answer (I think) is no, not on your end. I still need to do some more investigating with @softmango’s project, but I don’t have much to share at this point. Other than reducing the number of shaders/variants that need to be built, I don’t think you have control over how long we spend doing this work on the main thread. We’re investigating solutions and will report back as soon as we have something to share.

I have two noob-level questions:

  1. If you’re only targeting one kind of hardware, ie Metal + M2, why can’t you ship the app with precompiled shaders?
  2. Why does unity not have a simple option to compile shaders in scene and not show scene before it’s done to prevent stutters? I assume that’s what shader prewarming is in theory doing, but maybe I’m just doing it wrong.

We implemented a very manual but general solution. It basically crawls for Renderer / Mesh combinations and then iterates over that list, displaying it briefly (small and far away as to not really be visible). You need to also make sure things like fog and lighting are as similar as possible as to when it shows up later in your project to compile the correct shader variant. It is super manual, clunky, and not perfect but it does help the first time user experience… The experimental apis were not functioning well and would crash the app (ShaderWarmup.WarmupShader …)

At what point during the scene load are you crawling for Renderer / Mesh combinations?
Are you using additive scene loading?

Our solution is pretty bespoke as we are loading in experiences via Asset Bundles, and then have essentially lists of objects that get loaded in for that particular experience. What you could do is have all of the objects in your scene in a deactivated state, crawl those objects for renderers and warm those up one at a time with a custom on screen drawing solution (small, far away, etc) We were doing this on our first pass and it worked pretty well. It would need to happen after the scene is loaded so you have scene graph / objects in the scene.

@mtschoen Is there an update on the ETA for this fix for shader prewarming?

No specific ETA, but I think we have a solution in flight. I’ve been pretty backlogged with other bugs, but I should be able to test this out soon and get the gears turning again. In the meantime, I’ve shared a potential workaround in another thread for shutting down the compositor during long running processes like shader warmup, which may help you to mitigate the issue. I understand that this is not ideal, but it may unblock you in the short term while we work on addressing the shader warmup issue specifically.

Thanks for your patience, and hope this helps!