-
-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GodSVG Optimization roadmap #212
Comments
Edited a bit to update some things. |
Edited significantly because of a few developments. |
Closing this issue, as everything it points out is in a bunch of TODO comments now, that I occasionally check. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
GodSVG has a pretty poor performance. It will easily choke when SVGs get even slightly complex. It's time to establish what the current situation is, and propose some ideas on how to improve things.
This PR is going to focus on...
The fundamental bottlenecks
There are four performance-intensive tasks that are fundamental to GodSVG and not really able to be worked around in any way. That is...
There are a number of very situational ways to optimize each of these by avoiding full inspector rebuilds, re-rendering the full SVG, etc. but this post won't focus on those.
This post focuses not on how to avoid the worst case scenarios, but how to optimize them.
Parsing and highlighting
GodSVG works simultaneously with a text representation of the SVG and a native representation using RefCounteds: Tags and Attributes. Attributes and Tags can be a few different types, but they share most of the relevant logic. There are parsers for translating between text and these classes. Path attributes also have two representations: the value (a string for the path def) and the path commands, and there are separate parsers for translating between the two. As for highlighting, there is a parser too that returns a big color map dictionary.
These tasks are a notable bottleneck in some situations: for example, when panning around, a SVG is constructed that covers the screen exactly, and it needs to do all its parsing. Things like the implementation of more attributes with their own representations of the data (like transform having an internal Transform2D) will worsen this situation, same for other things.
I believe the main thing that can be improved here is that for a big SVG, things like numbers will often not be needed, only the strings will. But the numbers would still get parsed from the string automatically. This can be solved by having attributes only parse the string when the numeric value is needed.
For SVGs that are copies of the whole thing but with different svg attributes, perhaps we could have some more straightforward logic that skips parsing altogether, treating the inside parts as if it were plain text.
There are probably also good opportunities for making the parsing logic faster by just optimizing the code.
Rendering and displaying the SVG
I believe this has been mostly resolved since GodSVG now only renders the part of the SVG visible on the screen. But there are still some things to consider.
Multithreading: The drawing of the image can be multithreaded, by splitting the graphic to be displayed into strips with their own viewboxes, widths and heights, and letting WorkerThreadPool work on them. However, having so many cutoffs is quite problematic because of a bug in ThorVG whose fix isn't yet added in Godot. thorvg/thorvg#1785
Rendering the handles and contours
This is now done with Godot draw commands, which is solid even for massive SVGs. So in general, this isn't a priority to optimize, and I haven't found situations where it worsens the performance significantly. It's at worst a small overhead.
Since huge SVGs aren't a priority to support, the only optimization I'm looking out for is the way multilines are drawn. Currently, they are added to an array that's pretty much ready to be used for
draw_multiline()
. But it's not, becausedraw_multiline()
can't do antialiasing, so it uses a loop ofdraw_line()
, which is slower. This Godot PR might solve this: godotengine/godot#84497.A more complex optimization would be to bundle subsequent path operations into polylines. I tried to do once and failed; I wouldn't try it again, it's probably not that significant.
Building the inspector
The inspector with its tag and attribute editors easily becomes expensive. It's rebuilt when the SVG layout changes, that is, when tags are added, deleted, or moved. It's also redrawn when the SVG text changes. This means it's mainly important to optimize to improve the experience of using the code editor. But it also becomes the main bottleneck for big SVGs.
Unlike rendering and displaying, this seems to unavoidably cost at least O(n). And there seems to be no way to limit the amount of operations done in any way. There are ways to improve the lag spikes by doing the rebuild more gradually, but I want to first investigate if I can improve the baseline performance.
For now, no idea how to do that. I'm investigating it and I've even done some small steps towards resolving it. Given its current performance, it's medium priority.
The text was updated successfully, but these errors were encountered: