DrawTransparentObjects excessive time, is this canvas related?

Hi,

I've written a simple game and am relatively new to the profiler but have been learning it the past couple of weeks. My game is a basic 2D mobile game, not graphically intense at all e.g. plain black background simple colour objects and a few shaders nothing major. There is a little bit of 2D physics going on as there are up to 60 balls that can collide and effect balance but other than that nothing much going on.

Currently testing on Android and it runs perfect on a modern phone e.g. Motorola G10 and I am hoping for a budget of 32ms or 30fps.

I wanted to bench mark on an older phone though so dug out my old Samsung Galaxy S4, I would say it is passable and playable but not nicely smooth.

On digging into the profiler and reading around what I have learned I think it may be an issue caused by having a single Canvas with everything on it, the canvas has two count down timers which are constantly updating in game and hidden panels \ buttons that appear at specific intervals e.g. end of level. There is also a score that gets updated.

Really I'm just seeking some clarification if I am reading the profiler correctly or going down a dead end, what I think is causing the spikes and framerate drop when playing is the DrawTransparentObjects method which will spike from about 1/2ms right up to near 20ms on a spike pushing my game way up to 60+ ms.

I'm thinking that if I reworked the canvas and split the constantly updating parts out like the timers and left the more static elements together e.g. pre-level notifications, end of level summary that I could bring this time down significantly.

Am I on the right track here?

*Also I have ran through and optimised a lot of other things I was doing wrong also e.g. referencing yield returns, avoiding over coding in update method, using object pools. I feel I have optimised a lot of the code and certainly noticed improvements from the reworks, but its just not enough for the older phone.

Thanks in advance!
LS

8376885--1104360--CanvasHierarchy.jpg
8376885--1104363--ProfilerHierarchy.jpg
8376885--1104366--ProfilerTimeline.jpg

Hello,
This might have better fitted into the URP or UI subforums as it's less related to the process and tooling of profiling in Unity and more to how the features in this area operate. So I don't have too detailed an understanding of the specifics here but it does indeed look like your transparent elements getting rendered for the UI camera take up a good chunk of your frame time.

The 2 UI Profiler Modules (addable via top left-hand drop-down in the Profiler Window) and the Frame Debugger might provide more details of why that is, e.g. which elements are rendered in which batches and how that differs to other frames.

The general advice, that I'm not sure if it still fully applies here, is indeed to split out the more dynamic parts of the UI into their own canvas, so that updates to these elements don't dirty the entire canvas hierarchy, causing necessary recalculations if layouts and what is or isn't visible to be rendered

1 Like

Thanks Martin,

I didn’t get a chance yet but will have a shot at separating out the timers and the score dialogue from the other relatively static UI elements and see how that goes.

I’m sure if they would each need their own canvas or it would suffice to move the more dynamic elements en masse onto a single separate canvas or provide a separate canvas for each?

Thanks,
N

I think everything that would update at close to the same frequency could be grouped together. Also make sure to keep the hierarchy complexity tow as that has an impact on the recalculations cost.

Thanks Martin,

I ended up splitting out the frequently updated canvas items individually e.g. the score value. radial timers and the two text based countdowns. It didn't really make much difference though unfortunately, I am still getting those spikes in the profiler. The hierarchy in those reworked canvas items is very simple now also.

When I drilled further I see an awful lot of BatchRenderer.Flush followed by a StdRenderer.ApplyShader calls, these seem to be adding up and costing significant time.

8388774--1106637--FlushApplyShader.jpg

Hmm, yeah, I was wondering if re-layouting costs shouldn't be captured under lilac UGUI.Layout samples ...

Have you checked what the Frame Debugger and or the UI Profiler modules say about why these UI elements can't be processed in a single batch?

Unity Version ~ 2020.3.25f1
Profiling on Samsung Galaxy S4 connected via USB

So I've done a ton of optimising ~

Split out UI elements into logical canvas's e.g. dynamic \ static
Ordered UI elements in hierarchy to reduce frame draw
Substituted proper material to avoid default shader in UI sprites
Significantly reduced canvas hierarchy complexity by removing anything unnecessary
Updated Shaders to UPR

More generally
Removed almost all GetComponent statments
Cached references in scripts
Changed physics loops to use FixedUpdate instead of Update
Removed any unused code
Cached yield statements
Changed TMP_Pro text pool to sprite pool
Organised and put all my sprites on an Atlas
For my timers I got rid of any .ToString updates
Changed RigidBody2D Transform moves to be RigidBody moves to avoid physics recalculations
Reduced the physics time step
Set VSync to EveryVBlank
Significantly reduced the number of items in my pools
Reduced camera's from 2-1
Simplified the UPR asset as much as possible e.g. no shadows \ lights \ no post processing \ no HDR \ set SRP & Dynamic batching (very simple game no need for that stuff)

I've also been in the quality settings and used the lowest setting possible

So with all that I do see an improvements but its still missing frames and I consistently get >32ms on basic menu UI frames where there is no physical gameplay. I don't quite see really long frames now like I was getting e.g. >90ms but its still jittery when I play and profile on the S4. Frame debugger shows the number of draws down from circa 80 -> 11 to 15 typically, so things are batching much better now.

So after exhausting everything I could find and think to do, I thought I would create a new scene, completely basic with just a camera in it, surprisingly even it gives me frames >32ms and there is literally nothing on it.

Unity Ver 2020.3.33f1
So I thought make a new project specifically a 2D Mobile template one using the old In Built renderer, same thing just a scene with a single camera and nothing else, mostly the frames are around 30ms but occasionally one goes over, this seems ridiculous for a deployed app which essentially has no content< I would have thought it would have skipped along happily @200fps even on an old phone.

One final thing I tried was to attach a script to an object and set the following ~
private void Start()
{
//QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;
}

This helped a little too but it was no panacea, it feels like there is something obvious here I can not doing but I can't for the life of me see what it is. I just can't seem to get good performance on this S4 regardless of the complexity of the scene in play? is the phone just a dud (it seems to run other apps fine)?

Here's some examples of what I see, any thoughts?

Thanks,
LS

8426403--1115388--20220908_VSync_LowQUality.jpg 8426403--1115391--20220908_VSync_LowQuality_ProjSettings.jpg

8426403--1115394--20220908_VSync_LowQuality_Scene.jpg
8426403--1115397--20220908_VSync_LogCat.jpg

Hey again,

I have to admit, I've got nothing. I was going to suggest Adaptive Performance but the phone is too old to be supported. As a bit of a Hail Mary, you might try turning off Optimize Frame Pacing in the Player settings?

Or try reposting with your latest findings in the android or URP subforums?