20,741
edits
m (→Background: https://forum.flightgear.org/viewtopic.php?f=4&t=36410&p=373075#p373075) |
m (→Status) |
||
Line 7: | Line 7: | ||
== Status == | == Status == | ||
RFC (03/2020) | RFC (03/2020) | ||
Multi-threading in Nasal is supported and possible - however, you could basically say that people can only use it properly if they have a strong background in programming and/or in FlightGear internals - otherwise, it's unlikely that people can use it successfully - because the rest of FlightGear is basically single-threaded, and that also applies to all extension functions and FlightGear specific Nasal APIs. | |||
Basically, it's not feasible to introduce multi-threading at a later time, unless you have a strong background in software engineering. However, designing your systems with threading in mind upfront can work out reasonably well - but obviously you need to work out the data flow and dependencies between different code routines. | |||
The only person to really optimize all of the aircraft successfully, including Nasal code, is Richard and he happens to be a FlightGear core developer, and also has a background in computer science - and certainly must have been using FlightGear for 10+ year | |||
However, Richard has written a number of helpers which he is in the process of sharing, i.e. adding to fgdata - so that others, less familiar with fg internals, can also use these helpers. | |||
Speaking in general, you almost certainly don't want to use multi-threaded Nasal code - unless you have a corresponding background, or at least know Nasal/the property tree and the SGSubsystem architecture inside out. | |||
Sooner or later, it seems rather likely that Canvas based avionics may optionally get their own/private Nasal instance (and property tree) per Canvas - so that the corresponding scripts can run outside the FlightGear main loop. Under the hood, a Canvas is already primarily a property tree - one that watches certain properties/locations, and that maps reads/writes to the corresponding OSG APIs. | |||
Proceeding "a is" simply isn't viable for FlightGear as a whole, because the way Nasal and the Canvas system work, there is more and more rendering code tied to non-deterministic code (among others due to Nasal's garbage collector). However, Canvas based avionics have a well-defined set of inputs (think properties, and calling certain FG extension functions, e.g. to query the navdb) and well defined outputs (usually just a single FBO/RTT texture). | |||
Thus, conceptually the code used to update such a texture does not need to run inside the FlightGear main loop. Especially when keeping in mind that a typical cockpit may have 6+ of these FBO textures, all of which are currently updated by Nasal script running at frame rate inside the main loop. | |||
The shared requirement these update routines is that they require a state vector of properties and API calls - some are fixed (i.e. always the same properties), whereas others are dynamic and may change depending on the mode/context in question (imagine showing different modes/elements of a PFD/ND). | |||
However, our experience when designing the MapStructure/ND frameworks has been that regardless of the number of instruments, it isn't feasible to always poll/getprop properties during each update cycle - instead, it makes sense to use memoization (caching) - Richard came up with a dedicated framework for that, and also for splitting work across multiple frames. | |||
This is an approach that the MapStructure framework also used (instead of threading). | |||
Thus, if you were to render n 10+ instances of a ND, it would be kinda pointless to do so at frame rate while always polling /position/*, /orientation, and /fdm/* - likewise, using listeners would not be a good idea for state that changes per frame. | |||
In other words, what's needed is a partioning mechanism to subscribe to relevant state, and then only do the fetching once (per update cycle), where all subscribing avionics would merely get a copy of the state, rather than each doing their Nasal/C++/Nasal context switches for each extension function call. | |||
Richard has worked out a generic scheme to accomplish exactly that (see his fgdata commits to /Nasal). | |||
In the mid-term, it will make sense to have the discussion if, and how, to specify lists of relevant properties for each canvas - which would include output and input properties. At that point, the Canvas system itself could traverse that list at the CanvasMgr level, and provide each canvas texture with a copy of fresh state, without unnecessarily causing property tree "traffic". | |||
At that point, the setup would resemble the "instant replay/flight recorder" subsystem - because that, too, is using a configuration scheme to encode relevant I/O properties (per aircraft). | |||
The thing is, once you have this sort of info PER INSTRUMENT (per canvas), you can trivially use a dedicated SGPropertyNode per Canvas texture, and then also hook up a dedicated FGNasalSys instance to the Canvas texture in question. | |||
With this sort of setup, you'll then end up with an off-screen RTT/FBO context that can be asynchronously updated in the background, without having to run inside the main loop - you would even have to tell OSG to only run it at ~30 hz, because it could easily run at 100+ hz otherwise, i.e. updating a texture unnecessarily. | |||
The kind of coding to populate/update and render such a canvas texture would be a little different compared to what people are currently doing, but it would be well worth it - because you could literally have 10+ canvas textures computed/updated and generated outside the main loop, with the only required synchronization point being the list of subscriptions (properties, and FlightGear APIs) - and obviously the final stage where some locking will be required to fetch the generatede Canvas FBO from the OSG worker thread. | |||
And this, too, could be facilitated by some work that Richard has shared with the community, namely "Emesary" - which he is already using to hook up a threaded garbage collector to Nasal/FlightGear. | |||
Admittedly, all of this may seem a little roundabout and maybe even complex - but short of using a simple "worker thread" setup, threading Nasal code is unlikely to work due to the sheer number of architectural restrictions in FlightGear itself. | |||
Fixing up the Canvas system to support an optional mode where the property tree is a private one, not shared with the main fgfs tree, is comparatively straightforward however - right now, Nasal itself is integrated in the form of a singleton, so that would need to change - but that's under way already, due to unit testing work that bugman has been working on recently. | |||
More recently, Jules has been working on CompositeViewer support, which is another promising option - because compositeviewer means that a completely independent scene graph can be easily processed and shown, without cluttering up the main loop. | |||
== Motivation == | == Motivation == |