BAndysc / nodify-avalonia

Highly performant and modular controls for node-based editors designed for data-binding and MVVM for Avalonia. Port of WPF's version: https://miroiu.github.io/nodify
https://github.com/BAndysc/nodify-avalonia
MIT License
72 stars 3 forks source link

What is limiting the performance? It is MUCH slower than the WPF version! #10

Open DrDryg opened 4 months ago

DrDryg commented 4 months ago

I've compared this port with the WPF version. If the number of nodes, and more important the number of connections, is moderately large: Perhaps 50 nodes and most connections are made, the UI becomes slow and lag a lot.

To reproduce: In the playground example generate a graph with 50 nodes. Press the Connect/Disconnect 10 times to add connection. Now moving a node cause a lot of lag.

Doing the same thing in the WPF original Nodify results in a very responsive UI.

DrDryg commented 4 months ago

I found one improvement that could be made. I increased the MaxGpuResourceSizeBytes for Skia. It helped and the performance is fine for about 100 nodes and 100 connections with FPS only occasionally, when moving a node, dropping below 20-30 fps. Still far from WPF that can handle about 400 nodes and 1000 connections with the FPS not dropping below 30.

BAndysc commented 4 months ago

I increased the MaxGpuResourceSizeBytes for Skia. It helped and the

That's an interesting finding, good to know.

--

Other than that, the last time I profiled it, the performance was limited by the rendering time. WPF version use CacheMode optimization to avoid redrawing nodes when it is not necessary. Avalonia lacks this feature (but it is planned).

Additionally, from what I have noticed, Playground is a difficult scenario for Avalonia, mostly because the connections are very long. See that if you decrease the nodes distance

https://github.com/BAndysc/nodify-avalonia/blob/2121db5fcca421cab021c384d24b2b61665c4ff4/Examples/Nodify.Playground/Helpers/RandomNodesGenerator.cs#L26-L27

to

var xDistanceBetweenNodes = _rand.Next(15, 35);
var yDistanceBetweenNodes = _rand.Next(20, 35);

rendering is gonna be faster. Not sure anything can be done on the library side to fix it.

In my actual Avalonia app, I've decided to decrease the connections size as much as possible (it renders a tree, so this was easy), reduce nodes' visual tree complexity - it also helped.

DrDryg commented 4 months ago

Indeed shorter connection made a difference and in my use case most connections are likely to be short.

There is one thing that puzzles me and I've seen it before when experimenting with Avalonia. It doesn't matter if the content is visible or not it still slows down the drawing. So in this case, if I add many nodes and connections and zoom so I only see a few nodes and connections it is equally slow to move around a node. I seems like there is some inefficiency drawing everything even if it is not shown. Or the method determining if something needs to be shown is very inefficient. If that is the case one might remove invisible items from the visual tree to improved zoomed in performance. (Working on a small part of the graph is my typical use case.)

Do you have any thoughts on why it is slow when only showing a few items?

One more thing struck me too. With many nodes and connections the frame-rate also drops when doing nothing. Do you have any idea why that is? I didnt expect it since Avalonia isnt an immediate mode GUI.