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 "Terrain" 00020 #include "Tile" 00021 #include "TransparentLayer" 00022 00023 #include <osgEarth/Registry> 00024 #include <osgEarth/Map> 00025 #include <osgEarth/FindNode> 00026 #include <osgEarth/ThreadingUtils> 00027 00028 #include <osg/NodeCallback> 00029 #include <osg/NodeVisitor> 00030 #include <osg/Node> 00031 #include <osgGA/EventVisitor> 00032 00033 using namespace osgEarth; 00034 using namespace OpenThreads; 00035 00036 #define LC "[Terrain] " 00037 00038 //---------------------------------------------------------------------------- 00039 00040 namespace 00041 { 00045 struct NestingDrawCallback : public osg::Camera::DrawCallback 00046 { 00047 NestingDrawCallback( osg::Camera::DrawCallback* next ) : _next(next) { } 00048 00049 virtual void operator()( osg::RenderInfo& renderInfo ) const 00050 { 00051 dispatch( renderInfo ); 00052 } 00053 00054 void dispatch( osg::RenderInfo& renderInfo ) const 00055 { 00056 if ( _next ) 00057 _next->operator ()( renderInfo ); 00058 } 00059 00060 osg::ref_ptr<osg::Camera::DrawCallback> _next; 00061 }; 00062 00063 00064 // a simple draw callback, to be installed on a Camera, that tells all Terrains to 00065 // release GL memory on any expired tiles. 00066 struct QuickReleaseGLCallback : public NestingDrawCallback 00067 { 00068 typedef std::vector< osg::observer_ptr<Terrain> > ObserverTerrainList; 00069 00070 QuickReleaseGLCallback( Terrain* terrain, osg::Camera::DrawCallback* next ) 00071 : NestingDrawCallback(next), _terrain(terrain) { } 00072 00073 virtual void operator()( osg::RenderInfo& renderInfo ) const 00074 { 00075 osg::ref_ptr<Terrain> terrainSafe = _terrain.get(); 00076 if ( terrainSafe.valid() ) 00077 { 00078 terrainSafe->releaseGLObjectsForTiles( renderInfo.getState() ); 00079 } 00080 dispatch( renderInfo ); 00081 } 00082 00083 osg::observer_ptr<Terrain> _terrain; 00084 }; 00085 } 00086 00087 //---------------------------------------------------------------------------- 00088 00089 Terrain::Terrain(const MapFrame& update_mapf, 00090 const MapFrame& cull_mapf, 00091 OSGTileFactory* tileFactory, 00092 bool quickReleaseGLObjects ) : 00093 00094 _tileFactory( tileFactory ), 00095 _registeredWithReleaseGLCallback( false ), 00096 _update_mapf( update_mapf ), 00097 _cull_mapf( cull_mapf ), 00098 _onDemandDelay( 2 ), 00099 _quickReleaseGLObjects( quickReleaseGLObjects ), 00100 _quickReleaseCallbackInstalled( false ), 00101 _alwaysUpdate( false ), 00102 _sampleRatio( 1.0f ), 00103 _verticalScale( 1.0f ) 00104 { 00105 this->setThreadSafeRefUnref( true ); 00106 00107 // the EVENT_VISITOR will reset this to 0 once the "delay" is expired. 00108 _alwaysUpdate = false; 00109 setNumChildrenRequiringUpdateTraversal( 1 ); 00110 00111 // register for events in order to support ON_DEMAND frame scheme 00112 setNumChildrenRequiringEventTraversal( 1 ); 00113 00114 getOrCreateStateSet()->setMode(GL_BLEND , osg::StateAttribute::ON); 00115 } 00116 00117 Terrain::~Terrain() 00118 { 00119 // detach all the tiles from the terrain first. Otherwise osgTerrain::Terrain 00120 // will crap out. 00121 for( TileTable::iterator i = _tiles.begin(); i != _tiles.end(); ++i ) 00122 { 00123 i->second->attachToTerrain( 0L ); 00124 } 00125 _tiles.clear(); 00126 } 00127 00128 void 00129 Terrain::setTechniquePrototype( TerrainTechnique* value ) 00130 { 00131 _techPrototype = value; 00132 } 00133 00134 TerrainTechnique* 00135 Terrain::cloneTechnique() const 00136 { 00137 return osg::clone( _techPrototype.get(), osg::CopyOp::DEEP_COPY_ALL ); 00138 } 00139 00140 Tile* 00141 Terrain::createTile(const TileKey& key, GeoLocator* keyLocator) const 00142 { 00143 return new Tile( key, keyLocator, this->getQuickReleaseGLObjects() ); 00144 } 00145 00146 void 00147 Terrain::setVerticalScale( float value ) 00148 { 00149 if ( value != _verticalScale ) 00150 { 00151 _verticalScale = value; 00152 } 00153 } 00154 00155 void 00156 Terrain::setSampleRatio( float value ) 00157 { 00158 if ( value != _sampleRatio ) 00159 { 00160 _sampleRatio = value; 00161 } 00162 } 00163 00164 void 00165 Terrain::getTiles( TileVector& out ) 00166 { 00167 Threading::ScopedReadLock lock( _tilesMutex ); 00168 out.clear(); 00169 out.reserve( _tiles.size() ); 00170 for( TileTable::const_iterator i = _tiles.begin(); i != _tiles.end(); ++i ) 00171 out.push_back( i->second.get() ); 00172 } 00173 00174 void 00175 Terrain::registerTile( Tile* newTile ) 00176 { 00177 Threading::ScopedWriteLock exclusiveTileTableLock( _tilesMutex ); 00178 _tiles[ newTile->getTileId() ] = newTile; 00179 } 00180 00181 // immediately release GL memory for any expired tiles. 00182 // called from the DRAW thread (QuickReleaseGLCallback). 00183 void 00184 Terrain::releaseGLObjectsForTiles(osg::State* state) 00185 { 00186 OpenThreads::ScopedLock<Mutex> lock( _tilesToReleaseMutex ); 00187 00188 for( TileVector::iterator i = _tilesToRelease.begin(); i != _tilesToRelease.end(); ++i ) 00189 { 00190 i->get()->releaseGLObjects( state ); 00191 } 00192 00193 _tilesToRelease.clear(); 00194 00195 //while( _tilesToRelease.size() > 0 ) 00196 //{ 00197 // _tilesToRelease.front()->releaseGLObjects( state ); 00198 // _tilesToRelease.pop(); 00199 //} 00200 } 00201 00202 void 00203 Terrain::traverse( osg::NodeVisitor &nv ) 00204 { 00205 // UPDATE runs whenever a Tile runs its update traversal on the first pass. 00206 // i.e., only runs then a new Tile is born. 00207 if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR ) 00208 { 00209 // if the terrain engine requested "quick release", install the quick release 00210 // draw callback now. 00211 if ( _quickReleaseGLObjects && !_quickReleaseCallbackInstalled ) 00212 { 00213 osg::Camera* cam = findFirstParentOfType<osg::Camera>( this ); 00214 if ( cam ) 00215 { 00216 cam->setPostDrawCallback( new QuickReleaseGLCallback( this, cam->getPostDrawCallback() ) ); 00217 _quickReleaseCallbackInstalled = true; 00218 OE_INFO << LC << "Quick release enabled" << std::endl; 00219 } 00220 } 00221 00222 // Collect any "dead" tiles and queue them for shutdown. Since UPDATE only runs 00223 // when new tiles arrive, this clears out old tiles from the queue at that time. 00224 // Another approach might be to use an observer_ptr instead...but then we may 00225 // not be able to use the quick-release. 00226 { 00227 Threading::ScopedWriteLock tileTableExclusiveLock( _tilesMutex ); 00228 00229 for( TileTable::iterator i = _tiles.begin(); i != _tiles.end(); ) 00230 { 00231 Tile* tile = i->second.get(); 00232 if ( tile->getNumParents() == 0 && tile->getHasBeenTraversed() ) 00233 { 00234 _tilesToShutDown.push_back( tile ); 00235 00236 // i is incremented prior to calling erase, but i's previous value goes to erase, 00237 // maintaining validity 00238 _tiles.erase( i++ ); 00239 } 00240 else 00241 ++i; 00242 } 00243 } 00244 00245 // Remove any dead tiles from the main tile table, while at the same time queuing 00246 // any tiles that require quick-release. This criticial section requires an exclusive 00247 // lock on the main tile table. 00248 if ( _tilesToShutDown.size() > 0 ) // quick no-lock check.. 00249 { 00250 Threading::ScopedMutexLock tilesToReleaseExclusiveLock( _tilesToReleaseMutex ); 00251 00252 // Shut down any dead tiles once there tasks are complete. 00253 for( TileList::iterator i = _tilesToShutDown.begin(); i != _tilesToShutDown.end(); ) 00254 { 00255 Tile* tile = i->get(); 00256 if ( tile && tile->cancelActiveTasks() ) 00257 { 00258 if ( _quickReleaseGLObjects && _quickReleaseCallbackInstalled ) 00259 { 00260 _tilesToRelease.push_back( tile ); 00261 } 00262 00263 i = _tilesToShutDown.erase( i ); 00264 } 00265 else 00266 ++i; 00267 } 00268 } 00269 00270 // call subclass to continue update.. 00271 updateTraversal( nv ); 00272 } 00273 00274 else if ( nv.getVisitorType() == osg::NodeVisitor::EVENT_VISITOR ) 00275 { 00276 // in OSG's "ON_DEMAND" frame scheme, OSG runs the event visitor as part of the 00277 // test to see if a frame is needed. In sequential/preemptive mode, we need to 00278 // check whether there are any pending tasks running. 00279 00280 // In addition, once the tasks run out, we continue to delay on-demand rendering 00281 // for another full frame so that the event dispatchers can catch up. 00282 00283 if ( _tilesToShutDown.size() > 0 ) 00284 { 00285 setDelay( 2 ); 00286 } 00287 00288 else if ( _onDemandDelay <= 0 ) 00289 { 00290 unsigned numActiveTasks = getNumActiveTasks(); 00291 if ( numActiveTasks > 0 ) 00292 { 00293 setDelay( 2 ); 00294 } 00295 } 00296 00297 //OE_INFO << "Tasks = " << numTasks << std::endl; 00298 00299 if ( _onDemandDelay > 0 ) 00300 { 00301 osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>( &nv ); 00302 ev->getActionAdapter()->requestRedraw(); 00303 decDelay(); 00304 } 00305 } 00306 00307 osg::Group::traverse( nv ); 00308 } 00309 00310 void 00311 Terrain::setDelay( unsigned frames ) 00312 { 00313 if ( _onDemandDelay == 0 && !_alwaysUpdate ) 00314 { 00315 ADJUST_UPDATE_TRAV_COUNT( this, 1 ); 00316 } 00317 _onDemandDelay = frames; 00318 } 00319 00320 void 00321 Terrain::decDelay() 00322 { 00323 _onDemandDelay--; 00324 if ( _onDemandDelay == 0 && !_alwaysUpdate ) 00325 { 00326 ADJUST_UPDATE_TRAV_COUNT(this, -1); 00327 } 00328 }