osgEarth 2.1.1
|
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