Batching of UI elements

Hi!

Wasn’t sure whether I should necro an old thread or start a new one, so I opted on the latter, as the last message in the thread never received a reply.

Dave said:

Batching didn’t support sorted/transparent elements so there was no guarantee that your rendering order would be preserved. I think that is working now, but we haven’t fully tested the feature.

That was march 19. What is the current status on batching UI Elements?

A quick test shows if I put two buttons in the same dynamic batch group, then hover starts to act funky. Hover triggers hover state on both buttons. The buttons still work though. Without batching we are fairly screwed :slight_smile:

Edit: Seems fine if I use textures, but not sprites from texture atlas.

Best regards.

Honestly, it’s in a bit of ‘not great’ state :frowning:

The tests I’ve tried only have it working if the elements are not tinted and are not mixed with non batched UI which is really hard to do.

I’ve raised this with the team and asked for UI optimisation to be added to the roadmap.

1 Like

In other words, you can get some wins by adding some meshes into batch groups that render together (say one group for button images, one for text, one for images on top), but you need to manually trigger batch to update if any material property changes, as this is not tracked automatically.

2 Likes

Thanks! That is good to know. Would also be nice to have a ballpark timeframe, as we are getting ready to launch :slight_smile:

Meanwhile. Can you think of any optimisation that could reduce my draw calls? To put things in context, I am at about ~1700 draw calls, give or take a couple of hundred depending on the state.
All my sprites are divided into 3 atlases, where 2 of them are mostly sprite sheet animations that are shown “on top of everything”. I dont really notice any fps drop when they come into play. I also have UI Elements without textures, sprites or materials, just for the box shape. Would it be better to use sprites instead or does it not matter?

Any and all suggestions would be helpful!

Edit: Thanks @mvaligursky. I’ll try gradually adding things to batch groups and see where things break. Manually updating batch groups could prove to be a major headache :sweat_smile: – but one step at a time.

For some things (like the UI elements without textures just for the box shape) you could consider building the mesh dynamically from quads, this would give you considerably better performance. As an example, see how those quad decals are rendered here, all using a single render call:
http://playcanvas.github.io/#graphics/mesh-decals.html

You could expand this to cover your sprites from atlases as well - have one batch per atlas.

That’s pretty high. Do you know where they are coming from? Sprites are batchable as they are in 3D space and have a typical sorting order.

Sorry, we don’t even have a ballpark I’m afraid.

I’ll drop you a link to give you an idea :slight_smile:

Me and Mr_T have been having fun with this. Thanks to Mr_T for supplying a good test case for this.

There are several issues with the batching in this case:

  1. Text elements destroy and create mesh instances when the text is changed. It doesn’t seem to update the batch to remove the mesh instances when this happens so extra text is rendered to the screen as seen here in Spector.JS

  1. UI rendering order really gets messed up by batching.

To get around the 1. we disabled the entity which removes mesh instances from the batch, change the text and enabled the entity. Not the most efficient but enough to get working while investigating a fix or better method.

For 2. We used layers to handle render order on the UI. This ensures that the text is rendered last.

Final result:

https://playcanvas.com/editor/scene/1039294

Updating large batches that change frequently is not recommended (at least via the disable/enable method).

Next steps are to find better ways to add/remove the mesh instance from the batch without disabling.

2 Likes

Nice, thanks for sharing this, it’s quite useful to have this setup to play with.

Seeing the batcher run almost in realtime I am tempted to think what if a queue mechanism could be added. To split the batcher work per frame and avoid missing frames / larger than 16ms for batch generation. That would make sense only for small batches like these UI elements.

image

2 Likes

I was also thinking about spreading the work over several frames. Should be achievable even without messing with the engine :slight_smile:

FYI, changing the transform of a batched object is one confirmed alternative to disabling/enabling the entity for dynamic batches (that’s slightly more performant). I’ll keep looking for more.

1 Like

Created a ticket to improve this: https://github.com/playcanvas/engine/issues/2579

1 Like

Excellent! Things are working okay-ish currently, but definitely looking forward to improvements :slight_smile: