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/

Attachment: 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

Reply via email to