I was working with a simulator that uses FlightGear's network master/slave capability to drive 4 additional displays and discovered an obscure tile loading / tile caching / cache management bug. I believe I have tracked down exactly what and why this is happening, and I have a proposed fix that I'd like to post to the list for potential review and improvement before I commit the patch.
The problem I found was that when relocating to a nearby location, depending on the specific sequence of locations and view orientations, sometimes tiles would not be loaded, leaving gaping blank holes in the terrain. This could be especially problematic on the main machine because the flight dynamics cannot fully initialize until the local tile is loaded (and sometimes this bug would cause the local/current tile to be discarded and never reloaded.) We have a cache of loaded tiles that is larger than what you can see ... so if you fly around and then come back, you don't necessarily have to reload scenery that you previously visited if it's still in your cache. It's kind of like your browser cache ... you don't have to reload an image if it's already in the cache if you come back to a page you just visited. When you go to a new area, the new tiles are scheduled to be loaded and then the system goes off and loads them in a background thread. Once the cache fills up, the oldest tiles are removed. So if you start at some airport, then go to some other distant airport, then to yet another airport ... and in the process the tile cache fills up while loading the newest tiles, then the oldest tiles from the original airport would get removed first. The age of tiles is deteremined by a timestamp value that is saved for each tile. However, the tile timestamp is only updated with the tiles are actually in view and drawn (this is a neat capability but it is part of what bit me) ... so tiles from the original location that are behind your view and never seen will never have their time stamp updated and it will remain as zero. Now, when you go to the next location and again new tiles are scheduled and loaded, the new tiles behind you at the new location are also never actually seen or drawn and their time stamp is never actually updated and remains as zero. (Assuming you never turn to look at them.) Now, here is where this was biting me ... Let's say I relocate to a new location that is near the previous location (with the tile cache full), and the new location just happens to be over a previously loaded tile that was previously behind the viewer. This is a tile that is in the cache, but has never been looked at, so it's timestamp is still 0. The new location needs to be far enough away that it triggers the scheduled load of several new tiles. When the new tiles are scheduled and the cache is already full, something has to be removed. The system finds the tile with the oldest timestamp and removes that. However, all tiles that haven't been seen or drawn yet have a timestamp of 0 and they all tie, and this could easily include the tile that is right underneath your new location. So depending on the physical order of tiles in the cache which is random for all practical purpose, the current tile could get removed to make room for new tiles and now we have a huge problem. The FDM can't intialize because no tile is underneath it. And that tile will never get loaded because it was there when the new tiles were scheduled for loading, but was then immediately removed to make room for those new tiles. The code is at an impass and can't proceed. The fix I am proposing gives a current time stamp to each tile when it is loaded (instead of zero.) This should resolve the "tie" among tiles that have never been looked at or drawn. The oldest tiles will indeed be removed. This attached patch fixes the problem I am seeing, but I don't know if it's the best approach from a C++ standpoint. The timestamp is derived from an OSG concept of time which doesn't appear to be easily extractable if you don't have a chunk of the scene graph handy (which is the case when you create a new tile and haven't loaded anything into it yet.) So I created a static member for the cull call back class. Each time the timestamp is updated for any tile, this variable is also updated. I create a dummy instance of the class in static global space of the TileEntry.cxx file to ensure that this static class member is originally initialized to something valid (0.0). That way the first tile loaded won't inadvertently get a random time value if the compiler doesn't initialize the memory space to 0 for us. Anyway, that's probably an overly complex explanation of a very obscure and rare tile cache bug, but before I commit a fix to a portion of code I didn't write, I want to let others have the opportunity to review and comment (and negative comments will hopefully be attached to a proposed better fix.) :-) Thanks, Curt. -- Curtis Olson: http://baron.flightgear.org/~curt/
SimGear-TileEntry.cxx.diff
Description: Binary data
------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________ Flightgear-devel mailing list Flightgear-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/flightgear-devel