osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_osgterrain/CustomTerrain.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 #if 0
00020 #include "CustomTerrain"
00021 #include "CustomTile"
00022 #include "TransparentLayer"
00023 
00024 #include <osgEarth/Registry>
00025 #include <osgEarth/Map>
00026 #include <osgEarth/FindNode>
00027 
00028 #include <osg/NodeCallback>
00029 #include <osg/NodeVisitor>
00030 #include <osg/Node>
00031 #include <osgGA/EventVisitor>
00032 
00033 #include <OpenThreads/ScopedLock>
00034 
00035 
00036 using namespace osgEarth;
00037 using namespace OpenThreads;
00038 
00039 #define LC "[CustomTerrain] "
00040 
00041 // setting this will enable "fast GL object release" - the engine will activity
00042 // track tiles that expire from the scene graph, and will explicity force them
00043 // to deallocate their GL objects (instead of waiting for OSG to "lazily" 
00044 // release them). This is helpful for freeing up memory more quickly when 
00045 // aggresively navigating a map.
00046 #define QUICK_RELEASE_GL_OBJECTS 1
00047 
00048 //#define PREEMPTIVE_DEBUG 1
00049 
00050 //----------------------------------------------------------------------------
00051 
00052 namespace
00053 {
00057     struct NestingDrawCallback : public osg::Camera::DrawCallback
00058     {
00059         NestingDrawCallback( osg::Camera::DrawCallback* next ) : _next(next) { }
00060 
00061         virtual void operator()( osg::RenderInfo& renderInfo ) const
00062         {
00063             dispatch( renderInfo );
00064         }
00065 
00066         void dispatch( osg::RenderInfo& renderInfo ) const
00067         {
00068             if ( _next )
00069                 _next->operator ()( renderInfo );
00070         }
00071 
00072         osg::ref_ptr<osg::Camera::DrawCallback> _next;
00073     };
00074 
00075 
00076     // a simple draw callback, to be installed on a Camera, that tells all CustomTerrains to
00077     // release GL memory on any expired tiles.
00078     struct QuickReleaseGLCallback : public NestingDrawCallback
00079     {
00080             typedef std::vector< osg::observer_ptr< CustomTerrain > > ObserverTerrainList;
00081 
00082         QuickReleaseGLCallback( CustomTerrain* terrain, osg::Camera::DrawCallback* next )
00083             : NestingDrawCallback(next), _terrain(terrain) { }
00084 
00085         virtual void operator()( osg::RenderInfo& renderInfo ) const
00086         {
00087             osg::ref_ptr<CustomTerrain> terrainSafe = _terrain.get();
00088             if ( terrainSafe.valid() )
00089             {
00090                 terrainSafe->releaseGLObjectsForTiles( renderInfo.getState() );
00091             }
00092             dispatch( renderInfo );
00093         }
00094 
00095         osg::observer_ptr<CustomTerrain> _terrain;
00096     };
00097 }
00098 
00099 //----------------------------------------------------------------------------
00100 
00101 //TODO:  Register with the callback when we are first created...
00102 // immediately release GL memory for any expired tiles.
00103 // called from the DRAW thread
00104 void
00105 CustomTerrain::releaseGLObjectsForTiles(osg::State* state)
00106 {
00107     OpenThreads::ScopedLock<Mutex> lock( _tilesToReleaseMutex );
00108 
00109     //if ( _tilesToRelease.size() > 0 )
00110     //{
00111     //    OE_INFO << "Releasing " << _tilesToRelease.size() << " tiles" << std::endl;
00112     //}
00113 
00114     while( _tilesToRelease.size() > 0 )
00115     {
00116         _tilesToRelease.front()->releaseGLObjects( state );
00117         _tilesToRelease.pop();
00118     }
00119 }
00120 
00121 CustomTerrain::CustomTerrain(const MapFrame& update_mapf, 
00122                              const MapFrame& cull_mapf, 
00123                              OSGTileFactory* tileFactory,
00124                              bool            quickReleaseGLObjects ) :
00125 _revision(0),
00126 _tileFactory( tileFactory ),
00127 _numLoadingThreads( 0 ),
00128 _registeredWithReleaseGLCallback( false ),
00129 _update_mapf( update_mapf ),
00130 _cull_mapf( cull_mapf ),
00131 _onDemandDelay( 2 ),
00132 _quickReleaseGLObjects( quickReleaseGLObjects ),
00133 _quickReleaseCallbackInstalled( false ),
00134 _alwaysUpdate( false )
00135 {
00136     this->setThreadSafeRefUnref( true );
00137 
00138     _loadingPolicy = _tileFactory->getTerrainOptions().loadingPolicy().get();
00139 
00140     if ( _loadingPolicy.mode() != LoadingPolicy::MODE_SERIAL && _loadingPolicy.mode() != LoadingPolicy::MODE_PARALLEL )
00141     {
00142         setNumChildrenRequiringUpdateTraversal( 1 );
00143         _alwaysUpdate = true;
00144         _numLoadingThreads = computeLoadingThreads(_loadingPolicy);
00145         OE_INFO << LC << "Using a total of " << _numLoadingThreads << " loading threads " << std::endl;
00146     }
00147     else
00148     {        
00149         // undo the setting in osgTerrain::Terrain
00150         //setNumChildrenRequiringUpdateTraversal( 0 );
00151 
00152         // the EVENT_VISITOR will reset this to 0 once the "delay" is expired.
00153         _alwaysUpdate = false;
00154         setNumChildrenRequiringUpdateTraversal( 1 );
00155     }
00156 
00157     // register for events in order to support ON_DEMAND frame scheme
00158     setNumChildrenRequiringEventTraversal( 1 );
00159 }
00160 
00161 CustomTerrain::~CustomTerrain()
00162 {
00163     //nop
00164 }
00165 
00166 void
00167 CustomTerrain::incrementRevision()
00168 {
00169     // no need to lock; if we miss it, we'll get it the next time around
00170     _revision++;
00171 }
00172 
00173 int
00174 CustomTerrain::getRevision() const
00175 {
00176     // no need to lock; if we miss it, we'll get it the next time around
00177     return _revision;
00178 }
00179 
00180 void
00181 CustomTerrain::getCustomTile(const osgTerrain::TileID& tileID,
00182                              osg::ref_ptr<CustomTile>& out_tile,
00183                              bool lock )
00184 {
00185     if ( lock )
00186     {
00187         Threading::ScopedReadLock lock( _tilesMutex );
00188         TileTable::iterator i = _tiles.find( tileID );
00189         out_tile = i != _tiles.end()? i->second.get() : 0L;
00190     }
00191     else
00192     {
00193         TileTable::iterator i = _tiles.find( tileID );
00194         out_tile = i != _tiles.end()? i->second.get() : 0L;
00195     }
00196 }
00197 
00198 void
00199 CustomTerrain::getCustomTiles( TileVector& out )
00200 {
00201     Threading::ScopedReadLock lock( _tilesMutex );
00202     out.clear();
00203     out.reserve( _tiles.size() );
00204     for( TileTable::const_iterator i = _tiles.begin(); i != _tiles.end(); ++i )
00205         out.push_back( i->second.get() );
00206 }
00207 
00208 const LoadingPolicy&
00209 CustomTerrain::getLoadingPolicy() const
00210 {
00211     return _loadingPolicy;
00212 }
00213 
00214 // This method is called by CustomTerrain::traverse() in the UPDATE TRAVERSAL.
00215 void
00216 CustomTerrain::refreshFamily(const MapInfo& mapInfo,
00217                              //const osgTerrain::TileID& tileId,
00218                              const TileKey& key,
00219                              Relative* family,
00220                              bool tileTableLocked )
00221 {
00222     osgTerrain::TileID tileId = key.getTileId();
00223 
00224     // geocentric maps wrap around in the X dimension.
00225     bool wrapX = mapInfo.isGeocentric();
00226     unsigned int tileCountX, tileCountY;
00227     mapInfo.getProfile()->getNumTiles( tileId.level, tileCountX, tileCountY );
00228 
00229     // Relative::PARENT
00230     {
00231         family[Relative::PARENT].expected = true; // TODO: is this always correct?
00232         family[Relative::PARENT].elevLOD = -1;
00233         family[Relative::PARENT].imageLODs.clear();
00234         family[Relative::PARENT].tileID = osgTerrain::TileID( tileId.level-1, tileId.x/2, tileId.y/2 );
00235 
00236         osg::ref_ptr<CustomTile> parent;
00237         getCustomTile( family[Relative::PARENT].tileID, parent, !tileTableLocked );
00238         if ( parent.valid() )
00239         {
00240             family[Relative::PARENT].elevLOD = parent->getElevationLOD();
00241 
00242             ColorLayersByUID relLayers;
00243             parent->getCustomColorLayers( relLayers );
00244 
00245             for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
00246             {
00247                 family[Relative::PARENT].imageLODs[i->first] = i->second.getLevelOfDetail();
00248             }
00249         }
00250     }
00251 
00252     // Relative::WEST
00253     {
00254         family[Relative::WEST].expected = tileId.x > 0 || wrapX;
00255         family[Relative::WEST].elevLOD = -1;
00256         family[Relative::WEST].imageLODs.clear();
00257         family[Relative::WEST].tileID = osgTerrain::TileID( tileId.level, tileId.x > 0? tileId.x-1 : tileCountX-1, tileId.y );
00258         osg::ref_ptr<CustomTile> west;
00259         getCustomTile( family[Relative::WEST].tileID, west, !tileTableLocked );
00260         if ( west.valid() )
00261         {
00262             family[Relative::WEST].elevLOD = west->getElevationLOD();
00263 
00264             ColorLayersByUID relLayers;
00265             west->getCustomColorLayers( relLayers );
00266 
00267             for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
00268             {
00269                 family[Relative::WEST].imageLODs[i->first] = i->second.getLevelOfDetail();
00270             }
00271         }
00272     }
00273 
00274     // Relative::NORTH
00275     {
00276         family[Relative::NORTH].expected = tileId.y < (int)tileCountY-1;
00277         family[Relative::NORTH].elevLOD = -1;
00278         family[Relative::NORTH].imageLODs.clear();
00279         family[Relative::NORTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y < (int)tileCountY-1 ? tileId.y+1 : 0 );
00280         osg::ref_ptr<CustomTile> north;
00281         getCustomTile( family[Relative::NORTH].tileID, north, !tileTableLocked );
00282         if ( north.valid() )
00283         {
00284             family[Relative::NORTH].elevLOD = north->getElevationLOD();
00285 
00286             ColorLayersByUID relLayers;
00287             north->getCustomColorLayers( relLayers );
00288 
00289             for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
00290             {
00291                 family[Relative::NORTH].imageLODs[i->first] = i->second.getLevelOfDetail();
00292             }
00293         }
00294     }
00295 
00296     // Relative::EAST
00297     {
00298         family[Relative::EAST].expected = tileId.x < (int)tileCountX-1 || wrapX;
00299         family[Relative::EAST].elevLOD = -1;
00300         family[Relative::EAST].imageLODs.clear();
00301         family[Relative::EAST].tileID = osgTerrain::TileID( tileId.level, tileId.x < (int)tileCountX-1 ? tileId.x+1 : 0, tileId.y );
00302         osg::ref_ptr<CustomTile> east;
00303         getCustomTile( family[Relative::EAST].tileID, east, !tileTableLocked );
00304         if ( east.valid() )
00305         {
00306             family[Relative::EAST].elevLOD = east->getElevationLOD();
00307 
00308             ColorLayersByUID relLayers;
00309             east->getCustomColorLayers( relLayers );
00310 
00311             for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
00312             {
00313                 family[Relative::EAST].imageLODs[i->first] = i->second.getLevelOfDetail();
00314             }
00315         }
00316     }
00317 
00318     // Relative::SOUTH
00319     {
00320         family[Relative::SOUTH].expected = tileId.y > 0;
00321         family[Relative::SOUTH].elevLOD = -1;
00322         family[Relative::SOUTH].imageLODs.clear();
00323         family[Relative::SOUTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y > 0 ? tileId.y-1 : tileCountY-1 );
00324         osg::ref_ptr<CustomTile> south;
00325         getCustomTile( family[Relative::SOUTH].tileID, south, !tileTableLocked );
00326         if ( south.valid() )
00327         {
00328             family[Relative::SOUTH].elevLOD = south->getElevationLOD();
00329 
00330             ColorLayersByUID relLayers;
00331             south->getCustomColorLayers( relLayers );
00332 
00333             for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
00334             {
00335                 family[Relative::SOUTH].imageLODs[i->first] = i->second.getLevelOfDetail();
00336             }
00337         }
00338     }
00339 }
00340 
00341 OSGTileFactory*
00342 CustomTerrain::getTileFactory() {
00343     return _tileFactory.get();
00344 }
00345 
00346 #if 0
00347 void
00348 CustomTerrain::addTerrainCallback( TerrainCallback* cb )
00349 {
00350     _terrainCallbacks.push_back( cb );
00351 }
00352 #endif
00353 
00354 void
00355 CustomTerrain::registerTile( CustomTile* newTile )
00356 {
00357     Threading::ScopedWriteLock exclusiveTileTableLock( _tilesMutex );
00358     _tiles[ newTile->getTileID() ] = newTile;
00359     //OE_INFO << LC << "Registered tiles = " << _tiles.size() << std::endl;
00360 }
00361 
00362 unsigned int
00363 CustomTerrain::getNumTasksRemaining() const
00364 {
00365     ScopedLock<Mutex> lock(const_cast<CustomTerrain*>(this)->_taskServiceMutex );
00366     unsigned int total = 0;
00367     for (TaskServiceMap::const_iterator itr = _taskServices.begin(); itr != _taskServices.end(); ++itr)
00368     {
00369         total += itr->second->getNumRequests();
00370     }
00371     return total;
00372 }
00373 
00374 void
00375 CustomTerrain::traverse( osg::NodeVisitor &nv )
00376 {
00377     // UPDATE runs whenever a Tile runs its update traversal on the first pass.
00378     // i.e., only runs then a new Tile is born.
00379     if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
00380     {
00381         // if the terrain engine requested "quick release", install the quick release
00382         // draw callback now.
00383         if ( _quickReleaseGLObjects && !_quickReleaseCallbackInstalled )
00384         {
00385             osg::Camera* cam = findFirstParentOfType<osg::Camera>( this );
00386             if ( cam )
00387             {
00388                 cam->setPostDrawCallback( new QuickReleaseGLCallback( this, cam->getPostDrawCallback() ) );
00389                 _quickReleaseCallbackInstalled = true;
00390                 OE_INFO << LC << "Quick release enabled" << std::endl;
00391             }
00392         }
00393 
00394         // this stamp keeps track of when requests are dispatched. If a request's stamp gets too
00395         // old, it is considered "expired" and subject to cancelation
00396         int stamp = nv.getFrameStamp()->getFrameNumber();
00397 
00398         // Collect any "dead" tiles and queue them for shutdown.
00399         {
00400             Threading::ScopedWriteLock tileTableExclusiveLock( _tilesMutex );
00401 
00402             for( TileTable::iterator i = _tiles.begin(); i != _tiles.end(); )
00403             {
00404                 CustomTile* tile = i->second.get();
00405                 if ( tile->getNumParents() == 0 && tile->getHasBeenTraversed() )
00406                 {
00407                     _tilesToShutDown.push_back( tile );
00408                     
00409                     // i is incremented prior to calling erase, but i's previous value goes to erase,
00410                     // maintaining validity
00411                     _tiles.erase( i++ );
00412                 }
00413                 else
00414                     ++i;
00415 
00416             }
00417         }
00418 
00419         // Remove any dead tiles from the main tile table, while at the same time queuing 
00420         // any tiles that require quick-release. This criticial section requires an exclusive
00421         // lock on the main tile table.
00422         {
00423             Threading::ScopedMutexLock tilesToReleaseExclusiveLock( _tilesToReleaseMutex );
00424 
00425             // Shut down any dead tiles once there tasks are complete.
00426             for( TileList::iterator i = _tilesToShutDown.begin(); i != _tilesToShutDown.end(); )
00427             {
00428                 CustomTile* tile = i->get();
00429                 if ( tile && tile->cancelRequests() )
00430                 {
00431                     if ( _quickReleaseGLObjects && _quickReleaseCallbackInstalled )
00432                     {
00433                         _tilesToRelease.push( tile );
00434                     }
00435 
00436                     i = _tilesToShutDown.erase( i );
00437                 }
00438                 else
00439                     ++i;
00440             }
00441         }
00442 
00443 //        OE_NOTICE << "Tiles = " << _tiles.size() << std::endl;
00444 
00445         if ( _loadingPolicy.mode() == LoadingPolicy::MODE_SEQUENTIAL || _loadingPolicy.mode() == LoadingPolicy::MODE_PREEMPTIVE )
00446         {
00447             // update the frame stamp on the task services. This is necessary to support 
00448             // automatic request cancelation for image requests.
00449             {
00450                 ScopedLock<Mutex> lock( _taskServiceMutex );
00451                 for (TaskServiceMap::iterator i = _taskServices.begin(); i != _taskServices.end(); ++i)
00452                 {
00453                     i->second->setStamp( stamp );
00454                 }
00455             }
00456 
00457             // next, go through the live tiles and process update-traversal requests. This
00458             // requires a read-lock on the master tiles table.
00459             TileList updatedTiles;
00460             {
00461                 Threading::ScopedReadLock tileTableReadLock( _tilesMutex );
00462 
00463                 for( TileTable::const_iterator i = _tiles.begin(); i != _tiles.end(); ++i )
00464                 {
00465                     CustomTile* tile = i->second.get();
00466 
00467                     // update the neighbor list for each tile.
00468                     refreshFamily( _update_mapf.getMapInfo(), tile->getKey(), tile->getFamily(), true );
00469 
00470                     if ( tile->getUseLayerRequests() ) // i.e., sequential or preemptive mode
00471                     {
00472                         tile->servicePendingElevationRequests( _update_mapf, stamp, true );                   
00473                         tile->serviceCompletedRequests( _update_mapf, true );
00474                         //if ( tileModified && _terrainCallbacks.size() > 0 )
00475                         //{
00476                         //    updatedTiles.push_back( tile );
00477                         //}
00478                     }
00479                 }
00480             }
00481         }
00482 
00483 #if 0
00484         // finally, notify listeners of tile modifications.
00485         if ( updatedTiles.size() > 0 )
00486         {
00487             for( TerrainCallbackList::iterator n = _terrainCallbacks.begin(); n != _terrainCallbacks.end(); ++n )
00488             {
00489                 n->get()->onTerrainTilesUpdated( updatedTiles );
00490             }
00491         }
00492 #endif
00493     }
00494 
00495     else if ( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
00496     {
00497 #if 0
00498         // check each terrain tile for requests (if not in standard mode)
00499         if ( _loadingPolicy.mode() != LoadingPolicy::MODE_STANDARD )
00500         {
00501             int frameStamp = nv.getFrameStamp()->getFrameNumber();
00502 
00503             // make a thread-safe copy of the tile table
00504             CustomTileVector tiles;
00505             getCustomTiles( tiles );
00506 
00507             for( CustomTileVector::iterator i = tiles.begin(); i != tiles.end(); ++i )
00508             {
00509                 CustomTile* tile = i->get();
00510                 tile->servicePendingImageRequests( _cull_mapf, frameStamp );
00511             }
00512         }
00513 #endif
00514     } 
00515     
00516     else if ( nv.getVisitorType() == osg::NodeVisitor::EVENT_VISITOR )
00517     {
00518         // in OSG's "ON_DEMAND" frame scheme, OSG runs the event visitor as part of the
00519         // test to see if a frame is needed. In sequential/preemptive mode, we need to 
00520         // check whether there are any pending tasks running. 
00521 
00522         // In addition, once the tasks run out, we continue to delay on-demand rendering
00523         // for another full frame so that the event dispatchers can catch up.
00524 
00525         if ( _tilesToShutDown.size() > 0 )
00526         {
00527             setDelay( 2 );
00528         }
00529 
00530         else if ( _onDemandDelay <= 0 )
00531         {
00532             int numTasks = getNumTasksRemaining();
00533             if ( numTasks > 0 )
00534             {
00535                 setDelay( 2 );
00536             }
00537         }
00538 
00539         //OE_INFO << "Tasks = " << numTasks << std::endl;
00540 
00541         if ( _onDemandDelay > 0 )
00542         {
00543             osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>( &nv );
00544             ev->getActionAdapter()->requestRedraw();
00545             decDelay();
00546         }
00547     }
00548 
00549     osgTerrain::Terrain::traverse( nv );
00550 }
00551 
00552 void
00553 CustomTerrain::setDelay( unsigned frames )
00554 {
00555     if ( _onDemandDelay == 0 && !_alwaysUpdate )
00556     {
00557         ADJUST_UPDATE_TRAV_COUNT( this, 1 );
00558     }
00559     _onDemandDelay = frames;
00560 }
00561 
00562 void
00563 CustomTerrain::decDelay()
00564 {
00565     _onDemandDelay--;
00566     if ( _onDemandDelay == 0 && !_alwaysUpdate )
00567     {
00568         ADJUST_UPDATE_TRAV_COUNT(this, -1);
00569     }
00570 }
00571 
00572 TaskService*
00573 CustomTerrain::createTaskService( const std::string& name, int id, int numThreads )
00574 {
00575     ScopedLock<Mutex> lock( _taskServiceMutex );
00576 
00577     // first, double-check that the service wasn't created during the locking process:
00578     TaskServiceMap::iterator itr = _taskServices.find(id);
00579     if (itr != _taskServices.end())
00580         return itr->second.get();
00581 
00582     // ok, make a new one
00583     TaskService* service =  new TaskService( name, numThreads );
00584     _taskServices[id] = service;
00585     return service;
00586 }
00587 
00588 TaskService*
00589 CustomTerrain::getTaskService(int id)
00590 {
00591     ScopedLock<Mutex> lock( _taskServiceMutex );
00592     TaskServiceMap::iterator itr = _taskServices.find(id);
00593     if (itr != _taskServices.end())
00594     {
00595         return itr->second.get();
00596     }
00597     return NULL;
00598 }
00599 
00600 #define ELEVATION_TASK_SERVICE_ID 9999
00601 #define TILE_GENERATION_TASK_SERVICE_ID 10000
00602 
00603 TaskService*
00604 CustomTerrain::getElevationTaskService()
00605 {
00606     TaskService* service = getTaskService( ELEVATION_TASK_SERVICE_ID );
00607     if (!service)
00608     {
00609         service = createTaskService( "elevation", ELEVATION_TASK_SERVICE_ID, 1 );
00610     }
00611     return service;
00612 }
00613 
00614 
00615 TaskService*
00616 CustomTerrain::getImageryTaskService(int layerId)
00617 {
00618     TaskService* service = getTaskService( layerId );
00619     if (!service)
00620     {
00621         std::stringstream buf;
00622         buf << "layer " << layerId;
00623         std::string bufStr = buf.str();
00624         service = createTaskService( bufStr, layerId, 1 );
00625     }
00626     return service;
00627 }
00628 
00629 TaskService*
00630 CustomTerrain::getTileGenerationTaskSerivce()
00631 {
00632     TaskService* service = getTaskService( TILE_GENERATION_TASK_SERVICE_ID );
00633     if (!service)
00634     {
00635         int numCompileThreads = 
00636             _loadingPolicy.numCompileThreads().isSet() ? osg::maximum( 1, _loadingPolicy.numCompileThreads().value() ) :
00637             (int)osg::maximum( 1.0f, _loadingPolicy.numCompileThreadsPerCore().value() * (float)GetNumberOfProcessors() );
00638 
00639         service = createTaskService( "tilegen", TILE_GENERATION_TASK_SERVICE_ID, numCompileThreads );
00640     }
00641     return service;
00642 }
00643 
00644 void
00645 CustomTerrain::updateTaskServiceThreads( const MapFrame& mapf )
00646 {
00647     //Get the maximum elevation weight
00648     float elevationWeight = 0.0f;
00649     for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); ++itr)
00650     {
00651         ElevationLayer* layer = itr->get();
00652         float w = layer->getTerrainLayerOptions().loadingWeight().value();
00653         if (w > elevationWeight) elevationWeight = w;
00654     }
00655 
00656     float totalImageWeight = 0.0f;
00657     for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr)
00658     {
00659         totalImageWeight += itr->get()->getTerrainLayerOptions().loadingWeight().value();
00660     }
00661 
00662     float totalWeight = elevationWeight + totalImageWeight;
00663 
00664     if (elevationWeight > 0.0f)
00665     {
00666         //Determine how many threads each layer gets
00667         int numElevationThreads = (int)osg::round((float)_numLoadingThreads * (elevationWeight / totalWeight ));
00668         OE_INFO << LC << "Elevation Threads = " << numElevationThreads << std::endl;
00669         getElevationTaskService()->setNumThreads( numElevationThreads );
00670     }
00671 
00672     for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr)
00673     {
00674         const TerrainLayerOptions& opt = itr->get()->getTerrainLayerOptions();
00675         int imageThreads = (int)osg::round((float)_numLoadingThreads * (opt.loadingWeight().value() / totalWeight ));
00676         OE_INFO << LC << "Image Threads for " << itr->get()->getName() << " = " << imageThreads << std::endl;
00677         getImageryTaskService( itr->get()->getUID() )->setNumThreads( imageThreads );
00678     }
00679 }
00680 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines