I’m using hints for parent visual element (UsageHints.GroupTransform) and for each element as well (UsageHints.DynamicTransform). Dynamic elements have position set to absolute.
The question is, is it expected to have this performance for 10k elements (see profiling image below), or there is a hint to make it work even better?
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace MyTest
{
public class Test : MonoBehaviour
{
public UIDocument uiDocument;
void Start()
{
Application.targetFrameRate = 0;
var graph = new VisualElement();
graph.pickingMode = PickingMode.Ignore;
graph.usageHints = UsageHints.GroupTransform;
graph.style.backgroundColor = new Color(0.1f, 0.2f, 0.3f);
graph.style.flexGrow = 1;
uiDocument.rootVisualElement.Add(graph);
var list = new List<VisualElement>();
for (int i = 0; i < 10000; i++)
{
var item = new VisualElement();
item.pickingMode = PickingMode.Ignore;
item.usageHints = UsageHints.DynamicTransform;
item.AddToClassList("mt-test-graph-tick");
graph.Add(item);
list.Add(item);
}
//graph.schedule.Execute(() => { TranslateItems(graph, list); }).ExecuteLater(1000);
graph.schedule.Execute(() => { TranslateItems(graph, list); }).Every(1000);
}
private void TranslateItems(VisualElement graph, List<VisualElement> list)
{
var bound = graph.worldBound;
foreach (var item in list)
{
var x = Random.Range(0, bound.width);
var y = Random.Range(0, bound.height);
item.transform.position = new Vector3(x, y, 0);
}
}
}
}
10k elements (no specific hints) attached to a visual element with hint UsageHints.DynamicTransform. Parent element has position absolute and its parent has hint UsageHints.GroupTransform. Then the parent of 10k elements is moved each frame.
Thanks for bringing this up. This is definitely slower than expected. The main bottlenecks are currently the bounding-box and transform updates. We’ll make more investigations to see if there’s a way to speed this up, but it looks like this is just the cost of re-evaluating some required states for the VisualElements. This is currently implemented in (slow) managed code, but since they are on the hot path we’ll have to optimize them.
Is this for an actual use-case you’d like to implement or are you just evaluating the perf with this example?
Our actual use case is to draw charts/graphs with potentially 10-100k elements on graph. We are looking into ways to use only UI toolkit for that, but I guess for time being we’ll render those items as meshes with a camera into a render texture and then use it in UI.
As a side note, we have “data grids” we currently use MulticolumnListView for, that have performance issues as well.
If the 10-100k elements are all dynamic and moving (as they are in your above example), it will be definitely better to build your own mesh. This way you won’t pay the price of layout/styling of UI Toolkit.
If the 10-100k elements are mostly static, but you need to transform them as a group, adding them to a common GroupTransform parent and transforming that parent should be very efficient.
That’s the case we are considering (the second test from above). Still seems to be slow, compared to rendering a mesh to a texture.
Here is an example of one of MulticolumnListView:
This list is generated in about a second. Here is a profiling screen:
Same list view, but now I’m changing list selection via SetSelectionWithoutNotify:
Same list when moving mouse/hovering over rows. Here we have few elements that have their visibility changed by DisplayStyle.Flex/None
I do accept that we might’ve done something wrong, or extremely inefficient. But, in our case, performance drops very quickly with the increasing number of components in a list item. I see a similar pattern when doing a test UI with only standard components, though.
Nevertheless, we think UIToolkit is much better than the old UI and we area glad that we’ve migrated to it.
There seems to be an abnormally high CPU time spent in “Update Style”, which is about figuring out which selectors apply to your elements and resolving/building the final style object (responsible for allocations).
There’s definitely a limit to how much you can improve these numbers only be re-working your selectors, since the number of elements still plays a big factor, but I think it should be possible to get something better based on your screenshots.