]> git.mxchange.org Git - flightgear.git/commitdiff
Make a subtle change to tile loading/unloading policy in order to make the tile
authorcurt <curt>
Wed, 15 Sep 2004 15:52:05 +0000 (15:52 +0000)
committercurt <curt>
Wed, 15 Sep 2004 15:52:05 +0000 (15:52 +0000)
paging system much more robust when position change is very rapid and sporadic.

Recall that we must load 3d models in the main render thread because model
loading can trigger opengl calls (i.e. with texture loading) and all opengl
calls *must* happen in the main render thread.

To accomplish this we load the base tile in the pager thread and build a work
queue of external models that need to be loaded.  We never allow a tile to be
paged out of the tile cache until all it's pending model loads are complete.

However, when changing position very rapidly, we can quickly create a huge
backlog of pending model loads because we are changing positions faster than we
can load the associated models for the existing tiles.  The end result is
that tiles that are long out of range can't be removed because there is still
a huge backlog of pending model load requests and memory blows up.

This change being committed allows the tile paging system to remove tiles
if they are out of range, even when there are pending models to load.  The
model loading code in the render thread can now check to see if the tile
exists and discard any model load request for tiles that no longer exist.

This situation should never occur in normal operation, but could occur in
"contrived" situations where an external script was rapidly changing
the simulator position to then be able to query FG terrain height, and doing
this for a large number of points that are distributed across a large area.

src/Scenery/newcache.cxx
src/Scenery/tileentry.cxx
src/Scenery/tileentry.hxx
src/Scenery/tilemgr.cxx

index e55e2d655dbf395e7f9060d89b0cf6a7accfb363..033e11e8c911cdaef01062be649f975ad8de4b1f 100644 (file)
@@ -125,7 +125,8 @@ bool FGNewCache::make_space() {
        for ( ; current != end; ++current ) {
            long index = current->first;
            FGTileEntry *e = current->second;
-           if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
+           // if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
+           if ( e->is_loaded() ) {
 
                 timestamp = e->get_timestamp();
                 if ( timestamp < min_time ) {
index 6b132e7ee62e2e1a69c43d41f6aea98724354d19..153d49183ceaa1e8e10472607d295244941419b8 100644 (file)
@@ -818,6 +818,7 @@ FGTileEntry::load( const string_list &path_list, bool is_base )
                     FGDeferredModel *dm
                         = new FGDeferredModel( custom_path.str(),
                                                tile_path.str(),
+                                               tile_bucket,
                                                this, obj_trans );
                     FGTileMgr::model_ready( dm );
 
index dfb16965a1680e673ff231e41de83ce4dd3dc398..d3476c061d54ca4a923cdaed8521d153a3c16076 100644 (file)
@@ -70,21 +70,25 @@ private:
     string texture_path;
     FGTileEntry *tile;
     ssgTransform *obj_trans;
+    SGBucket bucket;
+
 
 public:
 
     inline FGDeferredModel() { }
-    inline FGDeferredModel( const string mp, const string tp,
+    inline FGDeferredModel( const string mp, const string tp, SGBucket b,
                     FGTileEntry *t, ssgTransform *ot )
     {
        model_path = mp;
        texture_path = tp;
+        bucket = b;
        tile = t;
        obj_trans = ot;
     }
     inline ~FGDeferredModel() { }
     inline string get_model_path() const { return model_path; }
     inline string get_texture_path() const { return texture_path; }
+    inline SGBucket get_bucket() const { return bucket; }
     inline FGTileEntry *get_tile() const { return tile; }
     inline ssgTransform *get_obj_trans() const { return obj_trans; }
 };
index 3cfe0471e52ed90a0155796ec91670be11b6f149..6730eaea211dee6863007d2e8aab7a975bde6995 100644 (file)
@@ -279,36 +279,51 @@ void FGTileMgr::update_queues()
 {
     // load the next model in the load queue.  Currently this must
     // happen in the render thread because model loading can trigger
-    // texture loading which involves use of the opengl api.
+    // texture loading which involves use of the opengl api.  Skip any
+    // models belonging to not loaded tiles (i.e. the tile was removed
+    // before we were able to load some of the associated models.)
     if ( !model_queue.empty() ) {
-        // cout << "loading next model ..." << endl;
-        // load the next tile in the queue
+        bool processed_one = false;
+
+        while ( model_queue.size() > 200 || processed_one == false ) {
+            processed_one = true;
+
+            if ( model_queue.size() > 200 ) {
+                SG_LOG( SG_TERRAIN, SG_INFO,
+                        "Alert: catching up on model load queue" );
+            }
+
+            // cout << "loading next model ..." << endl;
+            // load the next tile in the queue
 #if defined(ENABLE_THREADS) && ENABLE_THREADS
-        FGDeferredModel* dm = model_queue.pop();
+            FGDeferredModel* dm = model_queue.pop();
 #else
-        FGDeferredModel* dm = model_queue.front();
-        model_queue.pop();
+            FGDeferredModel* dm = model_queue.front();
+            model_queue.pop();
 #endif
 
-        ssgTexturePath( (char *)(dm->get_texture_path().c_str()) );
-        try
-        {
-            ssgEntity *obj_model =
-                globals->get_model_lib()->load_model( ".",
-                                                      dm->get_model_path(),
-                                                      globals->get_props(),
-                                                      globals->get_sim_time_sec() );
-            if ( obj_model != NULL ) {
-                dm->get_obj_trans()->addKid( obj_model );
+            // only load the model if the tile still exists in the
+            // tile cache
+            FGTileEntry *t = tile_cache.get_tile( dm->get_bucket() );
+            if ( t != NULL ) {
+                ssgTexturePath( (char *)(dm->get_texture_path().c_str()) );
+                try {
+                    ssgEntity *obj_model =
+                        globals->get_model_lib()->load_model( ".",
+                                                  dm->get_model_path(),
+                                                  globals->get_props(),
+                                                  globals->get_sim_time_sec() );
+                    if ( obj_model != NULL ) {
+                        dm->get_obj_trans()->addKid( obj_model );
+                    }
+                } catch (const sg_exception& exc) {
+                    SG_LOG( SG_ALL, SG_ALERT, exc.getMessage() );
+                }
+                
+                dm->get_tile()->dec_pending_models();
             }
+            delete dm;
         }
-        catch (const sg_exception& exc)
-        {
-            SG_LOG( SG_ALL, SG_ALERT, exc.getMessage() );
-        }
-
-        dm->get_tile()->dec_pending_models();
-        delete dm;
     }
     
     // cout << "current elevation (ssg) == " << scenery.get_cur_elev() << endl;
@@ -333,26 +348,26 @@ void FGTileMgr::update_queues()
 
     if ( !delete_queue.empty() ) {
         // cout << "delete queue = " << delete_queue.size() << endl;
+        bool processed_one = false;
 
-        while ( delete_queue.size() > 30 ) {
-            // uh oh, delete queue is blowing up, we aren't clearing
-            // it fast enough.  Let's just panic, well not panic, but
-            // get real serious and agressively free up some tiles so
-            // we don't explode our memory usage.
+        while ( delete_queue.size() > 30 || processed_one == false ) {
+            processed_one = true;
 
-            SG_LOG( SG_TERRAIN, SG_ALERT,
-                    "Alert: catching up on tile delete queue" );
+            if ( delete_queue.size() > 30 ) {
+                // uh oh, delete queue is blowing up, we aren't clearing
+                // it fast enough.  Let's just panic, well not panic, but
+                // get real serious and agressively free up some tiles so
+                // we don't explode our memory usage.
 
-            FGTileEntry* e = delete_queue.front();
-            while ( !e->free_tile() );
-            delete_queue.pop();
-            delete e;
-        }
+                SG_LOG( SG_TERRAIN, SG_ALERT,
+                        "Alert: catching up on tile delete queue" );
+            }
 
-        FGTileEntry* e = delete_queue.front();
-        if ( e->free_tile() ) {
-            delete_queue.pop();
-            delete e;
+            FGTileEntry* e = delete_queue.front();
+            if ( e->free_tile() ) {
+                delete_queue.pop();
+                delete e;
+            }
         }
     }
 }