From b0b6c342492868c465417b0fd71c8752e69a8fe5 Mon Sep 17 00:00:00 2001 From: curt Date: Wed, 11 Apr 2001 02:47:15 +0000 Subject: [PATCH] Initial stab at a threaded tile loader contributed by Bernie Bright. He writes: Here are the final changes to add threads to the tile loading. All the thread related code is in the new FGTileLoader class. ./configure.in ./acconfig.h Added --with-threads option and corresponding ENABLE_THREADS definition. The default is no threads. ./src/Scenery/tilemgr Removed load_queue and associated references. This has been replaced by a new class FGTileLoader in FGNewCache. Made the global variable global_tile_cache a member. schedule_needed(): removed global_tile_cache.exists() tests since sched_tile() effectively repeats the test. initialize_queue(): removed code that loads tiles since this is now performed by FGTileLoader. update(): ditto ./src/Scenery/newcache Added new class FGTileLoader to manage tile queuing and loading. tile_map typedefs are private. exists() is a const member function. fill_in(): deleted load_tile(): added. ./src/Scenery/FGTileLoader The new threaded tile loader. Maintains a queue of tiles waiting to be loaded and an array of one or more threads to load the tiles. Currently only a single thread is created. The queue is guarded by a mutex to synchronize access. A condition variable signals the thread when the queue is non-empty. CLO: I made a few tweaks to address a couple issues, hopefully what we have is solid, but now we kick it out to the general public to see. :-) --- acconfig.h | 3 + src/FDM/flight.hxx | 4 +- src/Include/config.h.in | 3 + src/Main/Makefile.am | 7 ++ src/Main/main.cxx | 4 +- src/Objects/matlib.cxx | 25 ++++--- src/Objects/newmat.cxx | 14 ++-- src/Objects/newmat.hxx | 7 +- src/Scenery/FGTileLoader.cxx | 141 +++++++++++++++++++++++++++++++++++ src/Scenery/FGTileLoader.hxx | 135 +++++++++++++++++++++++++++++++++ src/Scenery/Makefile.am | 1 + src/Scenery/newcache.cxx | 81 ++++++++++++-------- src/Scenery/newcache.hxx | 30 +++++--- src/Scenery/tileentry.cxx | 2 +- src/Scenery/tileentry.hxx | 6 ++ src/Scenery/tilemgr.cxx | 57 +++++++------- src/Scenery/tilemgr.hxx | 19 ++--- 17 files changed, 434 insertions(+), 105 deletions(-) create mode 100644 src/Scenery/FGTileLoader.cxx create mode 100644 src/Scenery/FGTileLoader.hxx diff --git a/acconfig.h b/acconfig.h index b25353bc3..94ae557f8 100644 --- a/acconfig.h +++ b/acconfig.h @@ -322,6 +322,9 @@ /* Define if lex declares yytext as a char * by default, not a char[]. */ #undef YYTEXT_POINTER +/* Define to use tile loading threads */ +#undef ENABLE_THREADS + /* Leave that blank line there!! Autoheader needs it. If you're adding to this file, keep in mind: diff --git a/src/FDM/flight.hxx b/src/FDM/flight.hxx index 20e226780..c04b12b8a 100644 --- a/src/FDM/flight.hxx +++ b/src/FDM/flight.hxx @@ -453,8 +453,8 @@ public: virtual void unbind (); virtual void update (); virtual bool update( int multi_loop ); - virtual bool ToggleDataLogging(bool state) {}; - virtual bool ToggleDataLogging(void) {}; + virtual bool ToggleDataLogging(bool state) { return false; } + virtual bool ToggleDataLogging(void) { return false; } // Define the various supported flight models (many not yet implemented) enum { diff --git a/src/Include/config.h.in b/src/Include/config.h.in index b1c6758c2..3c18956c7 100644 --- a/src/Include/config.h.in +++ b/src/Include/config.h.in @@ -103,6 +103,9 @@ /* Define if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING +/* Define to use tile loading threads */ +#undef ENABLE_THREADS + /* Define if you have the GetLocalTime function. */ #undef HAVE_GETLOCALTIME diff --git a/src/Main/Makefile.am b/src/Main/Makefile.am index 1f8250ec6..15af75a39 100644 --- a/src/Main/Makefile.am +++ b/src/Main/Makefile.am @@ -19,6 +19,12 @@ NETWORK_LIBS = \ $(top_builddir)/src/Network/libNetwork.a endif +if WITH_THREADS +THREAD_LIBS = -lsgthreads +else +THREAD_LIBS = +endif + if OLD_AUTOMAKE # nothing CXXFLAGS += -DPKGLIBDIR=\"$(pkglibdir)\" else @@ -73,6 +79,7 @@ fgfs_LDADD = \ -lsgroute -lsgsky -lsgephem -lsgtiming -lsgio -lsgscreen \ -lsgmath -lsgbucket -lsgdebug -lsgmagvar -lsgmisc -lsgxml \ $(SERIAL_LIBS) \ + $(THREAD_LIBS) \ -lplibpu -lplibfnt -lplibssg -lplibsg \ -lmk4 -lz \ $(opengl_LIBS) \ diff --git a/src/Main/main.cxx b/src/Main/main.cxx index c4b6cd0de..1eb0ae685 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -787,9 +787,9 @@ void fgUpdateTimeDepCalcs() { cur_fdm_state->update( 0 ); FGSteam::update( 0 ); - if ( global_tile_mgr.queue_size() == 0 ) { + //if ( global_tile_mgr.queue_size() == 0 ) { initial_freeze = false; - } + //} } if ( fgGetString("/sim/view-mode") == "pilot" ) { diff --git a/src/Objects/matlib.cxx b/src/Objects/matlib.cxx index b1449a08e..25535f8f4 100644 --- a/src/Objects/matlib.cxx +++ b/src/Objects/matlib.cxx @@ -129,15 +129,16 @@ bool FGMaterialLib::load( const string& mpath ) { in >> m; // build the ssgSimpleState - SGPath tex_path( globals->get_fg_root() ); - tex_path.append( "Textures.high" ); + SGPath tmp_path( globals->get_fg_root() ); + tmp_path.append( "Textures.high" ); - SGPath tmp_path = tex_path; - tmp_path.append( m.get_texture_name() ); - if ( ! local_file_exists(tmp_path.str()) + SGPath tex_path = tmp_path; + tex_path.append( m.get_texture_name() ); + if ( ! local_file_exists(tex_path.str()) || general.get_glMaxTexSize() < 512 ) { tex_path = SGPath( globals->get_fg_root() ); tex_path.append( "Textures" ); + tex_path.append( m.get_texture_name() ); } SG_LOG( SG_TERRAIN, SG_INFO, " Loading material " @@ -150,8 +151,10 @@ bool FGMaterialLib::load( const string& mpath ) { shade_model = GL_FLAT; } - m.build_ssg_state( tex_path.str(), shade_model, - fgGetBool("/sim/rendering/textures") ); + m.set_texture_name( tex_path.str() ); + m.build_ssg_state( shade_model, + fgGetBool("/sim/rendering/textures"), + false ); #if EXTRA_DEBUG m.dump_info(); @@ -201,10 +204,10 @@ bool FGMaterialLib::add_item ( const string &mat_name, const string &full_path ) string tex_name = full_path.substr( pos + 1 ); string tex_path = full_path.substr( 0, pos ); - FGNewMat m( mat_name, tex_name ); + FGNewMat m( mat_name, full_path ); SG_LOG( SG_TERRAIN, SG_INFO, " Loading material " - << mat_name << " (" << tex_path << ")"); + << mat_name << " (" << full_path << ")"); #if EXTRA_DEBUG m.dump_info(); @@ -217,8 +220,8 @@ bool FGMaterialLib::add_item ( const string &mat_name, const string &full_path ) shade_model = GL_FLAT; } - m.build_ssg_state( tex_path, shade_model, - fgGetBool("/sim/rendering/textures") ); + m.build_ssg_state( shade_model, fgGetBool("/sim/rendering/textures"), + true ); material_lib.matlib[mat_name] = m; diff --git a/src/Objects/newmat.cxx b/src/Objects/newmat.cxx index 15c82ad06..2fa702d61 100644 --- a/src/Objects/newmat.cxx +++ b/src/Objects/newmat.cxx @@ -70,12 +70,9 @@ FGNewMat::FGNewMat ( const string &mat_name, const string &tex_name ) } -void FGNewMat::build_ssg_state( const string& path, - GLenum shade_model, bool texture_default ) +void FGNewMat::build_ssg_state( GLenum shade_model, bool texture_default, + bool defer_tex_load ) { - SGPath tex_file( path ); - tex_file.append( texture_name ); - state = new ssgStateSelector(2); state->ref(); @@ -92,7 +89,12 @@ void FGNewMat::build_ssg_state( const string& path, textured->enable( GL_TEXTURE_2D ); textured->disable( GL_BLEND ); textured->disable( GL_ALPHA_TEST ); - textured->setTexture( (char *)tex_file.c_str(), wrapu, wrapv ); + if ( !defer_tex_load ) { + textured->setTexture( (char *)texture_name.c_str(), wrapu, wrapv ); + texture_loaded = true; + } else { + texture_loaded = false; + } // cout << "wrap u = " << wrapu << " wrapv = " << wrapv << endl; textured->enable( GL_COLOR_MATERIAL ); textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE ); diff --git a/src/Objects/newmat.hxx b/src/Objects/newmat.hxx index 43a640ef6..39ff8f499 100644 --- a/src/Objects/newmat.hxx +++ b/src/Objects/newmat.hxx @@ -89,6 +89,9 @@ private: // material properties sgVec4 ambient, diffuse, specular, emission; + // true if texture loading deferred, and not yet loaded + bool texture_loaded; + public: // Constructor @@ -102,8 +105,8 @@ public: friend istream& operator >> ( istream& in, FGNewMat& m ); // void load_texture( const string& root ); - void build_ssg_state( const string& path, - GLenum shade_model, bool texture_default ); + void build_ssg_state( GLenum shade_model, bool texture_default, + bool defer_tex_load = false ); void set_ssg_state( ssgSimpleState *s ); inline string get_material_name() const { return material_name; } diff --git a/src/Scenery/FGTileLoader.cxx b/src/Scenery/FGTileLoader.cxx new file mode 100644 index 000000000..5123953e6 --- /dev/null +++ b/src/Scenery/FGTileLoader.cxx @@ -0,0 +1,141 @@ +// FGTileLoader - Queue scenery tiles for loading. +// +// Written by Bernie Bright, started March 2001. +// +// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include
+#include "FGTileLoader.hxx" +#include "tileentry.hxx" + +/** + * + */ +FGTileLoader::FGTileLoader() +{ +#ifdef ENABLE_THREADS + // Create and start the loader threads. + for (int i = 0; i < MAX_THREADS; ++i) + { + threads[i] = new LoaderThread(this); + threads[i]->start(); + } +#endif // ENABLE_THREADS +} + +/** + * Terminate all threads. + */ +FGTileLoader::~FGTileLoader() +{ +#ifdef ENABLE_THREADS + // Wake up its time to die. + cond.broadcast(); + + for (int i = 0; i < MAX_THREADS; ++i) + { + threads[i]->cancel(); + threads[i]->join(); + } +#endif // ENABLE_THREADS +} + +/** + * + */ +void +FGTileLoader::add( FGTileEntry* tile ) +{ + /** + * Initialise tile_path here and not in ctor to avoid problems + * with the initialastion order of global objects. + */ + static bool beenhere = false; + if (!beenhere) + { + if ( globals->get_fg_scenery() != (string)"" ) { + tile_path.set( globals->get_fg_scenery() ); + } else { + tile_path.set( globals->get_fg_root() ); + tile_path.append( "Scenery" ); + } + beenhere = true; + } + +#ifdef ENABLE_THREADS + mutex.lock(); + tile_queue.push( tile ); + // Signal waiting working threads. + cond.signal(); + mutex.unlock(); +#else + tile->load( tile_path, true ); +#endif // ENABLE_THREADS +} + +#ifdef ENABLE_THREADS +/** + * + */ +void +FGTileLoader::LoaderThread::run() +{ + pthread_cleanup_push( cleanup_handler, loader ); + while ( true ) { + // Wait for a load request to be placed in the queue. + loader->mutex.lock(); + while (loader->empty()) + { + loader->cond.wait( loader->mutex ); + } + + // Have we been canceled - exits if yes. + //pthread_testcancel(); + if (loader->empty()) + { + loader->mutex.unlock(); + pthread_exit( PTHREAD_CANCELED ); + } + + // Grab the tile to load and release the mutex. + FGTileEntry* tile = loader->tile_queue.front(); + loader->tile_queue.pop(); + loader->mutex.unlock(); + + set_cancel( SGThread::CANCEL_DISABLE ); + tile->load( loader->tile_path, true ); + set_cancel( SGThread::CANCEL_DEFERRED ); + } + pthread_cleanup_pop(1); +} + +/** + * Ensure mutex is unlocked. + */ +void +cleanup_handler( void* arg ) +{ + FGTileLoader* loader = (FGTileLoader*) arg; + loader->mutex.unlock(); +} +#endif // ENABLE_THREADS diff --git a/src/Scenery/FGTileLoader.hxx b/src/Scenery/FGTileLoader.hxx new file mode 100644 index 000000000..f74ac3d16 --- /dev/null +++ b/src/Scenery/FGTileLoader.hxx @@ -0,0 +1,135 @@ +// FGTileLoader - Queue scenery tiles for loading. +// +// Written by Bernie Bright, started March 2001. +// +// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef FG_TILE_LOADER_HXX +#define FG_TILE_LOADER_HXX + +#include +#include + +#include +#include + +#ifdef ENABLE_THREADS +# include +#endif + +// Forward reference. +class FGTileEntry; + +/** + * Queues tiles for loading, possibly by a separate thread. + */ +class FGTileLoader +{ +public: + + /** + * Constructor. + */ + FGTileLoader(); + + /** + * Destructor. + */ + ~FGTileLoader(); + + /** + * Add a tile to the end of the load queue. + * @param tile The tile to be loaded from disk. + * @param vis Current visibilty (in feet?) (see FGTileMgr::vis). + */ + void add( FGTileEntry* tile ); + + /** + * Returns whether the load queue is empty (contains no elements). + * @return true if load queue is empty otherwise returns false. + */ + bool empty() const { return tile_queue.empty(); } + +private: + +private: + + /** + * FIFO queue of tiles to load from data files. + */ + std::queue< FGTileEntry* > tile_queue; + + /** + * Base name of directory containing tile data file. + */ + SGPath tile_path; + +#ifdef ENABLE_THREADS + /** + * Maximum number of threads to create for loading tiles. + */ + enum { MAX_THREADS = 1 }; + + /** + * This class represents the thread of execution responsible for + * loading a tile. + */ + class LoaderThread : public SGThread + { + public: + LoaderThread( FGTileLoader* l ) : loader(l) {} + ~LoaderThread() {} + + /** + * Reads the tile from disk. + */ + void run(); + + private: + FGTileLoader* loader; + + private: + // not implemented. + LoaderThread(); + LoaderThread( const LoaderThread& ); + LoaderThread& operator=( const LoaderThread& ); + }; + + friend class LoaderThread; + + /** + * Array of loading threads. + */ + LoaderThread* threads[ MAX_THREADS ]; + + /** + * Lock and synchronize access to tile queue. + */ + SGMutex mutex; + SGCondition cond; + + /** + * Thread cleanup handler. + */ + friend void cleanup_handler( void* ); +#endif // ENABLE_THREADS +}; + +#endif // FG_TILE_LOADER_HXX diff --git a/src/Scenery/Makefile.am b/src/Scenery/Makefile.am index 370762135..c79da6009 100644 --- a/src/Scenery/Makefile.am +++ b/src/Scenery/Makefile.am @@ -1,6 +1,7 @@ noinst_LIBRARIES = libScenery.a libScenery_a_SOURCES = \ + FGTileLoader.cxx FGTileLoader.hxx \ hitlist.cxx hitlist.hxx \ newcache.cxx newcache.hxx \ scenery.cxx scenery.hxx \ diff --git a/src/Scenery/newcache.cxx b/src/Scenery/newcache.cxx index b6d26bb7f..46c3ef44b 100644 --- a/src/Scenery/newcache.cxx +++ b/src/Scenery/newcache.cxx @@ -43,13 +43,9 @@ #include "newcache.hxx" #include "tileentry.hxx" -#include "tilemgr.hxx" // temp, need to delete later - -SG_USING_NAMESPACE(std); -// the tile cache -FGNewCache global_tile_cache; +SG_USING_NAMESPACE(std); // Constructor @@ -68,7 +64,7 @@ void FGNewCache::entry_free( long cache_index ) { SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index ); FGTileEntry *e = tile_cache[cache_index]; e->free_tile(); - delete( e ); + delete e; tile_cache.erase( cache_index ); } @@ -107,14 +103,16 @@ void FGNewCache::init( void ) { // Search for the specified "bucket" in the cache -bool FGNewCache::exists( const SGBucket& b ) { +bool FGNewCache::exists( const SGBucket& b ) const { long tile_index = b.gen_index(); - tile_map_iterator it = tile_cache.find( tile_index ); + const_tile_map_iterator it = tile_cache.find( tile_index ); return ( it != tile_cache.end() ); } +// depricated for threading +#if 0 // Fill in a tile cache entry with real data for the specified bucket void FGNewCache::fill_in( const SGBucket& b ) { SG_LOG( SG_TERRAIN, SG_DEBUG, "FILL IN CACHE ENTRY = " << b.gen_index() ); @@ -140,13 +138,12 @@ void FGNewCache::fill_in( const SGBucket& b ) { // Load the appropriate data file e->load( tile_path, true ); } +#endif // Ensure at least one entry is free in the cache void FGNewCache::make_space() { SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" ); - - SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() ); SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size ); @@ -169,26 +166,29 @@ void FGNewCache::make_space() { long index = current->first; FGTileEntry *e = current->second; - // calculate approximate distance from view point - sgdCopyVec3( abs_view_pos, - globals->get_current_view()->get_abs_view_pos() ); - - SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " - << abs_view_pos[0] << "," - << abs_view_pos[1] << "," - << abs_view_pos[2] ); - SG_LOG( SG_TERRAIN, SG_DEBUG, - " ref point = " << e->center ); - - sgdVec3 center; - sgdSetVec3( center, e->center.x(), e->center.y(), e->center.z() ); - dist = sgdDistanceVec3( center, abs_view_pos ); - - SG_LOG( SG_TERRAIN, SG_DEBUG, " distance = " << dist ); - - if ( dist > max_dist ) { - max_dist = dist; - max_index = index; + if ( e->is_loaded() ) { + // calculate approximate distance from view point + sgdCopyVec3( abs_view_pos, + globals->get_current_view()->get_abs_view_pos() ); + + SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " + << abs_view_pos[0] << "," + << abs_view_pos[1] << "," + << abs_view_pos[2] ); + SG_LOG( SG_TERRAIN, SG_DEBUG, + " ref point = " << e->center ); + + sgdVec3 center; + sgdSetVec3( center, + e->center.x(), e->center.y(), e->center.z() ); + dist = sgdDistanceVec3( center, abs_view_pos ); + + SG_LOG( SG_TERRAIN, SG_DEBUG, " distance = " << dist ); + + if ( dist > max_dist ) { + max_dist = dist; + max_index = index; + } } } @@ -206,3 +206,24 @@ void FGNewCache::make_space() { } } } + + +/** + * Create a new tile and schedule it for loading. + */ +void +FGNewCache::load_tile( const SGBucket& b ) +{ + // clear out a distant entry in the cache if needed. + make_space(); + + // create the entry + FGTileEntry *e = new FGTileEntry( b ); + + // register it in the cache + long tile_index = b.gen_index(); + tile_cache[tile_index] = e; + + // Schedule tile for loading + loader.add( e ); +} diff --git a/src/Scenery/newcache.hxx b/src/Scenery/newcache.hxx index ed7486f57..4eb92388e 100644 --- a/src/Scenery/newcache.hxx +++ b/src/Scenery/newcache.hxx @@ -46,18 +46,17 @@ #include #include "tileentry.hxx" +#include "FGTileLoader.hxx" SG_USING_STD(map); - -typedef map < long, FGTileEntry * > tile_map; -typedef tile_map::iterator tile_map_iterator; -typedef tile_map::const_iterator const_tile_map_iterator; - - // A class to store and manage a pile of tiles class FGNewCache { + typedef map < long, FGTileEntry * > tile_map; + typedef tile_map::iterator tile_map_iterator; + typedef tile_map::const_iterator const_tile_map_iterator; + // cache storage space tile_map tile_cache; @@ -70,6 +69,11 @@ class FGNewCache { // Free a tile cache entry void entry_free( long cache_index ); + /** + * Queue tiles for loading. + */ + FGTileLoader loader; + public: // Constructor @@ -82,13 +86,13 @@ public: void init( void ); // Check if the specified "bucket" exists in the cache - bool exists( const SGBucket& b ); + bool exists( const SGBucket& b ) const; // Ensure at least one entry is free in the cache void make_space(); // Fill in a tile cache entry with real data for the specified bucket - void fill_in( const SGBucket& b ); + // void fill_in( const SGBucket& b ); // Return a pointer to the specified tile cache entry inline FGTileEntry *get_tile( const long tile_index ) { @@ -119,11 +123,13 @@ public: inline int get_max_cache_size() const { return max_cache_size; } inline void set_max_cache_size( int m ) { max_cache_size = m; } -}; - -// the tile cache -extern FGNewCache global_tile_cache; + /** + * Create a new tile and enqueue it for loading. + * @param b + */ + void load_tile( const SGBucket& b ); +}; #endif // _NEWCACHE_HXX diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx index d6964a24e..f7c2a5e05 100644 --- a/src/Scenery/tileentry.cxx +++ b/src/Scenery/tileentry.cxx @@ -339,7 +339,7 @@ FGTileEntry::load( const SGPath& base, bool is_base ) basename.append( index_str ); string path = basename.str(); - SG_LOG( SG_TERRAIN, SG_INFO, "Loading tile " << path ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "Loading tile " << path ); // fgObjLoad will generate ground lighting for us ... ssgVertexArray *light_pts = new ssgVertexArray( 100 ); diff --git a/src/Scenery/tileentry.hxx b/src/Scenery/tileentry.hxx index 091110212..d2ff2909f 100644 --- a/src/Scenery/tileentry.hxx +++ b/src/Scenery/tileentry.hxx @@ -160,6 +160,12 @@ public: * random ground light points */ void load( const SGPath& base, bool is_base ); + + /** + * Return true if the tile entry is loaded, otherwise return false + * indicating that the loading thread is still working on this. + */ + inline bool is_loaded() const { return loaded; } }; diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index 3b1f4315e..4bdcfda59 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -93,7 +93,7 @@ int FGTileMgr::init() { } else { SG_LOG( SG_TERRAIN, SG_INFO, "... First time through." ); - global_tile_cache.init(); + tile_cache.init(); } hit_list.clear(); @@ -113,29 +113,32 @@ int FGTileMgr::init() { // schedule a tile for loading void FGTileMgr::sched_tile( const SGBucket& b ) { // see if tile already exists in the cache - FGTileEntry *t = global_tile_cache.get_tile( b ); + FGTileEntry *t = tile_cache.get_tile( b ); if ( t == NULL ) { // register a load request - load_queue.push_back( b ); + tile_cache.load_tile( b ); } } +// depricated for threading +#if 0 // load a tile void FGTileMgr::load_tile( const SGBucket& b ) { // see if tile already exists in the cache - FGTileEntry *t = global_tile_cache.get_tile( b ); + FGTileEntry *t = tile_cache.get_tile( b ); if ( t == NULL ) { SG_LOG( SG_TERRAIN, SG_DEBUG, "Loading tile " << b ); - global_tile_cache.fill_in( b ); - t = global_tile_cache.get_tile( b ); + tile_cache.fill_in( b ); + t = tile_cache.get_tile( b ); t->prep_ssg_node( scenery.center, vis); } else { SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile already in cache " << b ); } } +#endif static void CurrentNormalInLocalPlane(sgVec3 dst, sgVec3 src) { @@ -215,20 +218,20 @@ void FGTileMgr::schedule_needed() { #else vis = current_weather.get_visibility(); #endif - cout << "visibility = " << vis << endl; + // cout << "visibility = " << vis << endl; double tile_width = current_bucket.get_width_m(); double tile_height = current_bucket.get_height_m(); - cout << "tile width = " << tile_width << " tile_height = " << tile_height - << endl; + // cout << "tile width = " << tile_width << " tile_height = " + // << tile_height !<< endl; xrange = (int)(vis / tile_width) + 1; yrange = (int)(vis / tile_height) + 1; if ( xrange < 1 ) { xrange = 1; } if ( yrange < 1 ) { yrange = 1; } - cout << "xrange = " << xrange << " yrange = " << yrange << endl; + // cout << "xrange = " << xrange << " yrange = " << yrange << endl; - global_tile_cache.set_max_cache_size( (2*xrange + 2) * (2*yrange + 2) ); + tile_cache.set_max_cache_size( (2*xrange + 2) * (2*yrange + 2) ); SGBucket b; @@ -243,9 +246,7 @@ void FGTileMgr::schedule_needed() { for ( y = -1; y <= 1; ++y ) { if ( x != 0 || y != 0 ) { b = sgBucketOffset( longitude, latitude, x, y ); - if ( ! global_tile_cache.exists( b ) ) { - sched_tile( b ); - } + sched_tile( b ); } } } @@ -255,9 +256,7 @@ void FGTileMgr::schedule_needed() { for ( y = -yrange; y <= yrange; ++y ) { if ( x < -1 || x > 1 || y < -1 || y > 1 ) { SGBucket b = sgBucketOffset( longitude, latitude, x, y ); - if ( ! global_tile_cache.exists( b ) ) { - sched_tile( b ); - } + sched_tile( b ); } } } @@ -270,12 +269,12 @@ void FGTileMgr::initialize_queue() // system and load all relavant tiles SG_LOG( SG_TERRAIN, SG_INFO, "Updating Tile list for " << current_bucket ); - cout << "tile cache size = " << global_tile_cache.get_size() << endl; + // cout << "tile cache size = " << tile_cache.get_size() << endl; int i; // wipe/initialize tile cache - // global_tile_cache.init(); + // tile_cache.init(); previous_bucket.make_bad(); // build the local area list and schedule tiles for loading @@ -285,6 +284,8 @@ void FGTileMgr::initialize_queue() schedule_needed(); + // do we really want to lose this? CLO +#if 0 // Now force a load of the center tile and inner ring so we // have something to see in our first frame. for ( i = 0; i < 9; ++i ) { @@ -297,6 +298,7 @@ void FGTileMgr::initialize_queue() load_tile( pending ); } } +#endif } @@ -305,7 +307,7 @@ void FGTileMgr::initialize_queue() // tile_cache -- which actually handles all the // (de)allocations void FGTileMgr::destroy_queue() { - load_queue.clear(); + // load_queue.clear(); } @@ -328,8 +330,8 @@ int FGTileMgr::update( double lon, double lat ) { current_bucket.set_bucket( longitude, latitude ); // SG_LOG( SG_TERRAIN, SG_DEBUG, "Updating Tile list for " << current_bucket ); - if ( global_tile_cache.exists( current_bucket ) ) { - current_tile = global_tile_cache.get_tile( current_bucket ); + if ( tile_cache.exists( current_bucket ) ) { + current_tile = tile_cache.get_tile( current_bucket ); scenery.next_center = current_tile->center; } else { SG_LOG( SG_TERRAIN, SG_WARN, "Tile not found (Ok if initializing)" ); @@ -346,6 +348,8 @@ int FGTileMgr::update( double lon, double lat ) { state = Running; } + // now handled by threaded tile pager +#if 0 if ( load_queue.size() ) { SG_LOG( SG_TERRAIN, SG_INFO, "Load queue size = " << load_queue.size() << " loading a tile" ); @@ -354,6 +358,7 @@ int FGTileMgr::update( double lon, double lat ) { load_queue.pop_front(); load_tile( pending ); } +#endif if ( scenery.center == Point3D(0.0) ) { // initializing @@ -419,15 +424,15 @@ void FGTileMgr::prep_ssg_nodes() { // selector and transform FGTileEntry *e; - global_tile_cache.reset_traversal(); + tile_cache.reset_traversal(); - while ( ! global_tile_cache.at_end() ) { + while ( ! tile_cache.at_end() ) { // cout << "processing a tile" << endl; - if ( (e = global_tile_cache.get_current()) ) { + if ( (e = tile_cache.get_current()) ) { e->prep_ssg_node( scenery.center, vis); } else { cout << "warning ... empty tile in cache" << endl; } - global_tile_cache.next(); + tile_cache.next(); } } diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index 49d7135a6..e3f49e54c 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -31,16 +31,12 @@ #include -#include - #include #include #include "hitlist.hxx" - -SG_USING_STD(list); - +#include "newcache.hxx" #if defined(USE_MEM) || defined(WIN32) # define FG_MEM_COPY(to,from,n) memcpy(to, from, n) @@ -66,9 +62,6 @@ private: load_state state; - // pending tile load queue - list < SGBucket > load_queue; - // initialize the cache void initialize_queue(); @@ -80,9 +73,6 @@ private: // schedule a tile for loading void sched_tile( const SGBucket& b ); - // load a tile - void load_tile( const SGBucket& b ); - // schedule a needed buckets for loading void schedule_needed(); @@ -111,6 +101,11 @@ private: double last_longitude; double last_latitude; + /** + * + */ + FGNewCache tile_cache; + public: // Constructor @@ -144,8 +139,6 @@ public: // transform and update it's range selector based on current // visibilty void prep_ssg_nodes(); - - inline int queue_size() const { return load_queue.size(); } }; -- 2.39.5