Sharing the fix, because the problem might be really widespread.
I have a few relatively powerful PCs at home (6-core i7 & 24-core Ryzen Threadripper 3960x), and as I conclude now, both of them suffered from FPS drop on intense parts of songs while running Beat Saber.
Note that FPS drop on Oculus headsets isn’t perceived as strongly as you’d expect due to Asynchronous Spacewrap (AWS), so there is a good chance you don’t know you have the same issue — even if you are absolutely sure you know how FPS drop looks like. E.g. my fair amount of experience with Beat Saber didn’t help much. I noticed something is really off only when I switched to Ryzen 3960x-based dual GPU machine a few days ago — it was reasonable to expect a completely smooth Beat Saber experience there, but in fact, it was perceptually worse than on Oculus Quest (which is way less powerful). So I ended up digging into this and discovered the following:
- Yes, I get 80 FPS (i.e. exactly what’s expected on Oculus Rift S), but half of these frames are provided by ASW most of the time — i.e. basically, they are interpolated.
- And that’s despite both CPU and GPU load is around 8% or so!
- Yes, ASW is consistently on.
- Compositor timings are tiny (sub-1ms), which explains tiny GPU load.
- But application render timings are huge: 15ms+ most of the time on intense songs, which is way more than ~ 10ms you need on this stage to have 80 FPS.
- And that’s the reason ASW is on: the application is almost always unable to submit the frame data to the compositor in time.
So the CPU is to blame. But how, if that’s a 24-core monster? Moreover, the game runs smoothly on Oculus Quest delivering ~ same 75 FPS there relying on Snapdragon 835 with its ~ 3.5W of total power consumption. And somehow Ryzen 3960x consuming 6..13W per core is not enough for it. Really?
Luckily, my very first rain dance (apparently, experience matters even if you do a rain dance!) in an attempt to address this brought exactly what I needed:
- You need to pin Beat Saber process to 4 different physical cores; “physical” means you shouldn’t pin it to the virtual/hyperthreaded cores sharing the same physical hardware. That’s nearly how it should look in Task Manager:
- In addition, it makes sense to set the priority of Beat Saber process to High.
Overall, this workaround drops application timings from 15–17ms to 2.2–2.7ms in my case, i.e. allows the game to render ~ up to 400 FPS.
I experimented with a few different options for CPU affinity, and:
- App timings are the smallest ones when you pin the process to 2..4 different physical cores.
- If you pin it to just 2 cores, the game itself feels fine, but there are noticeable periods of “freezing” in menus
- Pinning to 5+ cores seems to make things worse — the more cores you give after 4, the further it creeps back to 15ms+ territory.
The issue manifests itself quite similarly both on 24-core AMD Ryzen Threadripper 3960x and on 6-core Intel Core I7–8700K, though the problem is a bit less pronounced on the later.
As for the actual impact, fixing the issue made a very substantial difference for me. It feels almost as ~ you play songs on maybe 5–10% lower speed; moreover, I understood that this FPS drop was actually the reason of some % of false misses — i.e. the larger % of missed frames, the more likely Beat Saber is to classify an actual hit as a miss. You can prove it by constraining it to 3–4 cores & pinning something else stealing the CPU time to the same cores — once you get 30 … 40 FPS, you’ll see lots of false misses.
Interestingly, ASW actually played a negative role here by masking the issue — I suspect I’d immediately notice this without ASW. ASW makes it feel as “something is off, though not sure what this is”. I though that maybe my peripheral vision is more “sensitive” to FPS, and that’s why I see some “jumping” instead of a smooth motion on intense parts. But no — once this was fixed, the “jumping” went away completely.
P.S. Using Task Manager each time you launch the game isn’t super convenient, so here is PowerShell script to do this for you — till the moment Beat Games (now Facebook) fixes the issue:
And a small file to launch the above PowerShell script:
Good luck in your war against cubes :)