Canvas Threading

From FlightGear wiki
Revision as of 11:27, 28 July 2020 by Hooray (talk | contribs) (→‎Canvas Architecture: https://forum.flightgear.org/viewtopic.php?f=30&t=36614&p=357608&hilit=#p357608)
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.


Status

RFC (03/2020)

Motivation

Cquote1.png once it [Canvas] is in simgear It should be really multi-viewer/threading capable. Everything that is not, might be changed at some time to match this criterion.

Such a change often comes with changes in the behavior that are not strictly needed but where people started relying on at some time. So better think about that at the first time.


— Mathias Fröhlich (2012-10-22). Re: [Flightgear-devel] Canvas reuse/restructuring.
(powered by Instant-Cquotes)
Cquote2.png

Background

This is a collection of ideas, discussions and patches with the goal of moving certain types of Canvas code out of the main loop into a dedicated background thread/process.

Problem

We have more and more aircraft that feature comparatively complex avionics, implemented on top of the Canvas stack via Nasal. Depending on the number of simulated displays/avionics, there is a fair share of property I/O going on, including a fair amount of redundant I/O, because many avionics/display instances share certain I/O requirements (think access to /position, /orientation etc.)

Many modern aircraft will feature between 6-8 Canvas-based MFDs that may be shown/updated at the same time.

For the time being, the free-form nature of Canvas/Nasal based avionics means that most avionics don't use any dedicated frameworks or standard patterns to formalize if/how and when crucial state is updated.

This includes property tree state, as well as other state retrieve via FlightGear extension functions (think Nasal/cppbind).

Thus, a number of complex cockpits have been demonstrated to be affected by the number of Nasal/Canvas based displays. Often, this is due to the structure of existing legacy code.

Goal

This article is intended to provide a comprehensive summary of the various discussions and proposals we have seen in the context of adapting the Canvas system to come up with a new execution mode/model, with the ultimate goal of improving run-time performance - which may include, but isn't restricted to, optionally moving certain aspects of a Canvas-based display out of the main loop into dedicated background threads.

Furthermore, the goal is come up with an execution model that is backwards compatible, and strictly "opt-in" for any functionality that cannot be provided in a safe fashion.


Canvas Architecture

WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.

The Canvas system is primarily implemented in C++, it's a listener based subsystem that watches the global property tree for relevant updates/changes, specifically accesses to /canvas are monitored.

Under the hood, each Canvas is implemented as an owner-drawn gauge (OD_Gauge), canvas textures are positioned in the scene using a texture visitor (OSG), replacing static textures as needed.

Each Canvas texture is then composed of so called "elements", the lowest-level element being the "group" which is primarily used to logically structure/organize a texture into a hierarchy of lower-level building blocks. Therefore, each Canvas texture always has a "root" node, which is a group.

In turn, each group may consist of specific "element" implementations, i.e. to render certain types of context, such as:

  • text
  • paths
  • raster images

(and any combination of these)

In addition, there are higher level helpers implemented in scripting space, e.g. a "window" class implemented on top of the image element. Or support for SVG graphics, implemented on top of the OpenVG based path handling support. Also, there is a special group type to handle specifically geographic projections, for mapping/charting purposes.

Approach

telling the canvas system to use another property tree (SGPropertyNode instance) is really straightforward - but at that point, it's no longer accessible to the rest of the sim.

You can easily try it for yourself, and just add a "text" element to that private canvas. The interesting part is making that show up again (i.e. via placements). Once you are able to tell a placement to use such a private property tree, you can use synchronize access by using a separate thread for each canvas texture (property tree). But again, it would be a static property tree until you provide /some/ access to it - so that it can be modified at runtime, and given what we have already, hooking up FGNasalSys is the most convenient method. But all of the canvas bindings/APIs we have already would need to be reviewed to get rid of the hard-coded assumption that there is only a single canvas tree in use.

Like you said, changing fgfs to operate on a hidden/private property tree is the easy part, interacting with that property tree is the interesting part.

Also, it would be a very different way of coding, we would need to use some kind of dedicated scheduling mechanism, or such background threads might "busy wait" unnecessarily.

If you know how to build sg/fg from source (git) and how to apply patches, I can provide the corresponding pointers to get you started experimenting with such an adapted Canvas system, we experimented with it a couple of years ago, and there should still be patches somewhere on the forum or the wiki.

References

References