#include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif using namespace osgDB; using namespace OpenThreads; static osg::ApplicationUsageProxy DatabasePager_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DO_PRE_COMPILE ","Switch on or off the pre compile of OpenGL object database pager."); static osg::ApplicationUsageProxy DatabasePager_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MINIMUM_COMPILE_TIME_PER_FRAME ","minimum compile time alloted to compiling OpenGL objects per frame in database pager."); static osg::ApplicationUsageProxy DatabasePager_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME ","maximum number of OpenGL objects to compile per frame in database pager."); static osg::ApplicationUsageProxy DatabasePager_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_DRAWABLE ","Set the drawable policy for setting of loaded drawable to specified type. mode can be one of DoNotModify, DisplayList, VBO or VertexArrays>."); static osg::ApplicationUsageProxy DatabasePager_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_PRIORITY ", "Set the thread priority to DEFAULT, MIN, LOW, NOMINAL, HIGH or MAX."); static osg::ApplicationUsageProxy DatabasePager_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_CHILDREN_TO_REMOVE_PER_FRAME ", "Set the maximum number of PagedLOD child to remove per frame."); static osg::ApplicationUsageProxy DatabasePager_e6(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_MINIMUM_INACTIVE_PAGEDLOD ", "Set the minimum number of inactive PagedLOD child to keep."); static osg::ApplicationUsageProxy DatabasePager_e7(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_EXPIRY_DELAY ","Set the length of time a PagedLOD child is kept in memory, without being used, before its tagged as expired, and ear marked to deletion."); // Convert function objects that take pointer args into functions that a // reference to an osg::ref_ptr. This is quite useful for doing STL // operations on lists of ref_ptr. This code assumes that a function // with an argument const Foo* should be composed into a function of // argument type ref_ptr&, not ref_ptr&. Some support // for that should be added to make this more general. namespace { template struct PointerTraits { typedef class NullType {} PointeeType; }; template struct PointerTraits { typedef U PointeeType; }; template struct PointerTraits { typedef U PointeeType; }; template class RefPtrAdapter : public std::unary_function::PointeeType>, typename FuncObj::result_type> { public: typedef typename PointerTraits::PointeeType PointeeType; typedef osg::ref_ptr RefPtrType; explicit RefPtrAdapter(const FuncObj& funcObj) : _func(funcObj) {} typename FuncObj::result_type operator()(const RefPtrType& refPtr) const { return _func(refPtr.get()); } protected: FuncObj _func; }; template RefPtrAdapter refPtrAdapt(const FuncObj& func) { return RefPtrAdapter(func); } } DatabasePager::DatabasePager() { //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<getOrCreateSharedStateManager(); //if (osgDB::Registry::instance()->getSharedStateManager()) //osgDB::Registry::instance()->setUseObjectCacheHint(true); } DatabasePager::DatabasePager(const DatabasePager& rhs) { //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<& DatabasePager::prototype() { static osg::ref_ptr s_DatabasePager = new DatabasePager; return s_DatabasePager; } DatabasePager* DatabasePager::create() { return DatabasePager::prototype().valid() ? DatabasePager::prototype()->clone() : new DatabasePager; } int DatabasePager::cancel() { int result = 0; if( isRunning() ) { _done = true; // cancel the thread.. // result = Thread::cancel(); //join(); // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. _databasePagerThreadBlock->release(); // then wait for the the thread to stop running. while(isRunning()) { // commenting out debug info as it was cashing crash on exit, presumable // due to osg::notify or std::cout destructing earlier than this destructor. // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"< lock(_fileRequestListMutex); _fileRequestList.clear(); } { OpenThreads::ScopedLock lock(_dataToCompileListMutex); _dataToCompileList.clear(); } { OpenThreads::ScopedLock lock(_childrenToDeleteListMutex); _childrenToDeleteList.clear(); } { OpenThreads::ScopedLock lock(_dataToMergeListMutex); _dataToMergeList.clear(); } // no mutex?? _activePagedLODList.clear(); _inactivePagedLODList.clear(); // ?? // _activeGraphicsContexts } void DatabasePager::resetStats() { // initialize the stats variables _minimumTimeToMergeTile = DBL_MAX; _maximumTimeToMergeTile = -DBL_MAX; _totalTimeToMergeTiles = 0.0; _numTilesMerges = 0; } void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const osg::FrameStamp* framestamp) { requestNodeFile(fileName,group,priority,framestamp,Registry::instance()->getOptions()); } void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const osg::FrameStamp* framestamp, ReaderWriter::Options* loadOptions) { if (!_acceptNewRequests) return; double timestamp = framestamp?framestamp->getReferenceTime():0.0; int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber; // search to see if filename already exist in the file loaded list. bool foundEntry = false; { OpenThreads::ScopedLock lock(_dataToCompileListMutex); for(DatabaseRequestList::iterator litr = _dataToCompileList.begin(); litr != _dataToCompileList.end() && !foundEntry; ++litr) { if ((*litr)->_fileName==fileName) { foundEntry = true; (*litr)->_frameNumberLastRequest = frameNumber; (*litr)->_timestampLastRequest = timestamp; (*litr)->_priorityLastRequest = priority; ++((*litr)->_numOfRequests); } } } if (!foundEntry) { OpenThreads::ScopedLock lock(_dataToMergeListMutex); for(DatabaseRequestList::iterator litr = _dataToMergeList.begin(); litr != _dataToMergeList.end() && !foundEntry; ++litr) { if ((*litr)->_fileName==fileName) { foundEntry = true; (*litr)->_frameNumberLastRequest = frameNumber; (*litr)->_timestampLastRequest = timestamp; (*litr)->_priorityLastRequest = priority; ++((*litr)->_numOfRequests); } } } if (!foundEntry) { OpenThreads::ScopedLock lock(_fileRequestListMutex); // search to see if entry already in file request list. bool foundEntry = false; for(DatabaseRequestList::iterator ritr = _fileRequestList.begin(); ritr != _fileRequestList.end() && !foundEntry; ++ritr) { if ((*ritr)->_fileName==fileName) { foundEntry = true; (*ritr)->_timestampLastRequest = timestamp; (*ritr)->_priorityLastRequest = priority; (*ritr)->_frameNumberLastRequest = frameNumber; ++((*ritr)->_numOfRequests); } } if (!foundEntry) { osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("< databaseRequest = new DatabaseRequest; databaseRequest->_fileName = fileName; databaseRequest->_frameNumberFirstRequest = frameNumber; databaseRequest->_timestampFirstRequest = timestamp; databaseRequest->_priorityFirstRequest = priority; databaseRequest->_frameNumberLastRequest = frameNumber; databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; databaseRequest->_groupForAddingLoadedSubgraph = group; databaseRequest->_loadOptions = loadOptions; _fileRequestList.push_back(databaseRequest); updateDatabasePagerThreadBlock(); } } if (!isRunning()) { OpenThreads::ScopedLock lock(_run_mutex); if (!_startThreadCalled) { _startThreadCalled = true; _done = false; osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber(); } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<getTextureAttributeList().size();++i) { osg::Texture* texture = dynamic_cast(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE)); // Has this texture already been encountered? if (texture && !_textureSet.count(texture)) { _textureSet.insert(texture); if (_changeAutoUnRef) texture->setUnRefImageDataAfterApply(_valueAutoUnRef); if ((_changeAnisotropy && texture->getMaxAnisotropy() != _valueAnisotropy)) { if (_changeAnisotropy) texture->setMaxAnisotropy(_valueAnisotropy); } if (!_pager->isCompiled(texture)) { compileStateSet = true; if (osg::getNotifyLevel() >= osg::DEBUG_INFO) { osg::notify(osg::DEBUG_INFO) <<"Found compilable texture " << texture << " "; osg::Image* image = texture->getImage(0); if (image) osg::notify(osg::DEBUG_INFO) << image->getFileName(); osg::notify(osg::DEBUG_INFO) << std:: endl; } break; } } } if (compileStateSet) { _dataToCompile.first.insert(stateset); } } } inline void apply(osg::Drawable* drawable) { if (_drawableSet.count(drawable)) return; apply(drawable->getStateSet()); switch(_drawablePolicy) { case DatabasePager::DO_NOT_MODIFY_DRAWABLE_SETTINGS: // do nothing, leave settings as they came in from loaded database. // osg::notify(osg::NOTICE)<<"DO_NOT_MODIFY_DRAWABLE_SETTINGS"<setUseDisplayList(true); drawable->setUseVertexBufferObjects(false); break; case DatabasePager::USE_VERTEX_BUFFER_OBJECTS: drawable->setUseDisplayList(true); drawable->setUseVertexBufferObjects(true); // osg::notify(osg::NOTICE)<<"USE_VERTEX_BUFFER_OBJECTS"<setUseDisplayList(false); drawable->setUseVertexBufferObjects(false); // osg::notify(osg::NOTICE)<<"USE_VERTEX_ARRAYS"<getUseDisplayList() && _pager->isCompiled(drawable)) { // osg::notify(osg::NOTICE)<<" Found compilable drawable"< > _textureSet; std::set > _drawableSet; }; struct DatabasePager::SortFileRequestFunctor { bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) const { if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; else if (lhs->_timestampLastRequest_timestampLastRequest) return false; else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); } }; void DatabasePager::setDatabasePagerThreadPause(bool pause) { _databasePagerThreadPaused = pause; updateDatabasePagerThreadBlock(); } void DatabasePager::run() { osg::notify(osg::INFO)<<"DatabasePager::run()"<block(); // // delete any children if required. // if (_deleteRemovedSubgraphsInDatabaseThread) { osg::ref_ptr obj = 0; { OpenThreads::ScopedLock lock(_childrenToDeleteListMutex); if (!_childrenToDeleteList.empty()) { //osg::notify(osg::NOTICE)<<"In DatabasePager thread deleting "<<_childrenToDeleteList.size()<<" objects"<tick(); obj = _childrenToDeleteList.back(); _childrenToDeleteList.pop_back(); //osg::notify(osg::NOTICE)<<"Done DatabasePager thread deleted in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<<" objects"< databaseRequest; // get the front of the file request list. { OpenThreads::ScopedLock lock(_fileRequestListMutex); if (!_fileRequestList.empty()) { std::sort(_fileRequestList.begin(),_fileRequestList.end(),SortFileRequestFunctor()); databaseRequest = _fileRequestList.front(); } } if (databaseRequest.valid()) { // check if databaseRequest is still relevant if (_frameNumber-databaseRequest->_frameNumberLastRequest<=1) { // load the data, note safe to write to the databaseRequest since once // it is created this thread is the only one to write to the _loadedModel pointer. //osg::notify(osg::NOTICE)<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick(); bool serialize_readNodeFile = true; if (serialize_readNodeFile) { // do *not* assume that we only have one DatabasePager, or that reaNodeFile is thread safe... static OpenThreads::Mutex s_serialize_readNodeFile_mutex; OpenThreads::ScopedLock lock(s_serialize_readNodeFile_mutex); databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, databaseRequest->_loadOptions.get()); } else { // assume that we only have one DatabasePager, or that readNodeFile is thread safe... databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, databaseRequest->_loadOptions.get()); } //osg::notify(osg::NOTICE)<<" node read in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<_loadedModel.valid() && !_activeGraphicsContexts.empty()) { // force a compute of the loaded model's bounding volume, so that when the subgraph // merged with the main scene graph and large computeBound() isn't incurred. databaseRequest->_loadedModel->getBound(); ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin(); DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr]; ++itr; // find all the compileable rendering objects FindCompileableGLObjectsVisitor frov(dtc, _changeAutoUnRef, _valueAutoUnRef, _changeAnisotropy, _valueAnisotropy, _drawablePolicy, this); databaseRequest->_loadedModel->accept(frov); if (!dtc.first.empty() || !dtc.second.empty()) { loadedObjectsNeedToBeCompiled = true; // copy the objects from the compile list to the other graphics context list. for(; itr != _activeGraphicsContexts.end(); ++itr) { databaseRequest->_dataToCompileMap[*itr] = dtc; } } } // move the databaseRequest from the front of the fileRequest to the end of // dataToCompile or dataToMerge lists. { OpenThreads::ScopedLock lock(_fileRequestListMutex); DatabaseRequestList::iterator itr = std::find(_fileRequestList.begin(),_fileRequestList.end(),databaseRequest); if (itr != _fileRequestList.end()) { if (databaseRequest->_loadedModel.valid()) { if (loadedObjectsNeedToBeCompiled) { OpenThreads::ScopedLock lock(_dataToCompileListMutex); _dataToCompileList.push_back(databaseRequest); } else { OpenThreads::ScopedLock lock(_dataToMergeListMutex); _dataToMergeList.push_back(databaseRequest); } } _fileRequestList.erase(itr); } updateDatabasePagerThreadBlock(); } // Prepare and prune the to-be-compiled list here in // the pager thread rather than in the draw or // graphics context thread(s). if (loadedObjectsNeedToBeCompiled) { OpenThreads::ScopedLock lock(_dataToCompileListMutex); std::sort(_dataToCompileList.begin(), _dataToCompileList.end(), SortFileRequestFunctor()); // Prune all the old entries. DatabaseRequestList::iterator tooOld = std::find_if(_dataToCompileList.begin(), _dataToCompileList.end(), refPtrAdapt(std::not1(std::bind2nd(std::mem_fun(&DatabaseRequest ::isRequestCurrent), _frameNumber)))); // This is the database thread, so just delete _dataToCompileList.erase(tooOld, _dataToCompileList.end()); if (!_dataToCompileList.empty()) { for(ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin(); itr != _activeGraphicsContexts.end(); ++itr) { osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr); if (gc) { osg::GraphicsThread* gt = gc->getGraphicsThread(); if (gt) { gt->add(new DatabasePager::CompileOperation(this)); } else { gc->makeCurrent(); compileAllGLObjects(*(gc->getState())); gc->releaseContext(); } } } // osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<_fileName<<" "<<_frameNumber-databaseRequest->_frameNumberLastRequest< lock(_fileRequestListMutex); if (!_fileRequestList.empty()) _fileRequestList.erase(_fileRequestList.begin()); updateDatabasePagerThreadBlock(); } } // go to sleep till our the next time our thread gets scheduled. if (firstTime) { // do a yield to get round a peculiar thread hang when testCancel() is called // in certain circumstances - of which there is no particular pattern. YieldCurrentThread(); firstTime = false; } } while (!testCancel() && !_done); } bool DatabasePager::requiresUpdateSceneGraph() const { { OpenThreads::ScopedLock lock(_dataToMergeListMutex); if (!_dataToMergeList.empty()) return true; } return false; } void DatabasePager::addLoadedDataToSceneGraph(double timeStamp) { // osg::Timer_t before = osg::Timer::instance()->tick(); DatabaseRequestList localFileLoadedList; // get the dat for the _dataToCompileList, leaving it empty via a std::vector<>.swap. { OpenThreads::ScopedLock lock(_dataToMergeListMutex); localFileLoadedList.swap(_dataToMergeList); } // add the loaded data into the scene graph. for(DatabaseRequestList::iterator itr=localFileLoadedList.begin(); itr!=localFileLoadedList.end(); ++itr) { DatabaseRequest* databaseRequest = itr->get(); // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get()); registerPagedLODs(databaseRequest->_loadedModel.get()); osg::Group* group = databaseRequest->_groupForAddingLoadedSubgraph.get(); osg::PagedLOD* plod = dynamic_cast(group); if (plod) { plod->setTimeStamp(plod->getNumChildren(),timeStamp); } group->addChild(databaseRequest->_loadedModel.get()); osg::notify(osg::INFO)<<"merged subgraph"<_fileName<<" after "<_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<_timestampFirstRequest; if (timeToMerge<_minimumTimeToMergeTile) _minimumTimeToMergeTile = timeToMerge; if (timeToMerge>_maximumTimeToMergeTile) _maximumTimeToMergeTile = timeToMerge; _totalTimeToMergeTiles += timeToMerge; ++_numTilesMerges; // osg::notify(osg::NOTICE)<<"curr = "<delta_m(before,osg::Timer::instance()->tick())<<" ms objects"<tick(); double expiryTime = currentFrameTime - _expiryDelay; osg::NodeList childrenRemoved; for(PagedLODList::iterator active_itr = _activePagedLODList.begin(); active_itr!=_activePagedLODList.end(); ) { const osg::PagedLOD* plod = active_itr->get(); bool remove_plod = false; if (plod->referenceCount()<=1) { // prune PageLOD's that are no longer externally referenced childrenRemoved.push_back(const_cast(plod)); //osg::notify(osg::NOTICE)<<"_activePagedLODList : pruning no longer externally referenced"<getFrameNumberOfLastTraversal()<_frameNumber) { // osg::notify(osg::NOTICE)<<"_activePagedLODList : moving PageLOD to inactive list"< _minimumNumOfInactivePagedLODs) targetNumOfRemovedChildPagedLODs = _inactivePagedLODList.size() - _minimumNumOfInactivePagedLODs; if (targetNumOfRemovedChildPagedLODs > _maximumNumOfRemovedChildPagedLODs) targetNumOfRemovedChildPagedLODs = _maximumNumOfRemovedChildPagedLODs; // filter out singly referenced PagedLOD and move reactivated PagedLOD into the active list for(PagedLODList::iterator inactive_itr = _inactivePagedLODList.begin(); inactive_itr!=_inactivePagedLODList.end(); ) { const osg::PagedLOD* plod = inactive_itr->get(); bool remove_plod = false; if (plod->referenceCount()<=1) { // prune PageLOD's that are no longer externally referenced childrenRemoved.push_back(const_cast(plod)); //osg::notify(osg::NOTICE)<<"_activePagedLODList : pruning no longer externally referenced"<getFrameNumberOfLastTraversal()>=_frameNumber) { // osg::notify(osg::NOTICE)<<"_inactivePagedLODList : moving PageLOD to active list"<(plod)->removeExpiredChildren(expiryTime,childrenRemoved)) { //osg::notify(osg::NOTICE)<<"Some children removed from PLod"<delta_m(before,osg::Timer::instance()->tick()); //osg::notify(osg::NOTICE)<<" time 1 "<delta_m(before,osg::Timer::instance()->tick())<<" ms "<getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->prune(); // update the Registry object cache. osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(currentFrameTime); osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime); // osg::notify(osg::NOTICE)<<"Done DatabasePager::removeExpiredSubgraphs() "<delta_m(before,osg::Timer::instance()->tick())<<" ms "<accept(fplv); } bool DatabasePager::requiresCompileGLObjects() const { OpenThreads::ScopedLock lock(_dataToCompileListMutex); return !_dataToCompileList.empty(); } void DatabasePager::setCompileGLObjectsForContextID(unsigned int contextID, bool on) { if (on) { _activeGraphicsContexts.insert(contextID); } else { _activeGraphicsContexts.erase(contextID); } } bool DatabasePager::getCompileGLObjectsForContextID(unsigned int contextID) { return _activeGraphicsContexts.count(contextID)!=0; } DatabasePager::CompileOperation::CompileOperation(osgDB::DatabasePager* databasePager): osg::GraphicsOperation("DatabasePager::CompileOperation",false), _databasePager(databasePager) { } void DatabasePager::CompileOperation::operator () (osg::GraphicsContext* context) { // osg::notify(osg::NOTICE)<<"Background thread compiling"<compileAllGLObjects(*(context->getState())); } bool DatabasePager::requiresExternalCompileGLObjects(unsigned int contextID) const { if (_activeGraphicsContexts.count(contextID)==0) return false; return osg::GraphicsContext::getCompileContext(contextID)==0; } void DatabasePager::compileAllGLObjects(osg::State& state) { double availableTime = DBL_MAX; compileGLObjects(state, availableTime); } void DatabasePager::compileGLObjects(osg::State& state, double& availableTime) { // osg::notify(osg::NOTICE)<<"DatabasePager::compileGLObjects "<<_frameNumber<getSharedStateManager(); osg::RenderInfo renderInfo; renderInfo.setState(&state); if (availableTime>0.0) { const osg::Timer& timer = *osg::Timer::instance(); osg::Timer_t start_tick = timer.tick(); double elapsedTime = 0.0; double estimatedTextureDuration = 0.0001; double estimatedDrawableDuration = 0.0001; osg::ref_ptr databaseRequest; // get the first compilable entry. { OpenThreads::ScopedLock lock(_dataToCompileListMutex); // advance to the next entry to compile if one is available. databaseRequest = _dataToCompileList.empty() ? 0 : _dataToCompileList.front(); }; unsigned int numObjectsCompiled = 0; // while there are valid databaseRequest's in the to compile list and there is // sufficient time left compile each databaseRequest's stateset and drawables. while (databaseRequest.valid() && (compileAll || (elapsedTime_dataToCompileMap; DataToCompile& dtc = dcm[state.getContextID()]; if (!dtc.first.empty() && (elapsedTime+estimatedTextureDuration)get(), state.getContextID()) || (sharedManager && sharedManager->isShared(itr->get()))) { elapsedTime = timer.delta_s(start_tick,timer.tick()); continue; } double startCompileTime = timer.delta_s(start_tick,timer.tick()); (*itr)->compileGLObjects(state); GLint p; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p); elapsedTime = timer.delta_s(start_tick,timer.tick()); // estimate the duration of the compile based on current compile duration. estimatedTextureDuration = (elapsedTime-startCompileTime); ++numObjectsCompiled; } if (osg::getNotifyLevel() >= osg::DEBUG_INFO && numObjectsCompiled > objTemp) osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled " << numObjectsCompiled - objTemp << " StateSets" << std::endl; // remove the compiled statesets from the list. sslist.erase(sslist.begin(),itr); } if (!dtc.second.empty() && (compileAll || ((elapsedTime+estimatedDrawableDuration)get(), state.getContextID())) { elapsedTime = timer.delta_s(start_tick,timer.tick()); continue; } double startCompileTime = timer.delta_s(start_tick,timer.tick()); (*itr)->compileGLObjects(renderInfo); elapsedTime = timer.delta_s(start_tick,timer.tick()); // estimate the duration of the compile based on current compile duration. estimatedDrawableDuration = (elapsedTime-startCompileTime); ++numObjectsCompiled; } if (osg::getNotifyLevel() >= osg::DEBUG_INFO && numObjectsCompiled > objTemp) osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled " << numObjectsCompiled - objTemp << " Drawables" << std::endl; // remove the compiled drawables from the list. dwlist.erase(dwlist.begin(),itr); } //osg::notify(osg::INFO)<<"Checking if compiled"<second.first.empty())) allCompiled=false; if (!(itr->second.second.empty())) allCompiled=false; } //if (numObjectsCompiled > 0) //osg::notify(osg::NOTICE)<< _frameNumber << "compiled " << numObjectsCompiled << " objects" << std::endl; if (allCompiled) { // we've compiled all of the current databaseRequest so we can now pop it off the // to compile list and place it on the merge list. // osg::notify(osg::NOTICE)<<"All compiled"< lock(_dataToCompileListMutex); // The request might have been removed from the // _dataToCompile list by another graphics thread, in // which case it's already on the merge list, or by // the pager, which means that the request has // expired. Also, the compile list might have been // shuffled by the pager, so the current request is // not guaranteed to still be at the beginning of the // list. DatabaseRequestList::iterator requestIter = std::find(_dataToCompileList.begin(), _dataToCompileList.end(), databaseRequest); if (requestIter != _dataToCompileList.end()) { { OpenThreads::ScopedLock lock(_dataToMergeListMutex); _dataToMergeList.push_back(databaseRequest); } _dataToCompileList.erase(requestIter); } if (!_dataToCompileList.empty()) databaseRequest = _dataToCompileList.front(); else databaseRequest = 0; } else { // osg::notify(osg::NOTICE)<<"Not all compiled"<