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 #include "StreamingTerrain" 00020 #include "StreamingTile" 00021 #include "TransparentLayer" 00022 00023 #include <osgEarth/Registry> 00024 #include <osgEarth/Map> 00025 #include <osgEarth/FindNode> 00026 00027 #include <osg/NodeCallback> 00028 #include <osg/NodeVisitor> 00029 #include <osg/Node> 00030 #include <osgGA/EventVisitor> 00031 00032 #include <OpenThreads/ScopedLock> 00033 00034 using namespace osgEarth; 00035 using namespace OpenThreads; 00036 00037 #define LC "[StreamingTerrain] " 00038 00039 //---------------------------------------------------------------------------- 00040 00041 StreamingTerrain::StreamingTerrain(const MapFrame& update_mapf, 00042 const MapFrame& cull_mapf, 00043 OSGTileFactory* tileFactory, 00044 bool quickReleaseGLObjects ) : 00045 00046 Terrain( update_mapf, cull_mapf, tileFactory, quickReleaseGLObjects ), 00047 _numLoadingThreads( 0 ) 00048 { 00049 _loadingPolicy = tileFactory->getTerrainOptions().loadingPolicy().get(); 00050 00051 setNumChildrenRequiringUpdateTraversal( 1 ); 00052 _alwaysUpdate = true; 00053 _numLoadingThreads = computeLoadingThreads(_loadingPolicy); 00054 00055 OE_INFO << LC << "Using a total of " << _numLoadingThreads << " loading threads " << std::endl; 00056 } 00057 00058 StreamingTerrain::~StreamingTerrain() 00059 { 00060 //nop 00061 } 00062 00063 Tile* 00064 StreamingTerrain::createTile(const TileKey& key, GeoLocator* locator) const 00065 { 00066 return new StreamingTile( key, locator, this->getQuickReleaseGLObjects() ); 00067 } 00068 00069 // This method is called by StreamingTerrain::traverse() in the UPDATE TRAVERSAL. 00070 void 00071 StreamingTerrain::refreshFamily(const MapInfo& mapInfo, 00072 const TileKey& key, 00073 StreamingTile::Relative* family, 00074 bool tileTableLocked ) 00075 { 00076 osgTerrain::TileID tileId = key.getTileId(); 00077 00078 // geocentric maps wrap around in the X dimension. 00079 bool wrapX = mapInfo.isGeocentric(); 00080 unsigned int tileCountX, tileCountY; 00081 mapInfo.getProfile()->getNumTiles( tileId.level, tileCountX, tileCountY ); 00082 00083 // Relative::PARENT 00084 { 00085 family[StreamingTile::Relative::PARENT].expected = true; // TODO: is this always correct? 00086 family[StreamingTile::Relative::PARENT].elevLOD = -1; 00087 family[StreamingTile::Relative::PARENT].imageLODs.clear(); 00088 family[StreamingTile::Relative::PARENT].tileID = osgTerrain::TileID( tileId.level-1, tileId.x/2, tileId.y/2 ); 00089 00090 osg::ref_ptr<StreamingTile> parent; 00091 getTile( family[StreamingTile::Relative::PARENT].tileID, parent, !tileTableLocked ); 00092 if ( parent.valid() ) 00093 { 00094 family[StreamingTile::Relative::PARENT].elevLOD = parent->getElevationLOD(); 00095 00096 ColorLayersByUID relLayers; 00097 parent->getCustomColorLayers( relLayers ); 00098 00099 for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i ) 00100 { 00101 family[StreamingTile::Relative::PARENT].imageLODs[i->first] = i->second.getLevelOfDetail(); 00102 } 00103 } 00104 } 00105 00106 // Relative::WEST 00107 { 00108 family[StreamingTile::Relative::WEST].expected = tileId.x > 0 || wrapX; 00109 family[StreamingTile::Relative::WEST].elevLOD = -1; 00110 family[StreamingTile::Relative::WEST].imageLODs.clear(); 00111 family[StreamingTile::Relative::WEST].tileID = osgTerrain::TileID( tileId.level, tileId.x > 0? tileId.x-1 : tileCountX-1, tileId.y ); 00112 osg::ref_ptr<StreamingTile> west; 00113 getTile( family[StreamingTile::Relative::WEST].tileID, west, !tileTableLocked ); 00114 if ( west.valid() ) 00115 { 00116 family[StreamingTile::Relative::WEST].elevLOD = west->getElevationLOD(); 00117 00118 ColorLayersByUID relLayers; 00119 west->getCustomColorLayers( relLayers ); 00120 00121 for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i ) 00122 { 00123 family[StreamingTile::Relative::WEST].imageLODs[i->first] = i->second.getLevelOfDetail(); 00124 } 00125 } 00126 } 00127 00128 // Relative::NORTH 00129 { 00130 family[StreamingTile::Relative::NORTH].expected = tileId.y < (int)tileCountY-1; 00131 family[StreamingTile::Relative::NORTH].elevLOD = -1; 00132 family[StreamingTile::Relative::NORTH].imageLODs.clear(); 00133 family[StreamingTile::Relative::NORTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y < (int)tileCountY-1 ? tileId.y+1 : 0 ); 00134 osg::ref_ptr<StreamingTile> north; 00135 getTile( family[StreamingTile::Relative::NORTH].tileID, north, !tileTableLocked ); 00136 if ( north.valid() ) 00137 { 00138 family[StreamingTile::Relative::NORTH].elevLOD = north->getElevationLOD(); 00139 00140 ColorLayersByUID relLayers; 00141 north->getCustomColorLayers( relLayers ); 00142 00143 for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i ) 00144 { 00145 family[StreamingTile::Relative::NORTH].imageLODs[i->first] = i->second.getLevelOfDetail(); 00146 } 00147 } 00148 } 00149 00150 // Relative::EAST 00151 { 00152 family[StreamingTile::Relative::EAST].expected = tileId.x < (int)tileCountX-1 || wrapX; 00153 family[StreamingTile::Relative::EAST].elevLOD = -1; 00154 family[StreamingTile::Relative::EAST].imageLODs.clear(); 00155 family[StreamingTile::Relative::EAST].tileID = osgTerrain::TileID( tileId.level, tileId.x < (int)tileCountX-1 ? tileId.x+1 : 0, tileId.y ); 00156 osg::ref_ptr<StreamingTile> east; 00157 getTile( family[StreamingTile::Relative::EAST].tileID, east, !tileTableLocked ); 00158 if ( east.valid() ) 00159 { 00160 family[StreamingTile::Relative::EAST].elevLOD = east->getElevationLOD(); 00161 00162 ColorLayersByUID relLayers; 00163 east->getCustomColorLayers( relLayers ); 00164 00165 for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i ) 00166 { 00167 family[StreamingTile::Relative::EAST].imageLODs[i->first] = i->second.getLevelOfDetail(); 00168 } 00169 } 00170 } 00171 00172 // Relative::SOUTH 00173 { 00174 family[StreamingTile::Relative::SOUTH].expected = tileId.y > 0; 00175 family[StreamingTile::Relative::SOUTH].elevLOD = -1; 00176 family[StreamingTile::Relative::SOUTH].imageLODs.clear(); 00177 family[StreamingTile::Relative::SOUTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y > 0 ? tileId.y-1 : tileCountY-1 ); 00178 osg::ref_ptr<StreamingTile> south; 00179 getTile( family[StreamingTile::Relative::SOUTH].tileID, south, !tileTableLocked ); 00180 if ( south.valid() ) 00181 { 00182 family[StreamingTile::Relative::SOUTH].elevLOD = south->getElevationLOD(); 00183 00184 ColorLayersByUID relLayers; 00185 south->getCustomColorLayers( relLayers ); 00186 00187 for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i ) 00188 { 00189 family[StreamingTile::Relative::SOUTH].imageLODs[i->first] = i->second.getLevelOfDetail(); 00190 } 00191 } 00192 } 00193 } 00194 00195 unsigned 00196 StreamingTerrain::getNumActiveTasks() const 00197 { 00198 ScopedLock<Mutex> lock(const_cast<StreamingTerrain*>(this)->_taskServiceMutex ); 00199 00200 unsigned int total = 0; 00201 for (TaskServiceMap::const_iterator itr = _taskServices.begin(); itr != _taskServices.end(); ++itr) 00202 { 00203 total += itr->second->getNumRequests(); 00204 } 00205 return total; 00206 } 00207 00208 void 00209 StreamingTerrain::updateTraversal( osg::NodeVisitor& nv ) 00210 { 00211 // this stamp keeps track of when requests are dispatched. If a request's stamp gets too 00212 // old, it is considered "expired" and subject to cancelation 00213 int stamp = nv.getFrameStamp()->getFrameNumber(); 00214 00215 // update the frame stamp on the task services. This is necessary to support 00216 // automatic request cancelation for image requests. 00217 { 00218 ScopedLock<Mutex> lock( _taskServiceMutex ); 00219 for (TaskServiceMap::iterator i = _taskServices.begin(); i != _taskServices.end(); ++i) 00220 { 00221 i->second->setStamp( stamp ); 00222 } 00223 } 00224 00225 // next, go through the live tiles and process update-traversal requests. This 00226 // requires a read-lock on the master tiles table. 00227 { 00228 Threading::ScopedReadLock tileTableReadLock( _tilesMutex ); 00229 00230 for( TileTable::const_iterator i = _tiles.begin(); i != _tiles.end(); ++i ) 00231 { 00232 StreamingTile* tile = static_cast<StreamingTile*>( i->second.get() ); 00233 00234 // update the neighbor list for each tile. 00235 refreshFamily( _update_mapf.getMapInfo(), tile->getKey(), tile->getFamily(), true ); 00236 00237 tile->servicePendingElevationRequests( _update_mapf, stamp, true ); 00238 tile->serviceCompletedRequests( _update_mapf, true ); 00239 } 00240 } 00241 } 00242 00243 TaskService* 00244 StreamingTerrain::createTaskService( const std::string& name, int id, int numThreads ) 00245 { 00246 ScopedLock<Mutex> lock( _taskServiceMutex ); 00247 00248 // first, double-check that the service wasn't created during the locking process: 00249 TaskServiceMap::iterator itr = _taskServices.find(id); 00250 if (itr != _taskServices.end()) 00251 return itr->second.get(); 00252 00253 // ok, make a new one 00254 TaskService* service = new TaskService( name, numThreads ); 00255 _taskServices[id] = service; 00256 return service; 00257 } 00258 00259 TaskService* 00260 StreamingTerrain::getTaskService(int id) 00261 { 00262 ScopedLock<Mutex> lock( _taskServiceMutex ); 00263 TaskServiceMap::iterator itr = _taskServices.find(id); 00264 if (itr != _taskServices.end()) 00265 { 00266 return itr->second.get(); 00267 } 00268 return NULL; 00269 } 00270 00271 #define ELEVATION_TASK_SERVICE_ID 9999 00272 #define TILE_GENERATION_TASK_SERVICE_ID 10000 00273 00274 TaskService* 00275 StreamingTerrain::getElevationTaskService() 00276 { 00277 TaskService* service = getTaskService( ELEVATION_TASK_SERVICE_ID ); 00278 if (!service) 00279 { 00280 service = createTaskService( "elevation", ELEVATION_TASK_SERVICE_ID, 1 ); 00281 } 00282 return service; 00283 } 00284 00285 00286 TaskService* 00287 StreamingTerrain::getImageryTaskService(int layerId) 00288 { 00289 TaskService* service = getTaskService( layerId ); 00290 if (!service) 00291 { 00292 std::stringstream buf; 00293 buf << "layer " << layerId; 00294 std::string bufStr = buf.str(); 00295 service = createTaskService( bufStr, layerId, 1 ); 00296 } 00297 return service; 00298 } 00299 00300 TaskService* 00301 StreamingTerrain::getTileGenerationTaskService() 00302 { 00303 TaskService* service = getTaskService( TILE_GENERATION_TASK_SERVICE_ID ); 00304 if (!service) 00305 { 00306 int numCompileThreads = 00307 _loadingPolicy.numCompileThreads().isSet() ? osg::maximum( 1, _loadingPolicy.numCompileThreads().value() ) : 00308 (int)osg::maximum( 1.0f, _loadingPolicy.numCompileThreadsPerCore().value() * (float)GetNumberOfProcessors() ); 00309 00310 service = createTaskService( "tilegen", TILE_GENERATION_TASK_SERVICE_ID, numCompileThreads ); 00311 } 00312 return service; 00313 } 00314 00315 void 00316 StreamingTerrain::updateTaskServiceThreads( const MapFrame& mapf ) 00317 { 00318 //Get the maximum elevation weight 00319 float elevationWeight = 0.0f; 00320 for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); ++itr) 00321 { 00322 ElevationLayer* layer = itr->get(); 00323 float w = layer->getTerrainLayerOptions().loadingWeight().value(); 00324 if (w > elevationWeight) elevationWeight = w; 00325 } 00326 00327 float totalImageWeight = 0.0f; 00328 for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr) 00329 { 00330 totalImageWeight += itr->get()->getTerrainLayerOptions().loadingWeight().value(); 00331 } 00332 00333 float totalWeight = elevationWeight + totalImageWeight; 00334 00335 if (elevationWeight > 0.0f) 00336 { 00337 //Determine how many threads each layer gets 00338 int numElevationThreads = (int)osg::round((float)_numLoadingThreads * (elevationWeight / totalWeight )); 00339 OE_INFO << LC << "Elevation Threads = " << numElevationThreads << std::endl; 00340 getElevationTaskService()->setNumThreads( numElevationThreads ); 00341 } 00342 00343 for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr) 00344 { 00345 const TerrainLayerOptions& opt = itr->get()->getTerrainLayerOptions(); 00346 int imageThreads = (int)osg::round((float)_numLoadingThreads * (opt.loadingWeight().value() / totalWeight )); 00347 OE_INFO << LC << "Image Threads for " << itr->get()->getName() << " = " << imageThreads << std::endl; 00348 getImageryTaskService( itr->get()->getUID() )->setNumThreads( imageThreads ); 00349 } 00350 }