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. :-)
This commit is contained in:
parent
a2049b110f
commit
b0b6c34249
17 changed files with 430 additions and 101 deletions
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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" ) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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; }
|
||||
|
|
141
src/Scenery/FGTileLoader.cxx
Normal file
141
src/Scenery/FGTileLoader.cxx
Normal file
|
@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#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
|
135
src/Scenery/FGTileLoader.hxx
Normal file
135
src/Scenery/FGTileLoader.hxx
Normal file
|
@ -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 <queue>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
# include <simgear/threads/SGThread.hxx>
|
||||
#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
|
|
@ -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 \
|
||||
|
|
|
@ -43,15 +43,11 @@
|
|||
|
||||
#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;
|
||||
|
||||
|
||||
// Constructor
|
||||
FGNewCache::FGNewCache( void ) {
|
||||
tile_cache.clear();
|
||||
|
@ -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() );
|
||||
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 );
|
||||
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 );
|
||||
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 );
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, " distance = " << dist );
|
||||
|
||||
if ( dist > max_dist ) {
|
||||
max_dist = dist;
|
||||
max_index = index;
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -46,18 +46,17 @@
|
|||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
#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; }
|
||||
|
||||
/**
|
||||
* Create a new tile and enqueue it for loading.
|
||||
* @param b
|
||||
*/
|
||||
void load_tile( const SGBucket& b );
|
||||
};
|
||||
|
||||
|
||||
// the tile cache
|
||||
extern FGNewCache global_tile_cache;
|
||||
|
||||
|
||||
#endif // _NEWCACHE_HXX
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,16 +31,12 @@
|
|||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <plib/ssg.h>
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
|
||||
#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(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue