I’m having a strange performance issue with my game. It runs fine in the editor, but when exported to Android, even with a nearly empty scene and no scripts running, I’m struggling to hit 60 FPS on my OnePlus 3T. It generally sits at 30, but will occasionally hit 60 for a few frames before dropping back down.
I tried to diagnose the problem by connecting Unity’s profiler, but when I do that, it jumps to a smooth 60 FPS with no issues. If I detach the profiler, it immediately drops back down to 30 FPS. I have no idea why it’s doing this, and I obviously can’t tell what’s slowing it down when the profiler isn’t connected.
For reference, I’m using Unity 2019.3.11f1 with URP, though this happens even with a render pipeline that has no extra features enabled, and with the lowest possible quality settings short of reducing resolution. I have a script that does this on startup, so the FPS shouldn’t be locked to 30 unless it’s a performance problem:
Application.targetFrameRate = 60;
QualitySettings.vSyncCount = 0;
I feel like I’m dealing with Michigan J. Frog here. Does anybody else have experience with this or any ideas of what to try?
It looks like this is a problem with landscape mode, somehow. I made a fresh project from the URP template and deleted everything from the scene except for the camera and light.
Here’s what I see from the profiler in portrait mode:
And here’s what I see in landscape mode (during the same run of the game; I just rotated my phone 90 degrees and waited a few seconds to make sure performance wasn’t being affected by the rotation animation itself):
Notice that in one of the spikes I have selected, Gfx.WaitForPresentOnGfxThread is taking over 6x as long in landscape mode as in portrait. What’s going on here?
Unless you counteract the default camera behavior, the areal your camera is showing would be vastly bigger in landscape mode. This is because the pixel to units shown ratio is fixed to the viewport height. So if in portrait mode, 1920 pixels equate to e.g. 1 unit at a distance of 10 units (let’s assume you only have things to display at 10 units distance) then your GPU has to process just a but more than 1/2 square units of texture, mesh and their shaders.
In landscape mode, 1080 pixels at 1 unit height would mean your GPU has to process the contents of just under 2 square units. So 4x that’s as much work. Your timeline shows your Render Thread is processing Gfx.PresentFrame so you are GPU bound. It might be more than 4x because after the GPU is done, it has missed the vBlank (which at 60 Hz Screen refresh rate occures every 16.66ms) so your GPU has to wait for the next one to present the frame. (Phones can only present on a vBlank due to hardware restrictions).
As to why this would be different behavior with or without the Profiler connected I have no clear answer with the limited info. Possibly your phone throttles the app if there is too little going on, and the Profiler adds some overhead/ busyness that lifts the throttling?
That would make sense to me in a scene full of objects, but the above profiles are from a completely empty scene. I can confirm it does the same thing in the default scene for a 2D project, i.e. the only object in the scene is a camera, and it has no skybox.
Correct me if I’m wrong, but I assume that the amount of GPU work shouldn’t increase in that case — we’re still rendering at the same resolution, and there aren’t any more meshes or textures to render regardless of the camera’s aspect ratio.
This is indeed puzzling with an empty scene. Have you tried using Unity’s GPU Profiler for this?
Also, you might want to try the Adreno Profiler from Qualcomm to get more hardware specific insights.
Unfortunately Unity’s GPU profiler module just reports that it’s not supported for my device (OnePlus 3T). I’ll get back to you with results from the Adreno Profiler as soon as Qualcomm approves my account.
Hmm, I can’t get the Adreno Profiler to connect to my app. It detects my device, but it says the app isn’t enabled for debugging. I’ve checked that the android.permission.INTERNET
and com.qti.permission.PROFILER
permissions are declared as required in the .apk manifest. Are you aware of any other steps I need to take to enable profiling?
I also tried the newer Snapdragon Profiler, and while it can see my device and successfully installs the files, it always times out while trying to connect. Not sure if that’s expected to be compatible with my device, though.
No luck getting any profiling info from the game yet. However, I’ve determined that this only happens when using the Vulkan API. With OpenGLES3, performance is stable regardless of the phone’s orientation.