Hi fellow wiki editors!

To help newly registered users get more familiar with the wiki (and maybe older users too) there is now a {{Welcome to the wiki}} template. Have a look at it and feel free to add it to new users discussion pages (and perhaps your own).

I have tried to keep the template short, but meaningful. /Johan G

Shuttle ADI ball

From FlightGear wiki
Jump to: navigation, search
This article is a stub. You can help the wiki by expanding it.

Background

Thorsten has done a few performance tests, and the ADI ball at full glory is a hog (mainly property throughput, canvas isn't good at that kind of problem...), it's okay under his windows setup (i.e. I can detect the effect on dragging one frame if I look for it), but just to be safe I'll do it in quality levels starting from not animating the ADI ball at all over lowres to a final hires version with all features and ladders.[1]


The bottleneck is rendering the ADI-created property IO when this is at high quality if the GPU is fast enough.[2]

It's property IO which is the bottleneck. Canvas isn't designed for this[3]


The center portion of the ADI ball consists of the line grid which is generated by projecting a pattern of meridians and coordinate circles on a sphere into 2d space and then clipping the central portion out of it.[4]


The actual bottleneck is the ADI ball canvas code. As I've tested it all needs to be done in the same frame, and the ADI should be updating reasonably fast. Also, getting the properties to display is not the issue, setting the points for canvas is - data provider ain't helping a bit. (ultimately as I said, the ADI is probably best drawn by a GLSL shader which is actually designed for this kind of crap, then it happens at nearero performance footprint - for the time being, we have what we have). As for the rest, a data provider helps you if you have n identical displays. Say for the HUDs we need 30 properties each, so we can fetch them once, have them in Nasal space, save 30 getprop calls in the second HUD. For the MFDs... let's go through the numbers. We have 40 pages by now, each displays on average something like 50 properties. That's 2000 getprop calls for the data provider to manage. At 3 Hz, and 30 fps, that's 200 requests per frame. Now, if these 40, no more than 9 different ones can actually be on at any given time - so that's 450 getprop calls if you do it without data provider. Now, we're not updating them all at once, we're updating in a staggered fashion - user selectable but per default just one display in a frame - so that's 50 getprop calls per frame. So effectively you get an update rate of ~3 Hz and query only the properties you really need. Seems kinda hard to beat with a data provider...[5]



That pattern is generated in the following way:

  • start from the mathematical expression for meridians and circles on a unit sphere
  • find the rotation matrix corresponding to the current attitude and apply it
  • evaluate the expression for a finite set of points along circles and meridians (at this stage, a resolution is picked)
  • project the resulting set into 2d space
  • clip to the visible portion of the circle

-> At the output stage of this, there's a long Nasal array filled with point coordinates and a flag that tells whether the plotter should draw a line between two points or just move to the next point. I can run all these operations at high resolution without being able to detect any framerate hit.

  • clear all points of the canvas path element from the last update, then write the whole set of points as determined above via .moveTo and .lineTo (at which point canvas must execute setprop() )

(Now, note that we can't assume much about the points having moved, or even being the same number - dependent on what part of the original structure survives projection and clipping, numbers and what is connected in the array is quite different - some meridians may not be visible at all,... - which makes moving points rather than drawing from scratch a very difficult exercise and which is why real time 3d rendering strategies never bother really bother to re-use parts of the scene) Now, I can disable the update after drawing once, so I get the pure cost of rendering. Which is low. Since doing the projection and the math is not the holdup, and since the actual rendering is not the holdup, it stands to reason that it's the property IO. The resolution chosen for the evaluation grid is the single decisive parameter for the framerate cost. Now, why do we need a high resolution - look at the screenshot, and you'll see that clipping is not good - the circle and meridian lines sometimes do not reach the boundary circle, sometimes go beyond it. So the resolution needs to be good to get decent edge detection and this drives the numbers. Now, we don't need the resolution in the center to represent curvature - so I've introduced another step that after doing 2d projection and clipping, it culls points in the center of the display. The result is that while Nasal computation overhead goes up (the additional step needs to be processed), property I/O goes down (because the array requested to be written is smaller), and the net result is a decent improvement in framerate. You can feel entirely free to use any profiling tools you like, but to me the math of performance consumption is very well established by these findings. The optimiation goal is to minimize property throughput by culling as agressively early on as we can possible get away with. (See - we agree on 'too many properties' the question is just to reduce their need - if we had circular clipping on the fragment shader level for this, we'd get by with a lot less resolution and it'd be a simple task for the GPU which, as I said elsewhere, is designed to do this kind of crap. Anyway, the ADI ball is created as part of Nasal/PFD/p_pfd.nas using the lower-level routines of Nasal/canvas_draw.nas where the whole math of projection and culling is done. I think that calls the Tait-Bryon rotation equations which are elsewhere (probably in Nasal/rel_orbital.nas)[6]


In the particular case of the ADI, it would mean hard-coding an instrument that has pretty muchero other applications in FG (the complication is that spacecraft can actually assume pretty much any yaw attitude with the velocity vector so you can have beta of 90 degrees no problem - so the instrument needs to show the complete range of yaw motion which transforms a 2d into a true 3d ADI - aircraft don't need any of that, or at least I'm not aware of any aircraft instrument that displays a huge beta range. If I ever get around to it (the Shuttle is sort of a black hole into which huge amounts of work time can just disappear without leaving a noticeable trace - the sheer amount of switches on the flightdeck is insane). I plan to cut out the middle-man (canvas) and just let the ADI ball be drawn by a special-purpose shader - graphics cards are actually made to solve this sort of thing, that should work at near zero performance impact.[7]


Related

References

References
  1. Thorsten  (Aug 26th, 2016).  Re: Space Shuttle .
  2. Thorsten  (Aug 25th, 2016).  Re: Space Shuttle .
  3. Thorsten  (Oct 29th, 2016).  Re: Nasal must go .
  4. Thorsten  (Oct 28th, 2016).  Re: Nasal must go .
  5. Thorsten  (Oct 29th, 2016).  Re: Nasal must go .
  6. Thorsten Renk  (Nov 28th, 2016).  Re: [Flightgear-devel] Explicit recursive listeners .