XRBeginFrame / Gfx.WaitForRenderThread hogging Frametime

I’m currently troubleshooting a frame issue on a very simple VR program (Unity 2020.3.33). The program itself is very barebones - display a 360 skybox, and record the head-motion data (x, y, z, pitch, yaw, roll) in a CSV file every frame. The skybox images change every couple of seconds, but during the switch I am not recording the head-motion data.

For a reason I can’t pin down, there are random periods of time where the frame time will jump from ~8 ms to ~30 ms. When I say random, I mean sometimes it will occur several times during a seven minute testing period, or sometimes it will not even occur at all. During these periods of time, the head motion data is not able to be recorded, and moving around the scene itself is visually laggy.

From the profiler, I see Gfx.WaitForRenderThread is hogging the frame time. Maybe I am not interpreting the profiler correctly, but the render thread is empty. (I can only insert one screenshot at a time, but "Gfx.WaitForRenderThread>Semaphore.WaitForSignal" is taking up ~90% of the frame time.

I’m using the Vive pro 2 with HTC base stations + trackers. The computer is pretty beefy:
Intel 13th gen i7 13700, NVIDIA RTX A4000.

I’m looking for some guidance on how to solve/ diagnose this issue. I am looking at possibly using Unity’s job system to record the head-motion data on another thread - let me know if this is a silly idea. This is my first time working with VR and with Unity, and I’m a fairly Junior developer, so any sort of insight would be helpful for me!

If you look closer there it is XRBeginFrame/Gfx.WaitForRenderThread where XRBeginFrame is part of OpenXR API I believe


If that is the case then what happens here is only partially under control/responsibility of Unity engine and has more to do with this OpenXR tech layer.

Not sure if I remember this correctly, since the last time I took some interest in VR been some years, but:

Renderers that target HMDs have fairy special requirements in order to make their users motion sick less often. And one of these requirements turned out to be that VR application needs to target stable 90 fps for ideal experience and drop to stable 60 fps or stable 30 fps when the computer can’t keep up with workload. And you can see this mechanism working in your Profiler snapshot - notice the almost stairs-like switching between 90 → 60 → 90 → 60 → 30 → 90 fps levels.

Can you see it?
Good. Because you need to know that this happens automatically (on OpenXR-level) if you miss a frame even once. What does that mean? That means that even a singular CPU/GPU spike causes this switch. So to get rid of these you need to make sure that your cpu workload is both small and STABLE.

Spreading whatever workload you have over multiple frames and background threads are both good ideas. Just make sure you are optimizing the a real source of a spike / switch first so this is not a vanity work.