Board index FlightGear Development Canvas

How to display Airport Chart?

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Re: How to display Airport Chart?

Postby Hooray » Sat Nov 09, 2013 12:58 am

Since I wanted to test if the navdisplay.mfd file has been sufficiently decoupled from the main aircraft/use, I put a quick hack together:

Image

compare groundspeed/headings etc in the main aircraft and in the canvas window.
(this is the same backend code, just with a driver hash to use AI traffic as the data source, rather than the main FG aircraft - and it's working NICELY, this is even superior to the built-in map dialog ! obviously AI aircraft doesn't have any cockpit buttons, so I had to use the property browser to set up the ND...)
Image
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby zakalawe » Sat Nov 09, 2013 2:51 am

Looking good, can you get this working so we can replace the map-widget for 3.0?

BTW a minimum-range query doesn't make the C++ code much faster, so I would rather keep the API simple for FGPositioned. I'm not sure using fixed range-based layers is a good idea - it works for the ND, but for the map we might want 'smooth' zooming instead of steps. I'm also surprised it's a good tradeoff in terms of memory use - for fixes and airports in particular, the large range causes a lot of cache and memory traffic, and since people rarely use 640nm range or zoom the map out that far, we'd like to avoid running the query until that range is requested. But maybe you already did this.
zakalawe
 
Posts: 1259
Joined: Sat Jul 19, 2008 5:48 pm
Location: Edinburgh, Scotland
Callsign: G-ZKLW
Version: next
OS: Mac

Re: How to display Airport Chart?

Postby Hooray » Sat Nov 09, 2013 3:08 am

zakalawe wrote in Sat Nov 09, 2013 2:51 am:Looking good, can you get this working so we can replace the map-widget for 3.0?


We need to check what's missing, or rather, what would be useful to replace the map widget completely/properly. For example, as far as I know, we don't currently have any hooks into the replay/flight recorder subsystem, which is however what's used to show flight path history,right ? So the poor-man's approach would be using a timer and sampling the position separately, but having access to the replay/recorder system would be great for many other reasons, so exposing it via cppbind would be awesome.

BTW a minimum-range query doesn't make the C++ code much faster, so I would rather keep the API simple for FGPositioned.

yeah, but the point was not making the C++ code faster, the point was making the Nasal code faster when updating groups - by writing positions to the right layers/groups directly.

Otherwise, we would need to filter/sort stuff in Nasal space - or extend the canvas system with some filter that automatically sorts groups based on configured ranges.
So having a min-range query supported would allow us to significantly restrict each query down to relevant stuff, and directly adding it to the right layer.
Let's see what Philosopher has come up with - maybe he disagrees, but I'd find it useful (and simple enough) - especially in comparison to more sophisticated optimizations.

I'm not sure using fixed range-based layers is a good idea - it works for the ND, but for the map we might want 'smooth' zooming instead of steps.

right, but most NDs these days do work with fixed ranges - and currently, the queries are not flexible enough, and the original 744 code would actually lag a bit behind in certain ranges (160nm+), simply due to the sheer number of symbols being written to the property tree, all to a single canvas group/layer.

We can do fgcommand-profiling again to see if there are any low-hanging fruits still, but I doubt it in the meantime... some locations/ranges cause more than 1000 symbols per layer to be added, that MUST have an effect on frame rate - even regardless of Nasal-space overhead

I'm also surprised it's a good tradeoff in terms of memory use - for fixes and airports in particular, the large range causes a lot of cache and memory traffic, and since people rarely use 640nm range or zoom the map out that far, we'd like to avoid running the query until that range is requested. But maybe you already did this.


yeah, the original airport-selection framework already supported "lazy" updates like these - but that would inevitably result in frame latency spikes once the corresponding range is requested - which is why it might be better to still populate each "range group" as long as it's hidden, using much smaller queries/results per layer (incrementally) - we could then use split-frame loops to update invisible groups "in the background" and on activating a layer, only add what's missing still.

Otherwise, we need to think about some way to selectively update items, that's much more canvas-friendly - especially for use-cases like the map dialog, where simply calling removeAllChildren() is a simple no-go.

We'll see how clever Philosopher's scheme is, and if it's gonna be flexible enough to support the map dialog - but algorithmically, I haven't yet really touched the 744 ND code, and there's still some room for improvement. Otherwise, we need to convince Tom that we need some canvas-level instancing support to make 1000+ identical symbols less heavy. I already mentioned in another thread, that we could use a nested canvas and render such symbols as raster images instead - i.e. a Nasal/Canvas-space "caching" workaround.

From a C++ standpoint, we'd also need to look at supporting a more "pole-friendly" projection mode possibly - I think there's an issue for that in the tracker.
Also, exposing some more scenery/vector data would be nice to render more useful maps - or we'll need to revisit ESRI shapefiles again for that sort of stuff.

So if we really want to replace the built-in map dialog and the navdisplay for 3.0, there are some open issues still - including label decluttering etc. And I do believe that we need a way to benchmark each group/element/canvas at the core level, so that we can identify groups that are comparatively heavy to update, and see where time is spent (listener notifications vs. shiva) - otherwise, it's hard for us to tell where time is spent, because there are so many abstraction layers now, so that even core profiling doesn't provide good information anymore, and Nasal-space benchmarking would be insufficient.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Philosopher » Sat Nov 09, 2013 3:32 am

I'm quite tired right now, but could I have some clarification as to how it currently works? Static objects get set into a layer and forgotten, right? (e.g. navaids) When do they get updated? What about moving objects (AI craft)? How do they get moved, if they're forgotten?

As for me, I basically have a positioned difference algorithm and will need to develop a symbol class/framework. Nothing addressing LOD/range yet, but I'll continue to think about it.

But I think we shouldn't need a min range: can't we just sort things in Nasal space and share data between ranges?
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: How to display Airport Chart?

Postby Hooray » Sat Nov 09, 2013 3:39 am

see traffic.model - it's just a timer that is triggered every 2 secs, which removes all traffic first and then adds it again - that's the way Gijs wrote it.

Okay, regarding multi-symbol instancing, I played a little with the idea mentioned in the other thread, i.e. using a separate canvas texture as a cache for shared geometry/instancing - where the draw files would write stuff into the canvas cache texture, and save the bounding box for each group into a Nasal hash, keeping the texture coordinates and dimensions in mind.

Basically, it's a huge ugly hack - but it works and is faster than using hundreds of SVG/path groups for each symbol. This now works such that it looks up the symbol in the cache texture and then uses setSourceRect() to obtain the relevant part of the texture, which is included as a canvas:// raster image.

The dialog on the right shows the canvas cache texture in a dialog (for inspection purposes, maintained in memory with placement:ref), the ND shows the texture in use as it is referenced via canvas:// as a raster image with texture mapping applied, there's only a single SVG/OpenVG path node now for 400+ instances of the same symbol, less than 50 lines of pretty ugly code.

Image
Image

If this is something that we want to pursue, Tom should probably have a look and re-implement the idea at the Nasal/Canvas level to make this less ugly and more useful in general.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Gijs » Sat Nov 09, 2013 11:20 am

Just wanted to say that I'll be out of town most of today. I will check Hooray's version tomorrow. ;-)
Airports: EHAM, EHLE, KSFO
Aircraft: 747-400
User avatar
Gijs
Moderator
 
Posts: 9544
Joined: Tue Jul 03, 2007 3:55 pm
Location: Delft, the Netherlands
Callsign: PH-GYS
Version: Git
OS: Windows 10

Re: How to display Airport Chart?

Postby Philosopher » Sat Nov 09, 2013 2:40 pm

That's really cool, Hooray! That actually makes my work oodles easier, I should just need to provide a controller-based switch for different symbols (e.g. for active versus inactive). You successfully removed calling a half-dozen draw routines from our worries :D.
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: How to display Airport Chart?

Postby Hooray » Sat Nov 09, 2013 5:01 pm

I think we need to wait for TheTom and/or Zakalawe to see if we want to use this method or if they're going to come up with something better for symbol instancing - the good thing about the decoupled nature of the design is that it's pretty straightforward to change things and optimize stuff without having to touch tons of places/Nasal files in $FG_ROOT.


PS: Been reviewing your recent commits, thanks for your work, much appreciated !
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Hooray » Sat Nov 09, 2013 9:13 pm

What about moving objects (AI craft)? How do they get moved, if they're forgotten?


at the moment, it's all pretty simple (ok, dumb) - the only optimization I did originally was drawing to separate groups, instead of drawing everything into one - which is why you'll see the .init() method of the model being invoked whenever an update is required, which basically trigger a full refresh for each layer/group, i.e. removing all children of the canvas group, and then populating the model vector again, and subsequently notifying the "view" (canvas group), which calls the specified *.draw callback for each drawable in the model's vector. So things are either updated via listeners or via timers. Even though we really should be using maketimer() instead of settimer().

The *.layer files are just there to combine an existing *.model with a matching *.draw file - frontends like the ND or the airport selection dialog never work with draw files or model files directly - in fact, they know nothing about these lower level details - all they're dealing with is the concept of a "layer", and a bunch of layer-specific control attributes (properties usually).

Each *.draw file will have at least one accompanying .model file that serves as the "driver" to provide the data that is to be drawn, so the draw file has knowledge about the drawable and will get the requested data out of the passed arguments - we may however have multiple *.layer files using the same set of draw/model files - just for different purposes. Given the lack of a real controller framework so far, that's how it's currently working: custom layers for different purposes. Putting new layers together is straightforward, even without knowing anything about map.nas - it's really just copy&paste and customizing...Usually, these layer/model files are 10-15 lines in size, so simple to update/port and maintain, even if we should get rid of the original helpers and classes.

Ideally, we'd really keep track of previous drawables and current drawables in the next iteration, so that we can identify a subset of added/removed items, hide removed stuff and move them to the next layer if applicable or schedule them for removal via split frame loops (maybe we could also set a flag to let the canvas system propagate/purge such marked properties in C++ space?) - however, like Zakalawe mentioned, we probably don't want to design the whole thing around the assumption of always having "range-aware" layers.

At the moment, it's a feasible compromise and a sensible optimization though - especially because performance does suffer when multiple NDs are rendered and updated (I've been rendering as many as 10 different NDs, using the AI traffic driver hash) - Gijs' original 744 ND does update quite a few things at framerate (well almost), and it seems that the canvas doesn't internally use bounding boxes to selectively update things, Tom can probably clarify if that's the case, but it also seems that all groups are updated separately, even unmodified ones - where using one texture per group/layer may be better performance-wise (but obviously more memory-hungry). I guess we will need to do some profiling again - I am also getting the impression that it's the sheer number of updates/setprop() writes that could be having an effect here, it might be faster to disable updates per group, update everything and then tell the canvas to process everything at once - rather than firing a listener for each setprop() call, I'd guess that processing everything once per group may be better - i.e. sort of like backbuffer rendering, having a flag to disable listener notifications/canvas processing, and enabling it again after everything has been written to the tree.



Looking at your commits, I am confident that we'll be able to replace the original MVC stubs, and use something that's better from a performance point of view.

EDIT: Canvas stress test of the day (all of these are independent navdisplay instances and canvases with different "drivers"):
Image
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Hooray » Sun Nov 10, 2013 12:51 am

@P: What were you trying to do here: https://gitorious.org/fg/hoorays-fgdata ... as/map.nas (432)

Apparently, we're now loading our files twice - I assume you just wanted to remove the *.controller extension because of your new framework ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Philosopher » Sun Nov 10, 2013 12:53 am

Thanks, friends, for the work you've put in! I got a change to test it this morning (aka I've been busy for the whole day ;)) and it worked well. (Couldn't find any controls, so looked up the root and used the property browser :oops:.)

Glad to know that my work will be useful. I like working in from designing to implementation, so I'll see what I can do (and if I can come up with more optimized paths).

@H: completely a mistake, probably a merging conflict (there was surprisingly little when I did have to merge map.nas). Thanks for the typos fix, I didn't load/test it...
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: How to display Airport Chart?

Postby Hooray » Sun Nov 10, 2013 12:59 am

ok, so continue loading once, minus the *.controller stuff ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Philosopher » Sun Nov 10, 2013 9:29 pm

Just a quick report on memory: with UFO in the middle of no scenery: 400MB; moving to KSFO increases to 760MB; 747-400 in no scenery is already 740MB; C-172P-canvas in no scenery is 970MB, w/ airport dialog and chart for EDKA: 1,000MB (KSFO slightly more), moving to KSFO is up to 1.33GB.

Firing it up to test Nasal introspection...
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: How to display Airport Chart?

Postby Hooray » Sun Nov 10, 2013 10:01 pm

yeah, we really need some way to track memory usage per subsystems to have a better idea about what's going on...

747-400 in no scenery is already 740MB; C-172P-canvas in no scenery is 970MB, w/ airport dialog and chart for EDKA: 1,000MB (KSFO slightly more), moving to KSFO is up to 1.33GB.

In case you didn't notice, I generalized Gijs' ND so that you can easily use it now on other aircraft, including the ufo and even AI aircraft, the 744 is a real memory hog ... so I find quick testing/development with the ufo more enjoyable, due to faster startup times :D

For quick testing, I have saved this snippet in my Nasal console, and merely uncomment the "connectAI" call to show AI traffic instead of the ufo:

Code: Select all
# ---------------
var ND = canvas.NavDisplay;
setprop("autopilot/settings/true-heading-deg",100);

     var myCockpit_switches = {
   # symbolic alias : relative property (as used in bindings), initial value, type
   'toggle_range':    {path: '/inputs/range-nm', value:40, type:'INT'},
   'toggle_weather':    {path: '/inputs/wxr', value:0, type:'BOOL'},
   'toggle_airports':    {path: '/inputs/arpt', value:0, type:'BOOL'},
   'toggle_stations':    {path: '/inputs/sta', value:0, type:'BOOL'},
   'toggle_waypoints':    {path: '/inputs/wpt', value:0, type:'BOOL'},
   'toggle_position':    {path: '/inputs/pos', value:0, type:'BOOL'},
   'toggle_data':       {path: '/inputs/data',value:0, type:'BOOL'},
   'toggle_terrain':    {path: '/inputs/terr',value:0, type:'BOOL'},
   'toggle_traffic':    {path: '/inputs/tcas',value:0, type:'BOOL'},
   'toggle_display_mode':    {path: '/mfd/display-mode', value:'MAP', type:'STRING'},
   # add new switches here
      };
   var myAI_ND = ND.new("/ai/nd", myCockpit_switches); # use the property browser to configure the AI ND
   var myND = canvas.new({
      "name": "ND4AI",
      "size": [1024, 1024],
      "view": [1024, 1024],
      "mipmapping": 1
   });
   # nd_display.ai.addPlacement({"node": "ndScreen"});
   var ai_group = myND.createGroup();   
   myAI_ND.newMFD(ai_group);

   var watch_traffic = func {
        var traffic = props.globals.initNode("/ai/models/").getChildren( "aircraft" );
   foreach(var ac; traffic)
     if (ac.getNode('velocities/true-airspeed-kt').getValue() >= 100) {
     print("Found traffic:", ac.getPath(),'=>' , ac.getNode("callsign").getValue());
   #myAI_ND.connectAI( ac ); # change position source to use AI system
   myAI_ND.update();

   var dlg = canvas.Window.new([400, 400], "dialog");
   dlg.setCanvas( myND );

     return;
     }
   settimer(watch_traffic, 1);
   }

   watch_traffic();


(if your AI traffic is disabled, you need to change it to remove the search for traffic or it won't pop up)

You'll find the control properties under /ai/nd/inputs in the property browser
For better performance, you may want to adjust the maketimer() call in the newMFD() method - Gijs originally set this to 0.05 i.e. almost framerate - but for testing purposes just increase the value to something between 200-500 ms until backend code gets faster
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: How to display Airport Chart?

Postby Hooray » Mon Nov 11, 2013 12:16 am

Here's a recent google-perftools profile when using the 744 ND.nas code (unoptimized) and circling above KSFO with the ND rendering a few layers:
Code: Select all
    640  29.4%  29.4%     1087  50.0% _nv019glcore
     501  23.0%  52.5%      983  45.2% _nv005glcore
     158   7.3%  59.7%      598  27.5% simgear::canvas::Group::update
     126   5.8%  65.5%      126   5.8% memcpy
      50   2.3%  67.8%       69   3.2% SGPropertyNode::getChildImpl
      42   1.9%  69.7%       42   1.9% __strlen_sse2
      39   1.8%  71.5%       39   1.8% osg::Object::getUserData
      32   1.5%  73.0%       46   2.1% shStrokePath
      32   1.5%  74.5%      510  23.4% simgear::canvas::Map::update
      30   1.4%  75.9%      158   7.3% simgear::canvas::Element::update
      27   1.2%  77.1%      691  31.8% vgDrawPath
      26   1.2%  78.3%      115   5.3% SGPropertyNode::set_double
      23   1.1%  79.4%       32   1.5% *__GI_____strtod_l_internal
      23   1.1%  80.4%       36   1.7% SGPropertyNode::getChild@fd9510
      18   0.8%  81.2%       18   0.8% SGPropertyNode::getDoubleValue@fdabb0
      18   0.8%  82.1%       25   1.1% _nv014glcore
      13   0.6%  82.7%       13   0.6% _init@647ac0
      13   0.6%  83.3%       14   0.6% shVector2ArrayPushBackP
      12   0.6%  83.8%       75   3.4% SGPropertyNode* find_node
      11   0.5%  84.3%       22   1.0% *__GI___libc_malloc
      11   0.5%  84.8%       12   0.6% _int_malloc
      11   0.5%  85.3%       16   0.7% simgear::canvas::Map::valueChanged
      10   0.5%  85.8%       10   0.5% SGPropertyNode::getStringValue@fdb4d0
      10   0.5%  86.3%       10   0.5% std::basic_string::compare@a7b50
       9   0.4%  86.7%       60   2.8% SGPropertyNode* find_node_aux
       8   0.4%  87.0%       13   0.6% *__GI___libc_free
       8   0.4%  87.4%        8   0.4% shPaintArrayFind
       7   0.3%  87.7%       23   1.1% shSet
       7   0.3%  88.0%       22   1.0% simgear::canvas::Canvas::valueChanged
       7   0.3%  88.4%        7   0.3% simgear::canvas::Element::getStyleInfo
       7   0.3%  88.7%     1466  67.4% simgear::canvas::Path::PathDrawable::drawImplementation
       7   0.3%  89.0%        7   0.3% std::basic_string::basic_string@a8dd0
       6   0.3%  89.3%        6   0.3% __mpn_mul
       6   0.3%  89.6%        7   0.3% boost::detail::function::function_obj_invoker2::invoke
       6   0.3%  89.8%       15   0.7% simgear::canvas::HorizontalProjection::worldToScreen
       5   0.2%  90.1%        5   0.2% *__GI___isnanf
       5   0.2%  90.3%        5   0.2% _int_free
       5   0.2%  90.5%       17   0.8% _nv013glcore
       5   0.2%  90.8%        8   0.4% boost::iterator_range parse_name
       5   0.2%  91.0%        5   0.2% memset
       5   0.2%  91.2%      598  27.5% simgear::canvas::Canvas::update
       5   0.2%  91.4%       33   1.5% simgear::canvas::Element::valueChanged
       4   0.2%  91.6%      119   5.5% SGPropertyNode::setDoubleValue@fdd570


I think we really need to stop writing all changed properties (lat,lon,hdg etc) to the canvas tree at frame rate, or find a good way to make atomic updates.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

PreviousNext

Return to Canvas

Who is online

Users browsing this forum: No registered users and 1 guest