Canvas SVG: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
No edit summary
 
(23 intermediate revisions by the same user not shown)
Line 4: Line 4:


== Background ==
== Background ==
Some lower end RPi/Intel based computers are taking ~15 seconds to show the FG1000 device.
{{See also|Canvas Threading}}


So there's currently a discussion taking place to optimize/port or re-implement Canvas SVG handling - could some more people please report here how long initialization of the FG1000 is taking for them ? Ideally, by using just the debug menu and checking how much time it takes for the PDF to show up ?
[[File:Svgnas-performance.png|thumb|svg.nas parsing [[FG1000]] artwork for benchmarking purposes]]
 
Some lower-end RPi/Intel based computers are taking ~15 seconds (during a single frame!) to show the FG1000 device.
 
In 02/2022, some users reported that the shuttle is taking more than 30 minutes to boot due to SVG processing <ref>https://forum.flightgear.org/viewtopic.php?f=19&t=35763&p=397312&hilit=svg#p397225</ref>.
 
[[File:CdG5Q9q.png|thumb|right]]
 
So there's currently a discussion taking place to optimize/port or re-implement Canvas SVG handling - could some more people please report here how long initialization of the FG1000 (or the shuttle) is taking for them ? Ideally, by using just the debug menu and checking how much time it takes for the PDF to show up ?


With some new MFDs making heavy use of SVG files, our way of using a custom scripted parser implemented in Nasal (svg.nas) is adding up considerably. i.e. performance is severely affected when processing such files.
With some new MFDs making heavy use of SVG files, our way of using a custom scripted parser implemented in Nasal (svg.nas) is adding up considerably. i.e. performance is severely affected when processing such files.


On some platforms, just the initialization of the [[FG1000]] is taking ~15 seconds - profiling shows most of the time is spent in ~1500 context switches between Nasal and C++ respectively.
On some platforms, just the initialization of the [[FG1000]] is taking ~15 seconds - profiling shows most of the time is spent in ~1500 context switches between Nasal and C++ respectively, due to how svg.nas uses the parsevg API to leverage callbacks implemented in Nasal.
 
== Objective ==
Better understand and improve performance of initializing and using SVG images via the Canvas.


== Ideas ==
== Ideas ==
* run parsexml in a Nasal worker thread (problematic: while parsing/loading can happen asynchronously, the parser needs a handle to the canvas group to draw into, so need to synchronize access to that) <ref>https://forum.flightgear.org/viewtopic.php?f=4&t=34571&p=368880#p368707</ref>
{{See also|Canvas_News#Skia_backend}}
* Stuart suggested to port svg.nas to C++ (that would still not give us any threading benefits)
 
* add support for persistence, i.e. to serialize a Canvas.Group structure to disk ($FG_HOME) and use caching from then on
* run parsexml in a Nasal worker thread (problematic: while parsing/loading can happen asynchronously, the parser needs a handle to the canvas group/canvas FBO to draw into, so need to synchronize access to that) <ref>https://forum.flightgear.org/viewtopic.php?f=4&t=34571&p=368880#p368707</ref>
** as of 02/2022, Jules has made progress fixing up the property tree implementation to become thread safe, which might make it more feasible to move some parsing/SGPropertyNode processing into a worker thread using a private property tree.
* Stuart suggested to port svg.nas to C++ (that would still not give us any threading benefits) - also, our custom parser is really trivial, i.e. only supports a subset of SVG
* create a new/dedicated [[Canvas Element]] specifically for handling SVG files in native code, without going through Nasal space (at least not inside the main loop), possibly adopting an existing SVG rendering back-end that is OpenGL/OSG compatible (see James' Ski/QQ2 comments)
* use an existing SVG back-end that renders into a scene graph, i.e. something like [https://github.com/vega/vega-scenegraph vega scenegraph] (see Scott's comments regarding nanovg)
* use the librsvg back-end in conjunction with annotations, to expose specific SVG elements via dedicated [[Canvas Element|sc::Element]] nodes, and treat others as "static" (aka raster images).


== Status ==
== Status ==
after a bit of googling, it actually turns out that there is already a dedicated plugin for SVG handling via OSG - so that would probably be the least amount of work, given that we already have Canvas::Image using the same ReaderWriter mechanism under the hood.
last update: 02/2022
 
after a bit of googling, it actually turns out that there is already a dedicated plugin for SVG handling via OSG - so that would probably be the least amount of work, given that we already have [[Canvas Image]] using the same ReaderWriter mechanism under the hood.


I don't know anything about the plugin's state - but I suppose it'll we much more feature-complete than our own little parser.
I don't know anything about the plugin's state - but I suppose it'll we much more feature-complete than our own little parser.
Line 34: Line 54:


var (width, height) = (512, 512);
var (width, height) = (512, 512);
# Create a standalone Canvas(not attached to any GUI dialog / aircraft etc)
var myCanvas = canvas.new({
var myCanvas = canvas.new({
     "name": "Canvas.Image SVG Test",
     "name": "Canvas.Image SVG Test",
    # The name is optional but allow
    for easier identification "size": [width, height],
    # Size of the underlying texture(should be a power of 2, required)[Resolution]
     "view": [width, height],
     "view": [width, height],
    # Virtual resolution(Defines the coordinate system of the canvas[Dimensions] # which will be stretched the size of the texture, required)
     "mipmapping": 1  
     "mipmapping": 1 # Enable mipmapping(optional)
});
});


# set background color
myCanvas.set("background", canvas.style.getColor("bg_color"));
myCanvas.set("background", canvas.style.getColor("bg_color"));


Line 67: Line 81:
== References ==
== References ==
{{Appendix}}
{{Appendix}}
[[Category:Canvas Element Proposals]]

Latest revision as of 18:45, 28 January 2022

This article is a stub. You can help the wiki by expanding it.


Background

svg.nas parsing FG1000 artwork for benchmarking purposes

Some lower-end RPi/Intel based computers are taking ~15 seconds (during a single frame!) to show the FG1000 device.

In 02/2022, some users reported that the shuttle is taking more than 30 minutes to boot due to SVG processing [1].

CdG5Q9q.png

So there's currently a discussion taking place to optimize/port or re-implement Canvas SVG handling - could some more people please report here how long initialization of the FG1000 (or the shuttle) is taking for them ? Ideally, by using just the debug menu and checking how much time it takes for the PDF to show up ?

With some new MFDs making heavy use of SVG files, our way of using a custom scripted parser implemented in Nasal (svg.nas) is adding up considerably. i.e. performance is severely affected when processing such files.

On some platforms, just the initialization of the FG1000 is taking ~15 seconds - profiling shows most of the time is spent in ~1500 context switches between Nasal and C++ respectively, due to how svg.nas uses the parsevg API to leverage callbacks implemented in Nasal.

Objective

Better understand and improve performance of initializing and using SVG images via the Canvas.

Ideas

  • add support for persistence, i.e. to serialize a Canvas.Group structure to disk ($FG_HOME) and use caching from then on
  • run parsexml in a Nasal worker thread (problematic: while parsing/loading can happen asynchronously, the parser needs a handle to the canvas group/canvas FBO to draw into, so need to synchronize access to that) [2]
    • as of 02/2022, Jules has made progress fixing up the property tree implementation to become thread safe, which might make it more feasible to move some parsing/SGPropertyNode processing into a worker thread using a private property tree.
  • Stuart suggested to port svg.nas to C++ (that would still not give us any threading benefits) - also, our custom parser is really trivial, i.e. only supports a subset of SVG
  • create a new/dedicated Canvas Element specifically for handling SVG files in native code, without going through Nasal space (at least not inside the main loop), possibly adopting an existing SVG rendering back-end that is OpenGL/OSG compatible (see James' Ski/QQ2 comments)
  • use an existing SVG back-end that renders into a scene graph, i.e. something like vega scenegraph (see Scott's comments regarding nanovg)
  • use the librsvg back-end in conjunction with annotations, to expose specific SVG elements via dedicated sc::Element nodes, and treat others as "static" (aka raster images).

Status

last update: 02/2022

after a bit of googling, it actually turns out that there is already a dedicated plugin for SVG handling via OSG - so that would probably be the least amount of work, given that we already have Canvas Image using the same ReaderWriter mechanism under the hood.

I don't know anything about the plugin's state - but I suppose it'll we much more feature-complete than our own little parser. And it being an OSG plugin, it will automatically be able to run in the background - so we won't have to add our own threading code.

Also, it's not a totally new dependency, rather just another OSG plugin - so comparatively easy to support via the existing build system (according to the OSG website, the plugin only needs librsvg)

[...]

Actually, it only just occurred to me that we may already have native SVG support anyway, due to the way how OSG ReaderWriter plugins work, it's very well possible that all that we need to do is build/add the SVG plugin, because at that point Canvas.Image might automatically be able to work "as is", without any C++ changes, all that is needed is specifying an SVG file - how does that sound? :D

(note this bypasses Nasal/svg.nas and the XML parser entirely, and runs inside a background thread handled by OSG, and it only takes a few ms to load/display)


var (width, height) = (512, 512);
var myCanvas = canvas.new({
    "name": "Canvas.Image SVG Test",
    "view": [width, height],
    "mipmapping": 1 
});

myCanvas.set("background", canvas.style.getColor("bg_color"));

# creating the top - level / root group which will contain all other elements / group
var root = myCanvas.createGroup();

var window = canvas.Window.new([width, height], "dialog");
window.setCanvas(myCanvas);

# path is relative to $FG_ROOT(base package)
var path = "Aircraft/Instruments-3d/FG1000/MFDPages/PFDInstruments.svg";
# create an image child
for the texture
var child = root.createChild("image")
    .setFile(path)
    .setSize(512, 512);

Native SVG handling via Canvas Image and the OSG SVG plugin (via librsvg)

References

References