#include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif using namespace osgDB; DatabasePager::DatabasePager() { //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<getReferenceTime():0.0; int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber; // search to see if filename already exist in the file loaded list. bool foundEntry = false; _dataToCompileListMutex.lock(); 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); } } _dataToCompileListMutex.unlock(); if (!foundEntry) { _dataToMergeListMutex.lock(); 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); } } _dataToMergeListMutex.unlock(); } if (!foundEntry) { _fileRequestListMutex.lock(); // 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; if (_fileRequestList.empty()) _fileRequestListEmptyBlock->release(); _fileRequestList.push_back(databaseRequest); } _fileRequestListMutex.unlock(); } if (!isRunning()) { static OpenThreads::Mutex s_mutex; OpenThreads::ScopedLock lock(s_mutex); static bool s_startThreadCalled = false; if (!s_startThreadCalled) { s_startThreadCalled = true; osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber(); } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<reset(); } void DatabasePager::signalEndFrame() { //osg::notify(osg::INFO) << "signalEndFrame <<<<<<<<<<<<<<<<<<<< "<release(); } class FindCompileableRenderingObjectsVisitor : public osg::NodeVisitor { public: FindCompileableRenderingObjectsVisitor(DatabasePager::DataToCompile& dataToCompile): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _dataToCompile(dataToCompile) { } virtual void apply(osg::Node& node) { apply(node.getStateSet()); traverse(node); } virtual void apply(osg::Geode& geode) { apply(geode.getStateSet()); for(unsigned int i=0;igetTextureAttributeList(); for(osg::StateSet::TextureAttributeList::iterator itr=tal.begin(); itr!=tal.end() && !foundTextureState; ++itr) { osg::StateSet::AttributeList& al = *itr; if (al.count(osg::StateAttribute::TEXTURE)==1) foundTextureState = true; } // if texture object attributes exist add the state to the list for later compilation. if (foundTextureState) { //osg::notify(osg::DEBUG_INFO)<<"Found compilable texture state"<getStateSet()); if (drawable->getUseDisplayList() || drawable->getUseVertexBufferObjects()) { //osg::notify(osg::INFO)<<"Found compilable drawable"<& 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::run() { osg::notify(osg::NOTICE)<<"DatabasePager::run()"<setExpiryDelay(10.0f); do { //std::cout<<"In run loop"<tick(); _fileRequestListEmptyBlock->block(); //osg::Timer_t t2 = osg::Timer::instance()->tick(); _frameBlock->block(); //osg::Timer_t t3 = osg::Timer::instance()->tick(); //std::cout<<"Time in _fileRequestListEmptyBlock block()"<delta_m(t1,t2)<delta_m(t2,t3)< databaseRequest; // get the front of the file request list. _fileRequestListMutex.lock(); if (!_fileRequestList.empty()) { std::sort(_fileRequestList.begin(),_fileRequestList.end(),SortFileRequestFunctor()); databaseRequest = _fileRequestList.front(); } _fileRequestListMutex.unlock(); 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::INFO)<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick(); databaseRequest->_loadedModel = osgDB::readNodeFile(databaseRequest->_fileName); osg::notify(osg::INFO)<<" node read"<delta_m(before,osg::Timer::instance()->tick())<_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 FindCompileableRenderingObjectsVisitor frov(dtc); databaseRequest->_loadedModel->accept(frov); if (!dtc.first.empty() || !dtc.second.empty()) { loadedObjectsNeedToBeCompiled = true; // copy the objects to 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 // dataLoad list. _fileRequestListMutex.lock(); if (databaseRequest->_loadedModel.valid()) { if (loadedObjectsNeedToBeCompiled) { _dataToCompileListMutex.lock(); _dataToCompileList.push_back(databaseRequest); _dataToCompileListMutex.unlock(); } else { _dataToMergeListMutex.lock(); _dataToMergeList.push_back(databaseRequest); _dataToMergeListMutex.unlock(); } } _fileRequestList.erase(_fileRequestList.begin()); if (_fileRequestList.empty()) _fileRequestListEmptyBlock->reset(); _fileRequestListMutex.unlock(); } else { //std::cout<<"frame number delta for "<_fileName<<" "<<_frameNumber-databaseRequest->_frameNumberLastRequest<reset(); _fileRequestListMutex.unlock(); } } // go to sleep till our the next time our thread gets scheduled. //YieldCurrentThread(); //std::cout<<"At end of loop"<.swap. _dataToMergeListMutex.lock(); localFileLoadedList.swap(_dataToMergeList); _dataToMergeListMutex.unlock(); // add the loaded data into the scene graph. for(DatabaseRequestList::iterator itr=localFileLoadedList.begin(); itr!=localFileLoadedList.end(); ++itr) { DatabaseRequest* databaseRequest = itr->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."<getTextureAttributeList(); for(osg::StateSet::TextureAttributeList::iterator itr=tal.begin(); itr!=tal.end() && !foundTextureState; ++itr) { osg::StateSet::AttributeList& al = *itr; osg::StateSet::AttributeList::iterator alitr = al.find(osg::StateAttribute::TEXTURE); if (alitr!=al.end()) { // found texture, so place it in the texture list. osg::Texture* texture = static_cast(alitr->second.first.get()); texture->dirtyTextureObject(); } } } } void DatabasePager::ReleaseTexturesAndDrawablesVisitor::apply(osg::Drawable* drawable) { apply(drawable->getStateSet()); if (drawable->getUseDisplayList() || drawable->getUseVertexBufferObjects()) { drawable->dirtyDisplayList(); } } void DatabasePager::removeExpiredSubgraphs(double currentFrameTime) { double expiryTime = currentFrameTime - _expiryDelay; osg::NodeList childrenRemoved; //osg::notify(osg::INFO)<<"DatabasePager::removeExpiredSubgraphs("<get(); plod->removeExpiredChildren(expiryTime,childrenRemoved); } for(unsigned int i=_pagedLODList.size(); i>0; ) { --i; osg::PagedLOD* plod = _pagedLODList[i].get(); if (plod->referenceCount()==1) { //osg::notify(osg::INFO)<<" PagedLOD "<referenceCount()<accept(rtadv); } } if (_deleteRemovedSubgraphsInDatabaseThread) { // transfer the removed children over to the to delete list so the database thread can delete them. _childrenToDeleteListMutex.lock(); _childrenToDeleteList.insert(_childrenToDeleteList.begin(),childrenRemoved.begin(),childrenRemoved.end()); _childrenToDeleteListMutex.unlock(); } // otherwise the childrenRemoved list will automatically unref() and deleting the nodes. } class FindPagedLODsVisitor : public osg::NodeVisitor { public: FindPagedLODsVisitor(DatabasePager::PagedLODList& pagedLODList): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _pagedLODList(pagedLODList) { } virtual void apply(osg::PagedLOD& plod) { _pagedLODList.push_back(&plod); traverse(plod); } DatabasePager::PagedLODList& _pagedLODList; }; void DatabasePager::registerPagedLODs(osg::Node* subgraph) { FindPagedLODsVisitor fplv(_pagedLODList); if (subgraph) subgraph->accept(fplv); } void DatabasePager::setCompileRenderingObjectsForContexID(unsigned int contextID, bool on) { if (on) { _activeGraphicsContexts.insert(contextID); } else { _activeGraphicsContexts.erase(contextID); } } bool DatabasePager::getCompileRenderingObjectsForContexID(unsigned int contextID) { return _activeGraphicsContexts.count(contextID)!=0; } void DatabasePager::compileRenderingObjects(osg::State& state, double& availableTime) { const osg::Timer& timer = *osg::Timer::instance(); osg::Timer_t start_tick = timer.tick(); double elapsedTime = 0.0; osg::ref_ptr databaseRequest; // get the first compileable entry. _dataToCompileListMutex.lock(); if (!_dataToCompileList.empty()) { std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor()); databaseRequest = _dataToCompileList.front(); } _dataToCompileListMutex.unlock(); // 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() && elapsedTime_dataToCompileMap; DataToCompile& dtc = dcm[state.getContextID()]; if (!dtc.first.empty() && elapsedTimecompile(state); elapsedTime = timer.delta_s(start_tick,timer.tick()); } // remove the compiled stateset from the list. sslist.erase(sslist.begin(),itr); } if (!dtc.second.empty() && elapsedTimecompile(state); elapsedTime = timer.delta_s(start_tick,timer.tick()); } // 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 (allCompiled) { osg::notify(osg::INFO)<<"All compiled"<