root/OpenSceneGraph/trunk/src/osgDB/DatabasePager.cpp @ 7074

Revision 7074, 41.0 kB (checked in by robert, 7 years ago)

Added include/osg/GLObjects + .cpp which provide osg::flush*DeletedGLObjects() methods.

Added and cleaned up DeleteHandler? calls in osgViewer to help avoid crashes on exit.

Changed DatabasePager? across to dynamically checcking osg::getCompileContext(..)

Updated wrappers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgDB/DatabasePager>
2#include <osgDB/ReadFile>
3
4#include <osg/Geode>
5#include <osg/Timer>
6#include <osg/Texture>
7#include <osg/Notify>
8#include <osg/ApplicationUsage>
9
10#include <OpenThreads/ScopedLock>
11
12#include <algorithm>
13
14#ifdef WIN32
15#include <windows.h>
16#else
17#include <unistd.h>
18#endif
19
20using namespace osgDB;
21using namespace OpenThreads;
22
23static osg::ApplicationUsageProxy DatabasePager_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DO_PRE_COMPILE <ON/OFF>","Switch on or off the pre compile of OpenGL object database pager.");
24static osg::ApplicationUsageProxy DatabasePager_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MINIMUM_COMPILE_TIME_PER_FRAME <float>","minimum compile time alloted to compiling OpenGL objects per frame in database pager.");
25static osg::ApplicationUsageProxy DatabasePager_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME <int>","maximum number of OpenGL objects to compile per frame in database pager.");
26static osg::ApplicationUsageProxy DatabasePager_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_DRAWABLE <mode>","Set the drawable policy for setting of loaded drawable to specified type.  mode can be one of DoNotModify, DisplayList, VBO or VertexArrays>.");
27DatabasePager::DatabasePager()
28{
29    //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<<std::endl;
30   
31    _startThreadCalled = false;
32
33    _done = false;
34    _acceptNewRequests = true;
35    _databasePagerThreadPaused = false;
36   
37    _useFrameBlock = false;
38    _numFramesActive = 0;
39    _frameNumber = 0;
40    _frameBlock = new osg::RefBlock;
41    _databasePagerThreadBlock = new osg::RefBlock;
42
43    _threadPriorityDuringFrame = THREAD_PRIORITY_MIN;
44    _threadPriorityOutwithFrame = THREAD_PRIORITY_MIN;
45
46#if __APPLE__
47    // OSX really doesn't like compiling display lists, and performs poorly when they are used,
48    // so apply this hack to make up for its short comings.
49    _drawablePolicy = USE_VERTEX_ARRAYS;
50#else
51    _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS;
52#endif   
53   
54    const char* str = getenv("OSG_DATABASE_PAGER_GEOMETRY");
55    if (!str) str = getenv("OSG_DATABASE_PAGER_DRAWABLE");
56    if (str)
57    {
58        if (strcmp(str,"DoNotModify")==0)
59        {
60            _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS;
61        }
62        else if (strcmp(str,"DisplayList")==0 || strcmp(str,"DL")==0)
63        {
64            _drawablePolicy = USE_DISPLAY_LISTS;
65        }
66        else if (strcmp(str,"VBO")==0)
67        {
68            _drawablePolicy = USE_VERTEX_BUFFER_OBJECTS;
69        }
70        else if (strcmp(str,"VertexArrays")==0 || strcmp(str,"VA")==0 )
71        {
72            _drawablePolicy = USE_VERTEX_ARRAYS;
73        }
74    }
75
76    _changeAutoUnRef = true;
77    _valueAutoUnRef = true;
78    _changeAnisotropy = false;
79    _valueAnisotropy = 1.0f;
80
81
82#if 1
83    _deleteRemovedSubgraphsInDatabaseThread = true;
84#else
85    _deleteRemovedSubgraphsInDatabaseThread = false;
86#endif
87   
88    _expiryDelay = 10;
89
90    const char* ptr=0;
91    _doPreCompile = true;
92    if( (ptr = getenv("OSG_DO_PRE_COMPILE")) != 0)
93    {
94        _doPreCompile = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
95                        strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
96    }
97
98    _targetFrameRate = 100.0;
99    _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms.
100    _maximumNumOfObjectsToCompilePerFrame = 4;
101    if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0)
102    {
103        _minimumTimeAvailableForGLCompileAndDeletePerFrame = atof(ptr);
104    }
105
106    if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0)
107    {
108        _maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
109    }
110
111    // make sure a SharedStateManager exists.
112    //osgDB::Registry::instance()->getOrCreateSharedStateManager();
113   
114    //if (osgDB::Registry::instance()->getSharedStateManager())
115        //osgDB::Registry::instance()->setUseObjectCacheHint(true);
116}
117
118DatabasePager::~DatabasePager()
119{
120    cancel();
121}
122
123int DatabasePager::cancel()
124{
125    int result = 0;
126    if( isRunning() )
127    {
128   
129        _done = true;
130
131        // cancel the thread..
132        // result = Thread::cancel();
133        //join();
134
135        // release the frameBlock and _databasePagerThreadBlock incase its holding up thread cancelation.
136        _frameBlock->release();
137        _databasePagerThreadBlock->release();
138
139        // then wait for the the thread to stop running.
140        while(isRunning())
141        {
142            // commenting out debug info as it was cashing crash on exit, presumable
143            // due to osg::notify or std::cout destructing earlier than this destructor.
144            // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<<std::endl;
145            OpenThreads::Thread::YieldCurrentThread();
146        }
147       
148        _startThreadCalled = false;
149    }
150    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
151    return result;
152}
153
154void DatabasePager::clear()
155{
156    {
157        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex);
158        _fileRequestList.clear();
159    }
160
161    {
162        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
163        _dataToCompileList.clear();
164    }
165
166    {
167        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex);
168        _childrenToDeleteList.clear();
169    }
170   
171    {
172        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
173        _dataToMergeList.clear();
174    }
175
176    // no mutex??
177    _activePagedLODList.clear();
178    _inactivePagedLODList.clear();
179   
180    // ??
181    // _activeGraphicsContexts
182}
183
184void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group,
185                                    float priority, const osg::FrameStamp* framestamp)
186{
187    requestNodeFile(fileName,group,priority,framestamp,Registry::instance()->getOptions());
188}
189
190void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group,
191                                    float priority, const osg::FrameStamp* framestamp,
192                                    ReaderWriter::Options* loadOptions)
193{
194    if (!_acceptNewRequests) return;
195   
196    double timestamp = framestamp?framestamp->getReferenceTime():0.0;
197    int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber;
198   
199    // search to see if filename already exist in the file loaded list.
200    bool foundEntry = false;
201
202    {
203        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
204   
205        for(DatabaseRequestList::iterator litr = _dataToCompileList.begin();
206            litr != _dataToCompileList.end() && !foundEntry;
207            ++litr)
208        {
209            if ((*litr)->_fileName==fileName)
210            {
211                foundEntry = true;
212                (*litr)->_frameNumberLastRequest = frameNumber;
213                (*litr)->_timestampLastRequest = timestamp;
214                (*litr)->_priorityLastRequest = priority;
215                ++((*litr)->_numOfRequests);
216            }
217        }       
218
219    }
220
221    if (!foundEntry)
222    {
223        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
224
225        for(DatabaseRequestList::iterator litr = _dataToMergeList.begin();
226            litr != _dataToMergeList.end() && !foundEntry;
227            ++litr)
228        {
229            if ((*litr)->_fileName==fileName)
230            {
231                foundEntry = true;
232                (*litr)->_frameNumberLastRequest = frameNumber;
233                (*litr)->_timestampLastRequest = timestamp;
234                (*litr)->_priorityLastRequest = priority;
235                ++((*litr)->_numOfRequests);
236            }
237        }       
238    }
239   
240    if (!foundEntry)
241    {
242   
243        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex);
244
245        // search to see if entry already  in file request list.
246        bool foundEntry = false;
247        for(DatabaseRequestList::iterator ritr = _fileRequestList.begin();
248            ritr != _fileRequestList.end() && !foundEntry;
249            ++ritr)
250        {
251            if ((*ritr)->_fileName==fileName)
252            {
253                foundEntry = true;
254                (*ritr)->_timestampLastRequest = timestamp;
255                (*ritr)->_priorityLastRequest = priority;
256                (*ritr)->_frameNumberLastRequest = frameNumber;
257                ++((*ritr)->_numOfRequests);
258            }
259        }       
260
261        if (!foundEntry)
262        {
263            osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("<<fileName<<")"<<std::endl;
264
265            osg::ref_ptr<DatabaseRequest> databaseRequest = new DatabaseRequest;
266
267            databaseRequest->_fileName = fileName;
268            databaseRequest->_frameNumberFirstRequest = frameNumber;
269            databaseRequest->_timestampFirstRequest = timestamp;
270            databaseRequest->_priorityFirstRequest = priority;
271            databaseRequest->_frameNumberLastRequest = frameNumber;
272            databaseRequest->_timestampLastRequest = timestamp;
273            databaseRequest->_priorityLastRequest = priority;
274            databaseRequest->_groupForAddingLoadedSubgraph = group;
275            databaseRequest->_loadOptions = loadOptions;
276
277            _fileRequestList.push_back(databaseRequest);
278
279            updateDatabasePagerThreadBlock();
280        }
281    }
282   
283    if (!isRunning())
284    {
285        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
286       
287        if (!_startThreadCalled)
288        {
289            _startThreadCalled = true;
290            _done = false;
291            osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl;
292            setSchedulePriority(_threadPriorityDuringFrame);
293            startThread();
294        }
295    }
296}
297
298void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp)
299{
300
301    if (framestamp)
302    {
303        //osg::notify(osg::INFO) << "signalBeginFrame "<<framestamp->getFrameNumber()<<">>>>>>>>>>>>>>>>"<<std::endl;
304        _frameNumber = framestamp->getFrameNumber();
305       
306    } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<<std::endl;
307
308    updateFrameBlock(1);
309
310    if (_numFramesActive>0 && _threadPriorityDuringFrame!=getSchedulePriority())
311        setSchedulePriority(_threadPriorityDuringFrame);
312}
313
314void DatabasePager::signalEndFrame()
315{
316    //osg::notify(osg::INFO) << "signalEndFrame <<<<<<<<<<<<<<<<<<<< "<<std::endl;
317    updateFrameBlock(-1);
318
319    if (_numFramesActive<=0 && _threadPriorityOutwithFrame!=getSchedulePriority())
320        setSchedulePriority(_threadPriorityOutwithFrame);
321
322}
323
324class DatabasePager::FindCompileableGLObjectsVisitor : public osg::NodeVisitor
325{
326public:
327    FindCompileableGLObjectsVisitor(DatabasePager::DataToCompile& dataToCompile,
328                               bool changeAutoUnRef, bool valueAutoUnRef,
329                               bool changeAnisotropy, float valueAnisotropy,
330                               DatabasePager::DrawablePolicy drawablePolicy):
331            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
332            _dataToCompile(dataToCompile),
333            _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
334            _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy),
335            _drawablePolicy(drawablePolicy)
336    {
337    }
338   
339    virtual void apply(osg::Node& node)
340    {
341        apply(node.getStateSet());
342
343        traverse(node);
344    }
345   
346    virtual void apply(osg::Geode& geode)
347    {
348        apply(geode.getStateSet());
349   
350        for(unsigned int i=0;i<geode.getNumDrawables();++i)
351        {
352            apply(geode.getDrawable(i));
353        }
354
355        traverse(geode);
356    }
357   
358    inline void apply(osg::StateSet* stateset)
359    {
360        if (stateset)
361        {
362            // search for the existance of any texture object attributes
363            bool foundTextureState = false;
364            for(unsigned int i=0;i<stateset->getTextureAttributeList().size();++i)
365            {
366                osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
367                if (texture)
368                {
369                    if (_changeAutoUnRef) texture->setUnRefImageDataAfterApply(_valueAutoUnRef);
370                    if (_changeAnisotropy) texture->setMaxAnisotropy(_valueAnisotropy);
371                    foundTextureState = true;
372                }
373            }
374
375            // if texture object attributes exist add the state to the list for later compilation.
376            if (foundTextureState)
377            {
378                //osg::notify(osg::DEBUG_INFO)<<"Found compilable texture state"<<std::endl;
379                _dataToCompile.first.insert(stateset);
380            }
381        }
382    }
383   
384    inline void apply(osg::Drawable* drawable)
385    {
386        apply(drawable->getStateSet());
387       
388        switch(_drawablePolicy)
389        {
390        case DatabasePager::DO_NOT_MODIFY_DRAWABLE_SETTINGS:
391             // do nothing, leave settings as they came in from loaded database.
392             // osg::notify(osg::NOTICE)<<"DO_NOT_MODIFY_DRAWABLE_SETTINGS"<<std::endl;
393             break;
394        case DatabasePager::USE_DISPLAY_LISTS:
395             drawable->setUseDisplayList(true);
396             drawable->setUseVertexBufferObjects(false);
397             break;
398        case DatabasePager::USE_VERTEX_BUFFER_OBJECTS:
399             drawable->setUseDisplayList(true);
400             drawable->setUseVertexBufferObjects(true);
401             // osg::notify(osg::NOTICE)<<"USE_VERTEX_BUFFER_OBJECTS"<<std::endl;
402             break;
403        case DatabasePager::USE_VERTEX_ARRAYS:
404             drawable->setUseDisplayList(false);
405             drawable->setUseVertexBufferObjects(false);
406             // osg::notify(osg::NOTICE)<<"USE_VERTEX_ARRAYS"<<std::endl;
407             break;
408        }
409       
410        if (drawable->getUseDisplayList() || drawable->getUseVertexBufferObjects())
411        {
412            // osg::notify(osg::NOTICE)<<"  Found compilable drawable"<<std::endl;
413            _dataToCompile.second.push_back(drawable);
414        }
415    }
416   
417    DatabasePager::DataToCompile&   _dataToCompile;
418    bool                            _changeAutoUnRef;
419    bool                            _valueAutoUnRef;
420    bool                            _changeAnisotropy;
421    float                           _valueAnisotropy;
422    DatabasePager::DrawablePolicy   _drawablePolicy;
423};
424
425
426struct DatabasePager::SortFileRequestFunctor
427{
428    bool operator() (const osg::ref_ptr<DatabasePager::DatabaseRequest>& lhs,const osg::ref_ptr<DatabasePager::DatabaseRequest>& rhs) const
429    {
430        if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true;
431        else if (lhs->_timestampLastRequest<rhs->_timestampLastRequest) return false;
432        else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest);
433    }
434};
435
436
437void DatabasePager::setDatabasePagerThreadPause(bool pause)
438{
439    _databasePagerThreadPaused = pause;
440    updateDatabasePagerThreadBlock();
441}
442
443void DatabasePager::run()
444{
445    osg::notify(osg::INFO)<<"DatabasePager::run()"<<std::endl;
446
447    // need to set the texture object manager to be able to reuse textures
448    osg::Texture::setMinimumNumberOfTextureObjectsToRetainInCache(100);
449   
450    // need to set the texture object manager to be able to reuse textures
451    osg::Drawable::setMinimumNumberOfDisplayListsToRetainInCache(500);
452
453    bool firstTime = true;
454   
455    do
456    {
457
458        _databasePagerThreadBlock->block();
459
460        if (_useFrameBlock)
461        {
462            _frameBlock->block();
463        }     
464
465        //
466        // delete any children if required.
467        //
468        if (_deleteRemovedSubgraphsInDatabaseThread)
469        {
470            osg::ref_ptr<osg::Object> obj = 0;
471            {
472                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex);
473                if (!_childrenToDeleteList.empty())
474                {
475                    //osg::notify(osg::NOTICE)<<"In DatabasePager thread deleting "<<_childrenToDeleteList.size()<<" objects"<<std::endl;
476                    //osg::Timer_t before = osg::Timer::instance()->tick();
477                    obj = _childrenToDeleteList.back();
478                    _childrenToDeleteList.pop_back();
479                    //osg::notify(osg::NOTICE)<<"Done DatabasePager thread deleted in "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms"<<" objects"<<std::endl;
480
481                    updateDatabasePagerThreadBlock();
482
483                }
484            }
485        }
486
487        //
488        // load any subgraphs that are required.
489        //
490        osg::ref_ptr<DatabaseRequest> databaseRequest;
491   
492        // get the front of the file request list.
493        {
494            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex);
495            if (!_fileRequestList.empty())
496            {
497                std::sort(_fileRequestList.begin(),_fileRequestList.end(),SortFileRequestFunctor());
498                databaseRequest = _fileRequestList.front();
499            }
500        }
501               
502        if (databaseRequest.valid())
503        {
504            // check if databaseRequest is still relevant
505            if (_frameNumber-databaseRequest->_frameNumberLastRequest<=1)
506            {
507                       
508                // load the data, note safe to write to the databaseRequest since once
509                // it is created this thread is the only one to write to the _loadedModel pointer.
510                //osg::notify(osg::NOTICE)<<"In DatabasePager thread readNodeFile("<<databaseRequest->_fileName<<")"<<std::endl;
511                //osg::Timer_t before = osg::Timer::instance()->tick();
512               
513               
514                bool serialize_readNodeFile = true;
515                if (serialize_readNodeFile)
516                {
517                    // do *not* assume that we only have one DatabasePager, or that reaNodeFile is thread safe...
518                    static OpenThreads::Mutex s_serialize_readNodeFile_mutex;
519                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_serialize_readNodeFile_mutex);
520                    databaseRequest->_loadedModel = osgDB::readNodeFile(databaseRequest->_fileName,
521                        databaseRequest->_loadOptions.get());
522                }
523                else
524                {
525                    // assume that we only have one DatabasePager, or that readNodeFile is thread safe...
526                    databaseRequest->_loadedModel = osgDB::readNodeFile(databaseRequest->_fileName,
527                        databaseRequest->_loadOptions.get());
528                }
529                   
530                //osg::notify(osg::NOTICE)<<"     node read in "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms"<<std::endl;
531               
532                bool loadedObjectsNeedToBeCompiled = false;
533
534                if (_doPreCompile && databaseRequest->_loadedModel.valid() && !_activeGraphicsContexts.empty())
535                {
536                    // force a compute of the loaded model's bounding volume, so that when the subgraph
537                    // merged with the main scene graph and large computeBound() isn't incurred.
538                    databaseRequest->_loadedModel->getBound();
539
540
541                    ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin();
542
543                    DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr];
544                    ++itr;               
545
546                    // find all the compileable rendering objects
547                    FindCompileableGLObjectsVisitor frov(dtc,
548                                                         _changeAutoUnRef, _valueAutoUnRef,
549                                                         _changeAnisotropy, _valueAnisotropy,
550                                                         _drawablePolicy);
551
552                    databaseRequest->_loadedModel->accept(frov);
553
554                    if (!dtc.first.empty() || !dtc.second.empty())
555                    {
556                        loadedObjectsNeedToBeCompiled = true;               
557
558                        // copy the objects from the compile list to the other graphics context list.
559                        for(;
560                            itr != _activeGraphicsContexts.end();
561                            ++itr)
562                        {
563                            databaseRequest->_dataToCompileMap[*itr] = dtc;
564                        }
565                    }
566                }           
567
568                // move the databaseRequest from the front of the fileRequest to the end of
569                // dataToCompile or dataToMerge lists.
570                {
571                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex);
572
573                    DatabaseRequestList::iterator itr = std::find(_fileRequestList.begin(),_fileRequestList.end(),databaseRequest);
574                    if (itr != _fileRequestList.end())
575                    {
576                        if (databaseRequest->_loadedModel.valid())
577                        {
578                            if (loadedObjectsNeedToBeCompiled)
579                            {
580                                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
581                                _dataToCompileList.push_back(databaseRequest);
582                            }
583                            else
584                            {
585                                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
586                                _dataToMergeList.push_back(databaseRequest);
587                            }
588                        }       
589
590                        _fileRequestList.erase(itr);
591                    }
592
593                    updateDatabasePagerThreadBlock();
594                }
595               
596                if (loadedObjectsNeedToBeCompiled)
597                {
598                    for(ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin();
599                        itr != _activeGraphicsContexts.end();
600                        ++itr)
601                    {
602                        osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr);
603                        if (gc)
604                        {   
605                            osg::OperationsThread* gt = gc->getGraphicsThread();
606                            if (gt)
607                            {
608                                gt->add(new DatabasePager::CompileOperation(this));
609                            }
610                            else
611                            {
612                                gc->makeCurrent();
613                               
614                                compileAllGLObjects(*(gc->getState()));
615                               
616                                gc->releaseContext();
617                            }
618                        }
619                    }
620
621                    // osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<<std::endl;                   
622                }
623               
624            }
625            else
626            {
627                //std::cout<<"frame number delta for "<<databaseRequest->_fileName<<" "<<_frameNumber-databaseRequest->_frameNumberLastRequest<<std::endl;
628                // remove the databaseRequest from the front of the fileRequest to the end of
629                // dataLoad list as its is no longer relevant
630                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex);
631
632                if (!_fileRequestList.empty()) _fileRequestList.erase(_fileRequestList.begin());
633
634                updateDatabasePagerThreadBlock();
635
636            }
637        }
638       
639        // go to sleep till our the next time our thread gets scheduled.
640
641        if (firstTime)
642        {
643            // do a yield to get round a peculiar thread hang when testCancel() is called
644            // in certain cirumstances - of which there is no particular pattern.
645            YieldCurrentThread();
646            firstTime = false;
647        }
648
649    } while (!testCancel() && !_done);
650
651}
652
653
654bool DatabasePager::requiresUpdateSceneGraph() const
655{
656    {
657        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
658        if (!_dataToMergeList.empty()) return true;
659    }
660   
661    return false;
662   
663}
664 
665
666void DatabasePager::addLoadedDataToSceneGraph(double timeStamp)
667{
668
669    // osg::Timer_t before = osg::Timer::instance()->tick();
670
671    DatabaseRequestList localFileLoadedList;
672
673    // get the dat for the _dataToCompileList, leaving it empty via a std::vector<>.swap.
674    {
675        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
676        localFileLoadedList.swap(_dataToMergeList);
677    }
678       
679    // add the loaded data into the scene graph.
680    for(DatabaseRequestList::iterator itr=localFileLoadedList.begin();
681        itr!=localFileLoadedList.end();
682        ++itr)
683    {
684        DatabaseRequest* databaseRequest = itr->get();
685
686        // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<<std::endl;
687       
688        if (osgDB::Registry::instance()->getSharedStateManager())
689            osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get());
690
691       
692        registerPagedLODs(databaseRequest->_loadedModel.get());
693       
694        osg::Group* group = databaseRequest->_groupForAddingLoadedSubgraph.get();
695        osg::PagedLOD* plod = dynamic_cast<osg::PagedLOD*>(group);
696        if (plod)
697        {
698            plod->setTimeStamp(plod->getNumChildren(),timeStamp);
699        }
700        group->addChild(databaseRequest->_loadedModel.get());
701        osg::notify(osg::INFO)<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests."<<std::endl;
702
703    }
704
705    // osg::notify(osg::NOTICE)<<"Done DatabasePager::addLoadedDataToSceneGraph"<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms  objects"<<localFileLoadedList.size()<<std::endl;
706   
707}
708
709
710void DatabasePager::removeExpiredSubgraphs(double currentFrameTime)
711{
712    //osg::notify(osg::NOTICE)<<"DatabasePager::removeExpiredSubgraphs()"<<std::endl;
713
714    // osg::Timer_t before = osg::Timer::instance()->tick();
715
716    double expiryTime = currentFrameTime - _expiryDelay;
717
718    osg::NodeList childrenRemoved;
719   
720
721    for(PagedLODList::iterator active_itr = _activePagedLODList.begin();
722        active_itr!=_activePagedLODList.end();
723        )
724    {
725        const osg::PagedLOD* plod = active_itr->get();
726        bool remove_plod = false;
727        if (plod->referenceCount()<=1)
728        {
729            // prune PageLOD's that are no longer externally referenced
730            childrenRemoved.push_back(const_cast<osg::PagedLOD*>(plod));
731            //osg::notify(osg::NOTICE)<<"_activePagedLODList : pruning no longer externally referenced"<<std::endl;
732            remove_plod = true;
733        }
734        else if (plod->getFrameNumberOfLastTraversal()<_frameNumber)
735        {               
736            // osg::notify(osg::NOTICE)<<"_activePagedLODList : moving PageLOD to inactive list"<<std::endl;
737            _inactivePagedLODList.push_back(*active_itr);
738            remove_plod = true;
739        }
740       
741        if (remove_plod)
742        {
743            PagedLODList::iterator itr_to_erase = active_itr;
744            ++active_itr;
745           
746            _activePagedLODList.erase(itr_to_erase);           
747        }
748        else
749        {
750            ++active_itr;
751        }
752    }
753   
754    unsigned int i = 0;
755    // unsigned int numberOfPagedLODToTest = _inactivePagedLODList.size();
756    unsigned int targetNumOfInActivePagedLODs = 100;
757    unsigned int targetNumOfRemovedChildPagedLODs = 0;
758    if (_inactivePagedLODList.size()>targetNumOfInActivePagedLODs) targetNumOfRemovedChildPagedLODs = _inactivePagedLODList.size()-targetNumOfInActivePagedLODs;
759   
760    if (targetNumOfRemovedChildPagedLODs>1) targetNumOfRemovedChildPagedLODs=1;
761   
762
763    // filter out singly referenced PagedLOD and move reactivated PagedLOD into the active list
764    for(PagedLODList::iterator inactive_itr = _inactivePagedLODList.begin();
765        inactive_itr!=_inactivePagedLODList.end();
766        )
767    {
768        const osg::PagedLOD* plod = inactive_itr->get();
769        bool remove_plod = false;
770        if (plod->referenceCount()<=1)
771        {
772            // prune PageLOD's that are no longer externally referenced
773            childrenRemoved.push_back(const_cast<osg::PagedLOD*>(plod));
774            //osg::notify(osg::NOTICE)<<"_activePagedLODList : pruning no longer externally referenced"<<std::endl;
775            remove_plod = true;
776        }
777        else if (plod->getFrameNumberOfLastTraversal()>=_frameNumber)
778        {
779            // osg::notify(osg::NOTICE)<<"_inactivePagedLODList : moving PageLOD to active list"<<std::endl;
780            // found a reactivated pagedLOD's need to put it back in the active list.               
781            _activePagedLODList.push_back(*inactive_itr);
782            remove_plod = true;
783        }
784       
785        if (remove_plod)
786        {
787            PagedLODList::iterator itr_to_erase = inactive_itr;
788            ++inactive_itr;
789           
790            _inactivePagedLODList.erase(itr_to_erase);           
791        }
792        else
793        {
794//            if (i<numberOfPagedLODToTest)
795            if (childrenRemoved.size()<targetNumOfRemovedChildPagedLODs)
796            {
797                // check for removing expired children.
798                if (const_cast<osg::PagedLOD*>(plod)->removeExpiredChildren(expiryTime,childrenRemoved))
799                {
800                    //osg::notify(osg::NOTICE)<<"Some children removed from PLod"<<std::endl;
801                }
802                else
803                {
804                    // osg::notify(osg::NOTICE)<<"no children removed from PLod"<<std::endl;
805                }
806            }
807       
808            ++inactive_itr;
809            ++i;
810        }
811    }
812
813    //osg::notify(osg::NOTICE)<<"_activePagedLODList.size()="<<_activePagedLODList.size()<<"\t_inactivePagedLODList.size()="<<_inactivePagedLODList.size()<<std::endl;
814
815
816    // osg::notify(osg::NOTICE)<<"   number stale "<<numberStale<<"  number active "<<_pagedLODList.size()-numberStale<<std::endl;
817
818    //double t = osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick());
819    //osg::notify(osg::NOTICE)<<"   time 1 "<<t<<" ms "<<_pagedLODList.size()<<" pagedLOD's"<<std::endl;
820    //osg::notify(osg::NOTICE)<<"   average time = "<<t/(double)_pagedLODList.size()<<" ms/per PagedLOD"<<std::endl;
821
822    if (!childrenRemoved.empty())
823    {
824        // pass the objects across to the database pager delete list
825        if (_deleteRemovedSubgraphsInDatabaseThread)
826        {
827            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex);
828            for (osg::NodeList::iterator critr = childrenRemoved.begin();
829                 critr!=childrenRemoved.end();
830                 ++critr)
831            {
832                _childrenToDeleteList.push_back(critr->get());
833            }
834            updateDatabasePagerThreadBlock();
835        }
836
837        childrenRemoved.clear();
838    }
839
840    // osg::notify(osg::NOTICE)<<"   time 2 "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
841
842   
843    if (osgDB::Registry::instance()->getSharedStateManager())
844        osgDB::Registry::instance()->getSharedStateManager()->prune();
845
846    // update the Registry object cache.
847    osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(currentFrameTime);
848    osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime);
849
850
851    // osg::notify(osg::NOTICE)<<"Done DatabasePager::removeExpiredSubgraphs() "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
852
853}
854
855
856class DatabasePager::FindPagedLODsVisitor : public osg::NodeVisitor
857{
858public:
859    FindPagedLODsVisitor(DatabasePager::PagedLODList& pagedLODList):
860        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
861        _pagedLODList(pagedLODList)
862    {
863    }
864   
865    virtual void apply(osg::PagedLOD& plod)
866    {
867        _pagedLODList.push_back(&plod);
868   
869        traverse(plod);
870    }
871   
872    DatabasePager::PagedLODList& _pagedLODList;
873};
874
875void DatabasePager::registerPagedLODs(osg::Node* subgraph)
876{
877    FindPagedLODsVisitor fplv(_activePagedLODList);
878    if (subgraph) subgraph->accept(fplv);
879}
880
881bool DatabasePager::requiresCompileGLObjects() const
882{
883    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
884    return !_dataToCompileList.empty();
885}
886
887void DatabasePager::setCompileGLObjectsForContextID(unsigned int contextID, bool on)
888{
889    if (on)
890    {
891        _activeGraphicsContexts.insert(contextID);
892    }
893    else
894    {
895        _activeGraphicsContexts.erase(contextID);
896    }
897}
898
899bool DatabasePager::getCompileGLObjectsForContextID(unsigned int contextID)
900{
901    return _activeGraphicsContexts.count(contextID)!=0;
902}
903
904
905DatabasePager::CompileOperation::CompileOperation(osgDB::DatabasePager* databasePager):
906    osg::Operation("DatabasePager::CompileOperation",false),
907    _databasePager(databasePager)
908{
909}
910
911void DatabasePager::CompileOperation::operator () (osg::Object* object)
912{
913    osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
914    if (!context) return;
915
916    // osg::notify(osg::NOTICE)<<"Background thread compiling"<<std::endl;
917    if (_databasePager.valid()) _databasePager->compileAllGLObjects(*(context->getState()));
918   
919}
920
921bool DatabasePager::requiresExternalCompileGLObjects(unsigned int contextID) const
922{
923    if (_activeGraphicsContexts.count(contextID)==0) return false;
924
925    return osg::GraphicsContext::getCompileContext(contextID)==0;
926}
927
928void DatabasePager::compileAllGLObjects(osg::State& state)
929{
930    double availableTime = DBL_MAX;
931    compileGLObjects(state, availableTime);
932}
933
934void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
935{
936    // osg::notify(osg::NOTICE)<<"DatabasePager::compileGLObjects "<<_frameNumber<<std::endl;
937
938    bool compileAll = (availableTime==DBL_MAX);
939
940    osg::RenderInfo renderInfo;
941    renderInfo.setState(&state);
942
943    if (availableTime>0.0)
944    {
945
946        const osg::Timer& timer = *osg::Timer::instance();
947        osg::Timer_t start_tick = timer.tick();
948        double elapsedTime = 0.0;
949        double estimatedTextureDuration = 0.0001;
950        double estimatedDrawableDuration = 0.0001;
951
952        osg::ref_ptr<DatabaseRequest> databaseRequest;
953
954        // get the first compileable entry.
955        {
956            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
957            if (!_dataToCompileList.empty())
958            {
959                std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor());
960
961                // prune all the old entries.
962                DatabaseRequestList::iterator litr;
963                int i=0;
964                for(litr = _dataToCompileList.begin();
965                    (litr != _dataToCompileList.end()) && (_frameNumber-(*litr)->_frameNumberLastRequest)<=1;
966                    ++litr,i++)
967                {
968                    //osg::notify(osg::NOTICE)<<"Compile "<<_frameNumber-(*litr)->_frameNumberLastRequest<<std::endl;
969                }
970                if (litr != _dataToCompileList.end())
971                {
972                    if (_deleteRemovedSubgraphsInDatabaseThread)
973                    {
974                        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex);
975
976                        for(DatabaseRequestList::iterator ditr=litr;
977                            ditr!=_dataToCompileList.end();
978                            ++ditr)
979                        {
980                            _childrenToDeleteList.push_back((*ditr)->_loadedModel.get());
981                        }
982                    }
983                    //osg::notify(osg::NOTICE)<<"Pruning "<<_dataToCompileList.size()-i<<std::endl;
984                    _dataToCompileList.erase(litr,_dataToCompileList.end());
985                }
986
987                // advance to the next entry to compile if one is available.
988                databaseRequest = _dataToCompileList.empty() ? 0 : _dataToCompileList.front();
989           
990            }
991        };
992
993        unsigned int numObjectsCompiled = 0;
994
995        // while there are valid databaseRequest's in the to compile list and there is
996        // sufficient time left compile each databaseRequest's stateset and drawables.
997        while (databaseRequest.valid() && (compileAll || (elapsedTime<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)) )
998        {
999            DataToCompileMap& dcm = databaseRequest->_dataToCompileMap;
1000            DataToCompile& dtc = dcm[state.getContextID()];
1001            if (!dtc.first.empty() && (elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)
1002            {
1003
1004                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
1005
1006                // we have StateSet's to compile
1007                StateSetList& sslist = dtc.first;
1008                //osg::notify(osg::INFO)<<"Compiling statesets"<<std::endl;
1009                StateSetList::iterator itr=sslist.begin();
1010                for(;
1011                    itr!=sslist.end() && (elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame;
1012                    ++itr)
1013                {
1014                    //osg::notify(osg::INFO)<<"    Compiling stateset "<<(*itr).get()<<std::endl;
1015
1016                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
1017
1018                    (*itr)->compileGLObjects(state);
1019
1020                    GLint p;
1021                    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p);
1022
1023                    elapsedTime = timer.delta_s(start_tick,timer.tick());
1024
1025
1026                    // estimate the duration of the compile based on current compile duration.
1027                    estimatedTextureDuration = (elapsedTime-startCompileTime);
1028
1029                    ++numObjectsCompiled;
1030                }
1031                // remove the compiled stateset from the list.
1032                sslist.erase(sslist.begin(),itr);
1033            }
1034
1035            if (!dtc.second.empty() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)))
1036            {
1037                // we have Drawable's to compile
1038                //osg::notify(osg::INFO)<<"Compiling drawables"<<std::endl;
1039                DrawableList& dwlist = dtc.second;
1040                DrawableList::iterator itr=dwlist.begin();
1041                for(;
1042                    itr!=dwlist.end() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
1043                    ++itr)
1044                {
1045                    //osg::notify(osg::INFO)<<"    Compiling drawable "<<(*itr).get()<<std::endl;
1046                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
1047                    (*itr)->compileGLObjects(renderInfo);
1048                    elapsedTime = timer.delta_s(start_tick,timer.tick());
1049
1050                    // estimate the duration of the compile based on current compile duration.
1051                    estimatedDrawableDuration = (elapsedTime-startCompileTime);
1052
1053                    ++numObjectsCompiled;
1054
1055                }
1056                // remove the compiled drawables from the list.
1057                dwlist.erase(dwlist.begin(),itr);
1058            }
1059
1060            //osg::notify(osg::INFO)<<"Checking if compiled"<<std::endl;
1061
1062            // now check the to compile entries for all active graphics contexts
1063            // to make sure that all have been compiled.
1064            bool allCompiled = true;
1065            for(DataToCompileMap::iterator itr=dcm.begin();
1066                itr!=dcm.end() && allCompiled;
1067                ++itr)
1068            {
1069                if (!(itr->second.first.empty())) allCompiled=false;
1070                if (!(itr->second.second.empty())) allCompiled=false;
1071            }
1072
1073
1074            if (allCompiled)
1075            {
1076                // we've compile all of the current databaseRequest so we can now pop it off the
1077                // osg::notify(osg::NOTICE)<<"All compiled"<<std::endl;
1078
1079                // to compile list and place it on the merge list.
1080                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
1081
1082                {
1083                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
1084                    _dataToMergeList.push_back(databaseRequest);
1085                }
1086
1087                if (!_dataToCompileList.empty()) _dataToCompileList.erase(_dataToCompileList.begin());
1088
1089                if (!_dataToCompileList.empty())
1090                {
1091                    std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor());
1092                    databaseRequest = _dataToCompileList.front();
1093                }
1094                else databaseRequest = 0;
1095
1096            }
1097            else 
1098            {
1099                // osg::notify(osg::NOTICE)<<"Not all compiled"<<std::endl;
1100                databaseRequest = 0;
1101            }
1102
1103            elapsedTime = timer.delta_s(start_tick,timer.tick());
1104        }
1105
1106        availableTime -= elapsedTime;
1107
1108        //osg::notify(osg::NOTICE)<<"elapsedTime="<<elapsedTime<<"\ttime remaining ="<<availableTime<<"\tnumObjectsCompiled = "<<numObjectsCompiled<<std::endl;
1109        //osg::notify(osg::NOTICE)<<"estimatedTextureDuration="<<estimatedTextureDuration;
1110        //osg::notify(osg::NOTICE)<<"\testimatedDrawableDuration="<<estimatedDrawableDuration<<std::endl;
1111    }
1112    else
1113    {
1114        availableTime = 0.0f;
1115    }
1116}
Note: See TracBrowser for help on using the browser.