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

Revision 9736, 76.7 kB (checked in by robert, 5 years ago)

Fixed to DatabasePager::getRequestsInProgress(), merged from:

svn merge -r 9734:9735 http://www.openscenegraph.org/svn/osg/OpenSceneGraph/branches/OpenSceneGraph-2.8

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgDB/DatabasePager>
15#include <osgDB/WriteFile>
16#include <osgDB/FileNameUtils>
17#include <osgDB/FileUtils>
18#include <osgDB/Registry>
19
20#include <osg/Geode>
21#include <osg/Timer>
22#include <osg/Texture>
23#include <osg/Notify>
24#include <osg/ProxyNode>
25#include <osg/ApplicationUsage>
26
27#include <OpenThreads/ScopedLock>
28
29#include <algorithm>
30#include <functional>
31#include <set>
32
33#include <stdlib.h>
34#include <string.h>
35
36#ifdef WIN32
37#include <windows.h>
38#else
39#include <unistd.h>
40#endif
41
42using namespace osgDB;
43using namespace OpenThreads;
44
45static 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.");
46static 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.");
47static 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.");
48static 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>.");
49static osg::ApplicationUsageProxy DatabasePager_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_PRIORITY <mode>", "Set the thread priority to DEFAULT, MIN, LOW, NOMINAL, HIGH or MAX.");
50static osg::ApplicationUsageProxy DatabasePager_e7(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_EXPIRY_DELAY <float> ","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.");
51static osg::ApplicationUsageProxy DatabasePager_e8(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_EXPIRY_FRAMES <int> ","Set number of frames a PagedLOD child is kept in memory, without being used, before its tagged as expired, and ear marked to deletion.");
52static osg::ApplicationUsageProxy DatabasePager_e9(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RELEASE_DELAY <float> ","Set the length of time a PagedLOD child's OpenGL objects are kept in memory, without being used, before be released (setting to OFF disables this feature.)");
53static osg::ApplicationUsageProxy DatabasePager_e10(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RELEASE_FRAMES <int> ","Set number of frames a PagedLOD child's OpenGL objects are kept in memory, without being used, before be released.");
54static osg::ApplicationUsageProxy DatabasePager_e11(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_PAGEDLOD <num>","Set the target maximum number of PagedLOD to maintain.");
55
56// Convert function objects that take pointer args into functions that a
57// reference to an osg::ref_ptr. This is quite useful for doing STL
58// operations on lists of ref_ptr. This code assumes that a function
59// with an argument const Foo* should be composed into a function of
60// argument type ref_ptr<Foo>&, not ref_ptr<const Foo>&. Some support
61// for that should be added to make this more general.
62
63namespace
64{
65template <typename U>
66struct PointerTraits
67{
68    typedef class NullType {} PointeeType;
69};
70
71template <typename U>
72struct PointerTraits<U*>
73{
74    typedef U PointeeType;
75};
76
77template <typename U>
78struct PointerTraits<const U*>
79{
80    typedef U PointeeType;
81};
82
83template <typename FuncObj>
84class RefPtrAdapter
85    : public std::unary_function<const osg::ref_ptr<typename PointerTraits<typename FuncObj::argument_type>::PointeeType>,
86                                 typename FuncObj::result_type>
87{
88public:
89    typedef typename PointerTraits<typename FuncObj::argument_type>::PointeeType PointeeType;
90    typedef osg::ref_ptr<PointeeType> RefPtrType;
91    explicit RefPtrAdapter(const FuncObj& funcObj) : _func(funcObj) {}
92    typename FuncObj::result_type operator()(const RefPtrType& refPtr) const
93    {
94        return _func(refPtr.get());
95    }
96protected:
97        FuncObj _func;
98};
99
100template <typename FuncObj>
101RefPtrAdapter<FuncObj> refPtrAdapt(const FuncObj& func)
102{
103    return RefPtrAdapter<FuncObj>(func);
104}
105}
106
107/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
108//
109//  FindCompileableGLObjectsVisitor
110//
111class DatabasePager::FindCompileableGLObjectsVisitor : public osg::NodeVisitor
112{
113public:
114    FindCompileableGLObjectsVisitor(DatabasePager::DataToCompile& dataToCompile,
115                               bool changeAutoUnRef, bool valueAutoUnRef,
116                               bool changeAnisotropy, float valueAnisotropy,
117                               DatabasePager::DrawablePolicy drawablePolicy,
118                               const DatabasePager* pager):
119            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
120            _dataToCompile(dataToCompile),
121            _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
122            _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy),
123            _drawablePolicy(drawablePolicy), _pager(pager)
124    {
125        if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES &&
126            osgDB::Registry::instance()->getKdTreeBuilder())
127        {
128            _kdTreeBuilder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
129        }
130       
131    }
132   
133    META_NodeVisitor("osgDB","FindCompileableGLObjectsVisitor")
134   
135    virtual void apply(osg::Node& node)
136    {
137        apply(node.getStateSet());
138
139        traverse(node);
140    }
141   
142    virtual void apply(osg::Geode& geode)
143    {
144        apply(geode.getStateSet());
145   
146        for(unsigned int i=0;i<geode.getNumDrawables();++i)
147        {
148            apply(geode.getDrawable(i));
149        }
150
151        traverse(geode);
152       
153        if (_kdTreeBuilder.valid())
154        {
155            geode.accept(*_kdTreeBuilder);
156        }
157       
158    }
159   
160    inline void apply(osg::StateSet* stateset)
161    {
162        if (stateset)
163        {
164            // search for the existance of any texture object
165            // attributes
166            // if texture object attributes exist and need to be
167            // compiled, add the state to the list for later
168            // compilation.
169            bool compileStateSet = false;
170            for(unsigned int i=0;i<stateset->getTextureAttributeList().size();++i)
171            {
172                osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
173                // Has this texture already been encountered?
174                if (texture && !_textureSet.count(texture))
175                {
176                    _textureSet.insert(texture);
177                    if (_changeAutoUnRef) texture->setUnRefImageDataAfterApply(_valueAutoUnRef);
178                    if ((_changeAnisotropy
179                         && texture->getMaxAnisotropy() != _valueAnisotropy))
180                    {
181                        if (_changeAnisotropy)
182                            texture->setMaxAnisotropy(_valueAnisotropy);
183                    }
184                   
185                    if (!_pager->isCompiled(texture))
186                    {
187                        compileStateSet = true;
188                        if (osg::getNotifyLevel() >= osg::DEBUG_INFO)
189                        {
190                            osg::notify(osg::DEBUG_INFO)
191                                <<"Found compilable texture " << texture << " ";
192                            osg::Image* image = texture->getImage(0);
193                            if (image) osg::notify(osg::DEBUG_INFO) << image->getFileName();
194                            osg::notify(osg::DEBUG_INFO) << std:: endl;
195                        }
196                        break;
197                    }
198                }
199            }
200            if (compileStateSet)
201            {
202                _dataToCompile.first.insert(stateset);
203            }
204
205        }
206    }
207   
208    inline void apply(osg::Drawable* drawable)
209    {
210        if (_drawableSet.count(drawable))
211            return;
212
213        _drawableSet.insert(drawable);
214       
215        apply(drawable->getStateSet());
216       
217        switch(_drawablePolicy)
218        {
219        case DatabasePager::DO_NOT_MODIFY_DRAWABLE_SETTINGS:
220             // do nothing, leave settings as they came in from loaded database.
221             // osg::notify(osg::NOTICE)<<"DO_NOT_MODIFY_DRAWABLE_SETTINGS"<<std::endl;
222             break;
223        case DatabasePager::USE_DISPLAY_LISTS:
224             drawable->setUseDisplayList(true);
225             drawable->setUseVertexBufferObjects(false);
226             break;
227        case DatabasePager::USE_VERTEX_BUFFER_OBJECTS:
228             drawable->setUseDisplayList(true);
229             drawable->setUseVertexBufferObjects(true);
230             // osg::notify(osg::NOTICE)<<"USE_VERTEX_BUFFER_OBJECTS"<<std::endl;
231             break;
232        case DatabasePager::USE_VERTEX_ARRAYS:
233             drawable->setUseDisplayList(false);
234             drawable->setUseVertexBufferObjects(false);
235             // osg::notify(osg::NOTICE)<<"USE_VERTEX_ARRAYS"<<std::endl;
236             break;
237        }
238        // Don't compile if already compiled. This can happen if the
239        // subgraph is shared with already-loaded nodes.
240        //
241        // XXX This "compiles" VBOs too, but compilation doesn't do
242        // anything for VBOs, does it?
243        if (drawable->getUseDisplayList() && !_pager->isCompiled(drawable))
244        {
245            // osg::notify(osg::NOTICE)<<"  Found compilable drawable"<<std::endl;
246            _dataToCompile.second.push_back(drawable);
247        }
248    }
249   
250    DatabasePager::DataToCompile&           _dataToCompile;
251    bool                                    _changeAutoUnRef;
252    bool                                    _valueAutoUnRef;
253    bool                                    _changeAnisotropy;
254    float                                   _valueAnisotropy;
255    DatabasePager::DrawablePolicy           _drawablePolicy;
256    const DatabasePager*                    _pager;
257    std::set<osg::ref_ptr<osg::Texture> >   _textureSet;
258    std::set<osg::ref_ptr<osg::Drawable> >  _drawableSet;
259    osg::ref_ptr<osg::KdTreeBuilder>        _kdTreeBuilder;
260   
261protected:
262
263    FindCompileableGLObjectsVisitor& operator = (const FindCompileableGLObjectsVisitor&) { return *this; }
264};
265
266
267/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
268//
269//  SortFileRequestFunctor
270//
271struct DatabasePager::SortFileRequestFunctor
272{
273    bool operator() (const osg::ref_ptr<DatabasePager::DatabaseRequest>& lhs,const osg::ref_ptr<DatabasePager::DatabaseRequest>& rhs) const
274    {
275        if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true;
276        else if (lhs->_timestampLastRequest<rhs->_timestampLastRequest) return false;
277        else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest);
278    }
279};
280
281
282/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
283//
284//  ReadQueue
285//
286void DatabasePager::RequestQueue::sort()
287{
288    std::sort(_requestList.begin(),_requestList.end(),SortFileRequestFunctor());
289}
290
291
292/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293//
294//  ReadQueue
295//
296DatabasePager::ReadQueue::ReadQueue(DatabasePager* pager, const std::string& name):
297    _pager(pager),
298    _name(name)
299{
300    _block = new osg::RefBlock;
301}
302
303void DatabasePager::ReadQueue::clear()
304{
305    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
306
307    for(RequestList::iterator citr = _requestList.begin();
308        citr != _requestList.end();
309        ++citr)
310    {
311        (*citr)->_loadedModel = 0;
312        (*citr)->_requestQueue = 0;
313    }
314
315    _requestList.clear();
316
317    updateBlock();
318}
319
320void DatabasePager::ReadQueue::add(DatabasePager::DatabaseRequest* databaseRequest)
321{
322    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
323    _requestList.push_back(databaseRequest);
324    databaseRequest->_requestQueue = this;
325
326    updateBlock();
327}
328
329void DatabasePager::ReadQueue::takeFirst(osg::ref_ptr<DatabaseRequest>& databaseRequest)
330{
331    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
332
333    if (!_requestList.empty())
334    {
335        sort();
336   
337        databaseRequest = _requestList.front();
338        databaseRequest->_requestQueue = 0;
339        _requestList.erase(_requestList.begin());
340
341        updateBlock();
342    }
343}
344
345/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
346//
347//  DatabaseThread
348//
349DatabasePager::DatabaseThread::DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name):
350    _done(false),
351    _active(false),
352    _pager(pager),
353    _mode(mode),
354    _name(name)
355{
356}
357
358DatabasePager::DatabaseThread::DatabaseThread(const DatabaseThread& dt, DatabasePager* pager):
359    _done(false),
360    _active(false),
361    _pager(pager),
362    _mode(dt._mode),
363    _name(dt._name)
364{
365   
366}
367
368DatabasePager::DatabaseThread::~DatabaseThread()
369{
370    cancel();
371}
372
373int DatabasePager::DatabaseThread::cancel()
374{
375    int result = 0;
376
377    if( isRunning() )
378    {
379   
380        _done = true;
381       
382        switch(_mode)
383        {
384            case(HANDLE_ALL_REQUESTS):
385                _pager->_fileRequestQueue->release();
386                break;
387            case(HANDLE_NON_HTTP):
388                _pager->_fileRequestQueue->release();
389                break;
390            case(HANDLE_ONLY_HTTP):
391                _pager->_httpRequestQueue->release();
392                break;
393        }
394
395        // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
396        // _databasePagerThreadBlock->release();
397
398        // then wait for the the thread to stop running.
399        while(isRunning())
400        {
401            // commenting out debug info as it was cashing crash on exit, presumable
402            // due to osg::notify or std::cout destructing earlier than this destructor.
403            // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<<std::endl;
404            OpenThreads::Thread::YieldCurrentThread();
405        }
406       
407        // _startThreadCalled = false;
408    }
409    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
410    return result;
411
412}
413
414void DatabasePager::DatabaseThread::run()
415{
416    osg::notify(osg::INFO)<<_name<<": DatabasePager::DatabaseThread::run"<<std::endl;
417   
418#if 1
419    // need to set the texture object manager to be able to reuse textures
420    osg::Texture::setMinimumNumberOfTextureObjectsToRetainInCache(100);
421   
422    // need to set the display list manager to be able to reuse display lists
423    osg::Drawable::setMinimumNumberOfDisplayListsToRetainInCache(100);
424#else
425    // need to set the texture object manager to be able to reuse textures
426    osg::Texture::setMinimumNumberOfTextureObjectsToRetainInCache(0);
427   
428    // need to set the display list manager to be able to reuse display lists
429    osg::Drawable::setMinimumNumberOfDisplayListsToRetainInCache(0);
430#endif
431
432    bool firstTime = true;
433   
434    osg::ref_ptr<DatabasePager::ReadQueue> read_queue;
435    osg::ref_ptr<DatabasePager::ReadQueue> out_queue;
436   
437    switch(_mode)
438    {
439        case(HANDLE_ALL_REQUESTS):
440            read_queue = _pager->_fileRequestQueue;
441            break;
442        case(HANDLE_NON_HTTP):
443            read_queue = _pager->_fileRequestQueue;
444            out_queue = _pager->_httpRequestQueue;
445            break;
446        case(HANDLE_ONLY_HTTP):
447            read_queue = _pager->_httpRequestQueue;
448            break;
449    }
450   
451    //Getting CURL Environment Variables (If found rewrite OSG Options)
452    osg::ref_ptr<FileCache> fileCache = osgDB::Registry::instance()->getFileCache();
453
454    do
455    {
456        _active = false;
457
458        read_queue->block();
459
460        _active = true;
461
462        osg::notify(osg::INFO)<<_name<<": _pager->_requestList.size()= "<<read_queue->_requestList.size()<<" to delete = "<<read_queue->_childrenToDeleteList.size()<<std::endl;
463
464
465        //
466        // delete any children if required.
467        //
468        if (_pager->_deleteRemovedSubgraphsInDatabaseThread && !(read_queue->_childrenToDeleteList.empty()))
469        {
470            ObjectList deleteList;
471
472            {
473                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(read_queue->_childrenToDeleteListMutex);
474                deleteList.swap(read_queue->_childrenToDeleteList);
475                read_queue->updateBlock();
476            }
477        }
478
479        //
480        // load any subgraphs that are required.
481        //
482        osg::ref_ptr<DatabaseRequest> databaseRequest;
483        read_queue->takeFirst(databaseRequest);
484
485        bool readFromFileCache = false;
486               
487        if (databaseRequest.valid())
488        {
489            // check if databaseRequest is still relevant
490            if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)<=1)
491            {
492
493                // now check to see if this request is appropriate for this thread
494                switch(_mode)
495                {
496                    case(HANDLE_ALL_REQUESTS):
497                        // do nothing as this thread can handle the load
498                        if (osgDB::containsServerAddress(databaseRequest->_fileName))
499                        {
500                            if (fileCache.valid() && fileCache->existsInCache(databaseRequest->_fileName))
501                            {
502                                readFromFileCache = true;
503                            }
504                        }
505                        break;
506                       
507                    case(HANDLE_NON_HTTP):
508                        // check the cache first
509                        if (osgDB::containsServerAddress(databaseRequest->_fileName))
510                        {
511                            if (fileCache.valid() && fileCache->existsInCache(databaseRequest->_fileName))
512                            {
513                                readFromFileCache = true;
514                            }
515                            else
516                            {
517                                osg::notify(osg::INFO)<<_name<<": Passing http requests over "<<databaseRequest->_fileName<<std::endl;
518                                out_queue->add(databaseRequest.get());
519                                databaseRequest = 0;
520                            }
521                        }
522                        break;
523                       
524                    case(HANDLE_ONLY_HTTP):
525                        // make sure the request is a http request
526                        if (!osgDB::containsServerAddress(databaseRequest->_fileName))
527                        {
528                            osg::notify(osg::NOTICE)<<_name<<": Help we have request we shouldn't have "<<databaseRequest->_fileName<<std::endl;
529                            databaseRequest = 0;
530                        }
531                        break;
532                }
533            }
534            else
535            {               
536                databaseRequest = 0;
537            }
538        }
539       
540       
541        if (databaseRequest.valid())
542        {
543                       
544            // load the data, note safe to write to the databaseRequest since once
545            // it is created this thread is the only one to write to the _loadedModel pointer.
546            //osg::notify(osg::NOTICE)<<"In DatabasePager thread readNodeFile("<<databaseRequest->_fileName<<")"<<std::endl;
547            //osg::Timer_t before = osg::Timer::instance()->tick();
548
549
550            // assume that readNode is thread safe...
551            ReaderWriter::ReadResult rr = readFromFileCache ?
552                        fileCache->readNode(databaseRequest->_fileName, databaseRequest->_loadOptions.get(), false) :
553                        Registry::instance()->readNode(databaseRequest->_fileName, databaseRequest->_loadOptions.get(), false);
554
555            if (rr.validNode()) databaseRequest->_loadedModel = rr.getNode();
556            if (rr.error()) osg::notify(osg::WARN)<<"Error in reading file "<<databaseRequest->_fileName<<" : "<<rr.message() << std::endl;
557
558            if (databaseRequest->_loadedModel.valid() &&
559                osgDB::containsServerAddress(databaseRequest->_fileName) &&
560                fileCache.valid() &&
561                !readFromFileCache)
562            {
563                fileCache->writeNode(*(databaseRequest->_loadedModel), databaseRequest->_fileName, databaseRequest->_loadOptions.get());
564            }
565
566            if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)>1)
567            {
568                osg::notify(osg::INFO)<<_name<<": Warning DatabaseRquest no longer required."<<std::endl;
569                databaseRequest->_loadedModel = 0;
570            }
571           
572            osg::ref_ptr<osg::Group> groupForAddingLoadedSubgraph = databaseRequest->_groupForAddingLoadedSubgraph.get();
573
574            if (!groupForAddingLoadedSubgraph)
575            {
576                osg::notify(osg::INFO)<<_name<<": Warning parent of loaded subgraph, deleted."<<std::endl;
577                databaseRequest->_loadedModel = 0;
578            }
579
580            //osg::notify(osg::NOTICE)<<"     node read in "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms"<<std::endl;
581
582            bool loadedObjectsNeedToBeCompiled = false;
583
584            if (databaseRequest->_loadedModel.valid())
585            {           
586                databaseRequest->_loadedModel->getBound();
587
588                osg::NodePath nodePath;
589                osg::NodePathList nodePathList = groupForAddingLoadedSubgraph->getParentalNodePaths();
590                if (!nodePathList.empty()) nodePath = nodePathList.front();
591                nodePath.push_back(groupForAddingLoadedSubgraph.get());
592
593#if 1
594                // force a compute of the loaded model's bounding volume, so that when the subgraph
595                // merged with the main scene graph and large computeBound() isn't incurred.
596                ActiveGraphicsContexts::iterator itr = _pager->_activeGraphicsContexts.begin();
597
598                DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr];
599                ++itr;               
600
601                // find all the compileable rendering objects
602                DatabasePager::FindCompileableGLObjectsVisitor frov(dtc,
603                                                     _pager->_changeAutoUnRef, _pager->_valueAutoUnRef,
604                                                     _pager->_changeAnisotropy, _pager->_valueAnisotropy,
605                                                     _pager->_drawablePolicy,
606                                                     _pager);
607
608                // push the soon to be parent on the nodepath of the NodeVisitor so that
609                // during traversal one can test for where it'll be in the overall scene graph               
610                for(osg::NodePath::iterator nitr = nodePath.begin();
611                    nitr != nodePath.end();
612                    ++nitr)
613                {
614                    frov.pushOntoNodePath(*nitr);
615                }
616
617                databaseRequest->_loadedModel->accept(frov);
618
619                if (_pager->_doPreCompile &&
620                    !_pager->_activeGraphicsContexts.empty())
621                {
622                    if (!dtc.first.empty() || !dtc.second.empty())
623                    {
624                        loadedObjectsNeedToBeCompiled = true;               
625
626                        // copy the objects from the compile list to the other graphics context list.
627                        for(;
628                            itr != _pager->_activeGraphicsContexts.end();
629                            ++itr)
630                        {
631                            databaseRequest->_dataToCompileMap[*itr] = dtc;
632                        }
633                    }
634                }
635#else
636                if (_pager->_doPreCompile &&
637                    !_pager->_activeGraphicsContexts.empty())
638                {
639                    // force a compute of the loaded model's bounding volume, so that when the subgraph
640                    // merged with the main scene graph and large computeBound() isn't incurred.
641                    ActiveGraphicsContexts::iterator itr = _pager->_activeGraphicsContexts.begin();
642
643                    DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr];
644                    ++itr;               
645
646                    // find all the compileable rendering objects
647                    DatabasePager::FindCompileableGLObjectsVisitor frov(dtc,
648                                                         _pager->_changeAutoUnRef, _pager->_valueAutoUnRef,
649                                                         _pager->_changeAnisotropy, _pager->_valueAnisotropy,
650                                                         _pager->_drawablePolicy,
651                                                         _pager);
652
653                    // push the soon to be parent on the nodepath of the NodeVisitor so that
654                    // during traversal one can test for where it'll be in the overall scene graph               
655                    for(osg::NodePath::iterator nitr = nodePath.begin();
656                        nitr != nodePath.end();
657                        ++nitr)
658                    {
659                        frov.pushOntoNodePath(*nitr);
660                    }
661
662                    databaseRequest->_loadedModel->accept(frov);
663
664                    if (!dtc.first.empty() || !dtc.second.empty())
665                    {
666                        loadedObjectsNeedToBeCompiled = true;               
667
668                        // copy the objects from the compile list to the other graphics context list.
669                        for(;
670                            itr != _pager->_activeGraphicsContexts.end();
671                            ++itr)
672                        {
673                            databaseRequest->_dataToCompileMap[*itr] = dtc;
674                        }
675                    }
676                }
677                else
678                {
679                    // check to see if we need to run the KdTreeBuilder
680                    if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES &&
681                        osgDB::Registry::instance()->getKdTreeBuilder())
682                    {
683                        //osg::Timer_t before = osg::Timer::instance()->tick();
684                        //osg::notify(osg::NOTICE)<<"osgTerrain::GeometryTechnique::build kd tree"<<std::endl;
685                        osg::ref_ptr<osg::KdTreeBuilder> builder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
686
687                        for(osg::NodePath::iterator nitr = nodePath.begin();
688                            nitr != nodePath.end();
689                            ++nitr)
690                        {
691                            builder->pushOntoNodePath(*nitr);
692                        }
693
694                        databaseRequest->_loadedModel->accept(*builder);
695                        //osg::Timer_t after = osg::Timer::instance()->tick();
696                        //osg::notify(osg::NOTICE)<<"KdTree build time "<<osg::Timer::instance()->delta_m(before, after)<<std::endl;
697                    }
698                }
699#endif
700
701                // move the databaseRequest from the front of the fileRequest to the end of
702                // dataToCompile or dataToMerge lists.
703                if (loadedObjectsNeedToBeCompiled)
704                {
705                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_dataToCompileList->_requestMutex);
706                    databaseRequest->_requestQueue = _pager->_dataToCompileList.get();
707                    _pager->_dataToCompileList->_requestList.push_back(databaseRequest);
708                }
709                else
710                {
711                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_dataToMergeList->_requestMutex);
712                    databaseRequest->_requestQueue = _pager->_dataToMergeList.get();
713                    _pager->_dataToMergeList->_requestList.push_back(databaseRequest);
714                }
715            }       
716
717            // Prepare and prune the to-be-compiled list here in
718            // the pager thread rather than in the draw or
719            // graphics context thread(s).
720            if (loadedObjectsNeedToBeCompiled)
721            {
722                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_dataToCompileList->_requestMutex);
723
724                _pager->_dataToCompileList->sort();
725
726                // Prune all the old entries.
727                RequestQueue::RequestList::iterator tooOld
728                    = std::find_if(_pager->_dataToCompileList->_requestList.begin(),
729                                   _pager->_dataToCompileList->_requestList.end(),
730                                   refPtrAdapt(std::not1(std::bind2nd(std::mem_fun(&DatabaseRequest::isRequestCurrent),
731                                   _pager->_frameNumber))));
732
733                // This is the database thread, so just delete
734                for(RequestQueue::RequestList::iterator citr = tooOld;
735                    citr != _pager->_dataToCompileList->_requestList.end();
736                    ++citr)
737                {
738                    osg::notify(osg::INFO)<<_name<<": pruning from compile list"<<std::endl;
739                    (*citr)->_loadedModel = 0;
740                    (*citr)->_requestQueue = 0;
741                }
742
743                _pager->_dataToCompileList->_requestList.erase(tooOld, _pager->_dataToCompileList->_requestList.end());
744
745                loadedObjectsNeedToBeCompiled = !_pager->_dataToCompileList->_requestList.empty();
746            }
747
748            if (loadedObjectsNeedToBeCompiled && !_pager->_activeGraphicsContexts.empty())
749            {
750                for(ActiveGraphicsContexts::iterator itr = _pager->_activeGraphicsContexts.begin();
751                    itr != _pager->_activeGraphicsContexts.end();
752                    ++itr)
753                {
754                    osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr);
755                    if (gc)
756                    {   
757                        osg::GraphicsThread* gt = gc->getGraphicsThread();
758                        if (gt)
759                        {
760                            gt->add(new DatabasePager::CompileOperation(_pager));
761                        }
762                        else
763                        {
764                            gc->makeCurrent();
765
766                            _pager->compileAllGLObjects(*(gc->getState()));
767
768                            gc->releaseContext();
769                        }
770                    }
771                }
772
773                // osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<<std::endl;                   
774            }
775        }
776        else
777        {
778            OpenThreads::Thread::YieldCurrentThread();
779        }
780       
781       
782        // go to sleep till our the next time our thread gets scheduled.
783
784        if (firstTime)
785        {
786            // do a yield to get round a peculiar thread hang when testCancel() is called
787            // in certain circumstances - of which there is no particular pattern.
788            YieldCurrentThread();
789            firstTime = false;
790        }
791
792    } while (!testCancel() && !_done);
793}
794
795
796DatabasePager::DatabasePager()
797{
798    //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<<std::endl;
799   
800    _startThreadCalled = false;
801
802    _done = false;
803    _acceptNewRequests = true;
804    _databasePagerThreadPaused = false;
805   
806    _numFramesActive = 0;
807    _frameNumber = 0;
808   
809    const char* str = getenv("OSG_DATABASE_PAGER_PRIORITY");
810    if (str)
811    {
812        if (strcmp(str,"DEFAULT")==0)
813        {
814            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_DEFAULT);
815        }
816        else if (strcmp(str,"MIN")==0)
817        {
818            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MIN);
819        }
820        else if (strcmp(str,"LOW")==0)
821        {
822            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW);
823        }
824        else if (strcmp(str,"NOMINAL")==0)
825        {
826            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_NOMINAL);
827        }
828        else if (strcmp(str,"HIGH")==0)
829        {
830            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_HIGH);
831        }
832        else if (strcmp(str,"MAX")==0)
833        {
834            setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MAX);
835        }
836    }
837
838#if __APPLE__
839    // OSX really doesn't like compiling display lists, and performs poorly when they are used,
840    // so apply this hack to make up for its short comings.
841    _drawablePolicy = USE_VERTEX_ARRAYS;
842#else
843    _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS;
844#endif   
845   
846    str = getenv("OSG_DATABASE_PAGER_GEOMETRY");
847    if (!str) str = getenv("OSG_DATABASE_PAGER_DRAWABLE");
848    if (str)
849    {
850        if (strcmp(str,"DoNotModify")==0)
851        {
852            _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS;
853        }
854        else if (strcmp(str,"DisplayList")==0 || strcmp(str,"DL")==0)
855        {
856            _drawablePolicy = USE_DISPLAY_LISTS;
857        }
858        else if (strcmp(str,"VBO")==0)
859        {
860            _drawablePolicy = USE_VERTEX_BUFFER_OBJECTS;
861        }
862        else if (strcmp(str,"VertexArrays")==0 || strcmp(str,"VA")==0 )
863        {
864            _drawablePolicy = USE_VERTEX_ARRAYS;
865        }
866    }
867
868    _changeAnisotropy = false;
869    _valueAnisotropy = 1.0f;
870
871
872   
873    const char* ptr=0;
874
875    _deleteRemovedSubgraphsInDatabaseThread = true;
876    if( (ptr = getenv("OSG_DELETE_IN_DATABASE_THREAD")) != 0)
877    {
878        _deleteRemovedSubgraphsInDatabaseThread = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
879                        strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
880
881    }
882
883    _expiryDelay = 10.0;
884    if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0)
885    {
886        _expiryDelay = atof(ptr);
887        osg::notify(osg::NOTICE)<<"Expiry delay = "<<_expiryDelay<<std::endl;
888    }
889
890    _expiryFrames = 1; // Last frame will not be expired
891    if( (ptr = getenv("OSG_EXPIRY_FRAMES")) != 0)
892    {
893        _expiryFrames = atoi(ptr);
894        osg::notify(osg::NOTICE)<<"Expiry frames = "<<_expiryFrames<<std::endl;
895    }
896
897    if( (ptr = getenv("OSG_RELEASE_DELAY")) != 0)
898    {
899        if (strcmp(ptr,"OFF")==0 || strcmp(ptr,"Off")==0  || strcmp(ptr,"off")==0)
900        {
901            setReleaseDelay(DBL_MAX);
902        }
903        else
904        {
905            setReleaseDelay(atof(ptr));
906        }
907           
908        osg::notify(osg::NOTICE)<<"Release delay = "<<_releaseDelay<<std::endl;
909    }
910    else
911    {
912        setReleaseDelay(DBL_MAX);
913    }
914   
915
916    _releaseFrames = 1; // Last frame will not be release
917    if( (ptr = getenv("OSG_RELEASE_FRAMES")) != 0)
918    {
919        _releaseFrames = atoi(ptr);
920        osg::notify(osg::NOTICE)<<"Release frames = "<<_releaseFrames<<std::endl;
921    }
922
923
924    _targetMaximumNumberOfPageLOD = 300;
925    if( (ptr = getenv("OSG_MAX_PAGEDLOD")) != 0)
926    {
927        _targetMaximumNumberOfPageLOD = atoi(ptr);
928        osg::notify(osg::NOTICE)<<"_targetMaximumNumberOfPageLOD = "<<_targetMaximumNumberOfPageLOD<<std::endl;
929    }
930
931
932    _doPreCompile = false;
933    if( (ptr = getenv("OSG_DO_PRE_COMPILE")) != 0)
934    {
935        _doPreCompile = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
936                        strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
937    }
938
939    _targetFrameRate = 100.0;
940    _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms.
941    _maximumNumOfObjectsToCompilePerFrame = 4;
942    if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0)
943    {
944        _minimumTimeAvailableForGLCompileAndDeletePerFrame = atof(ptr);
945    }
946
947    if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0)
948    {
949        _maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
950    }
951
952    // initialize the stats variables
953    resetStats();
954
955    // make sure a SharedStateManager exists.
956    //osgDB::Registry::instance()->getOrCreateSharedStateManager();
957   
958    //if (osgDB::Registry::instance()->getSharedStateManager())
959        //osgDB::Registry::instance()->setUseObjectCacheHint(true);
960       
961    _fileRequestQueue = new ReadQueue(this,"fileRequestQueue");
962    _httpRequestQueue = new ReadQueue(this,"httpRequestQueue");
963   
964    _dataToCompileList = new RequestQueue;
965    _dataToMergeList = new RequestQueue;
966   
967    setUpThreads(
968        osg::DisplaySettings::instance()->getNumOfDatabaseThreadsHint(),
969        osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint());
970
971}
972
973DatabasePager::DatabasePager(const DatabasePager& rhs)
974{
975    //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<<std::endl;
976   
977    _startThreadCalled = false;
978
979    _done = false;
980    _acceptNewRequests = true;
981    _databasePagerThreadPaused = false;
982   
983    _numFramesActive = 0;
984    _frameNumber = 0;
985
986    _drawablePolicy = rhs._drawablePolicy;
987
988    _changeAutoUnRef = rhs._changeAutoUnRef;
989    _valueAutoUnRef = rhs._valueAutoUnRef;
990    _changeAnisotropy = rhs._changeAnisotropy;
991    _valueAnisotropy = rhs._valueAnisotropy;
992
993
994    _deleteRemovedSubgraphsInDatabaseThread = rhs._deleteRemovedSubgraphsInDatabaseThread;
995   
996    _expiryDelay = rhs._expiryDelay;
997    _expiryFrames = rhs._expiryFrames;
998
999    _releaseDelay = rhs._releaseDelay;
1000    _releaseFrames = rhs._releaseFrames;
1001
1002    _targetMaximumNumberOfPageLOD = rhs._targetMaximumNumberOfPageLOD;
1003
1004    _doPreCompile = rhs._doPreCompile;
1005    _targetFrameRate = rhs._targetFrameRate;
1006    _minimumTimeAvailableForGLCompileAndDeletePerFrame = rhs._minimumTimeAvailableForGLCompileAndDeletePerFrame;
1007    _maximumNumOfObjectsToCompilePerFrame = rhs._maximumNumOfObjectsToCompilePerFrame;
1008
1009    _fileRequestQueue = new ReadQueue(this,"fileRequestQueue");
1010    _httpRequestQueue = new ReadQueue(this,"httpRequestQueue");
1011   
1012    _dataToCompileList = new RequestQueue;
1013    _dataToMergeList = new RequestQueue;
1014
1015    for(DatabaseThreadList::const_iterator dt_itr = rhs._databaseThreads.begin();
1016        dt_itr != rhs._databaseThreads.end();
1017        ++dt_itr)
1018    {
1019        _databaseThreads.push_back(new DatabaseThread(**dt_itr,this));
1020    }
1021
1022    // initialize the stats variables
1023    resetStats();
1024}
1025
1026
1027DatabasePager::~DatabasePager()
1028{
1029    cancel();
1030}
1031
1032osg::ref_ptr<DatabasePager>& DatabasePager::prototype()
1033{
1034    static osg::ref_ptr<DatabasePager> s_DatabasePager = new DatabasePager;
1035    return s_DatabasePager;
1036}
1037
1038DatabasePager* DatabasePager::create()
1039{
1040    return DatabasePager::prototype().valid() ?
1041           DatabasePager::prototype()->clone() :
1042           new DatabasePager;
1043}
1044
1045void DatabasePager::setUpThreads(unsigned int totalNumThreads, unsigned int numHttpThreads)
1046{
1047    _databaseThreads.clear();
1048   
1049    unsigned int numGeneralThreads = numHttpThreads < totalNumThreads ?
1050        totalNumThreads - numHttpThreads :
1051        1;
1052   
1053    if (numHttpThreads==0)
1054    {
1055        for(unsigned int i=0; i<numGeneralThreads; ++i)
1056        {
1057            addDatabaseThread(DatabaseThread::HANDLE_ALL_REQUESTS,"HANDLE_ALL_REQUESTS");
1058        }
1059    }
1060    else
1061    {
1062        for(unsigned int i=0; i<numGeneralThreads; ++i)
1063        {
1064            addDatabaseThread(DatabaseThread::HANDLE_NON_HTTP, "HANDLE_NON_HTTP");
1065        }
1066
1067        for(unsigned int i=0; i<numHttpThreads; ++i)
1068        {
1069            addDatabaseThread(DatabaseThread::HANDLE_ONLY_HTTP, "HANDLE_ONLY_HTTP");
1070        }
1071    }   
1072}
1073
1074unsigned int DatabasePager::addDatabaseThread(DatabaseThread::Mode mode, const std::string& name)
1075{
1076    osg::notify(osg::INFO)<<"DatabasePager::addDatabaseThread() "<<name<<std::endl;
1077
1078    unsigned int pos = _databaseThreads.size();
1079   
1080    DatabaseThread* thread = new DatabaseThread(this, mode,name);
1081    _databaseThreads.push_back(thread);
1082   
1083    if (_startThreadCalled)
1084    {
1085        osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl;
1086        thread->startThread();
1087    }
1088   
1089    return pos;
1090}
1091
1092void DatabasePager::setReleaseDelay(double releaseDelay)
1093{
1094    _releaseDelay = releaseDelay;
1095
1096    if (_releaseDelay==DBL_MAX)
1097    {
1098        _changeAutoUnRef = true;
1099        _valueAutoUnRef = true;
1100    }
1101    else
1102    {
1103        // when GLObject release is used make sure Images aren't unref'd as they may be needed later.
1104        _changeAutoUnRef = true;
1105        _valueAutoUnRef = false;
1106    }
1107}
1108
1109int DatabasePager::setSchedulePriority(OpenThreads::Thread::ThreadPriority priority)
1110{
1111    int result = 0;
1112    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1113        dt_itr != _databaseThreads.end();
1114        ++dt_itr)
1115    {
1116        result = (*dt_itr)->setSchedulePriority(priority);
1117    }
1118    return result;
1119}
1120
1121bool DatabasePager::isRunning() const
1122{
1123    for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin();
1124        dt_itr != _databaseThreads.end();
1125        ++dt_itr)
1126    {
1127        if ((*dt_itr)->isRunning()) return true;
1128    }
1129   
1130    return false;
1131}
1132
1133int DatabasePager::cancel()
1134{
1135    int result = 0;
1136
1137    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1138        dt_itr != _databaseThreads.end();
1139        ++dt_itr)
1140    {
1141        (*dt_itr)->setDone(true);
1142    }
1143
1144    // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
1145    _fileRequestQueue->release();
1146    _httpRequestQueue->release();
1147
1148    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1149        dt_itr != _databaseThreads.end();
1150        ++dt_itr)
1151    {
1152        (*dt_itr)->cancel();
1153    }
1154
1155    _done = true;
1156    _startThreadCalled = false;
1157
1158    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
1159    return result;
1160}
1161
1162void DatabasePager::clear()
1163{
1164    _fileRequestQueue->clear();
1165    _httpRequestQueue->clear();
1166       
1167    {
1168        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
1169        for(RequestQueue::RequestList::iterator citr = _dataToCompileList->_requestList.begin();
1170            citr != _dataToCompileList->_requestList.end();
1171            ++citr)
1172        {
1173            (*citr)->_loadedModel = 0;
1174            (*citr)->_requestQueue = 0;
1175        }
1176        _dataToCompileList->_requestList.clear();
1177    }
1178
1179    {
1180        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1181        for(RequestQueue::RequestList::iterator citr = _dataToMergeList->_requestList.begin();
1182            citr != _dataToMergeList->_requestList.end();
1183            ++citr)
1184        {
1185            (*citr)->_loadedModel = 0;
1186            (*citr)->_requestQueue = 0;
1187        }
1188        _dataToMergeList->_requestList.clear();
1189    }
1190
1191    // note, no need to use a mutex as the list is only accessed from the update thread.
1192    _activePagedLODList.clear();
1193    _inactivePagedLODList.clear();
1194
1195    // ??
1196    // _activeGraphicsContexts
1197}
1198
1199void DatabasePager::resetStats()
1200{
1201    // initialize the stats variables
1202    _minimumTimeToMergeTile = DBL_MAX;
1203    _maximumTimeToMergeTile = -DBL_MAX;
1204    _totalTimeToMergeTiles = 0.0;
1205    _numTilesMerges = 0;
1206}
1207
1208bool DatabasePager::getRequestsInProgress() const
1209{
1210    if (getFileRequestListSize()>0) return true;
1211
1212    if (getDataToCompileListSize()>0)
1213    {
1214        return true;
1215    }
1216
1217    if (getDataToMergeListSize()>0) return true;
1218
1219    for(DatabaseThreadList::const_iterator itr = _databaseThreads.begin();
1220        itr != _databaseThreads.end();
1221        ++itr)
1222    {
1223        if ((*itr)->getActive()) return true;
1224    }
1225    return false;
1226}
1227
1228
1229void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group,
1230                                    float priority, const osg::FrameStamp* framestamp,
1231                                    osg::ref_ptr<osg::Referenced>& databaseRequest)
1232{
1233    requestNodeFile(fileName,group,priority,framestamp,databaseRequest,Registry::instance()->getOptions());
1234}
1235
1236void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group,
1237                                    float priority, const osg::FrameStamp* framestamp,
1238                                    osg::ref_ptr<osg::Referenced>& databaseRequestRef,
1239                                    ReaderWriter::Options* loadOptions)
1240{
1241    if (!_acceptNewRequests) return;
1242   
1243    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1244
1245    double timestamp = framestamp?framestamp->getReferenceTime():0.0;
1246    int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber;
1247   
1248    static int previousFrame = -1;
1249    static double totalTime = 0.0;
1250   
1251
1252    if (previousFrame!=frameNumber)
1253    {
1254        // osg::notify(osg::NOTICE)<<"requestNodeFiles for "<<previousFrame<<" time = "<<totalTime<<std::endl;
1255
1256        previousFrame = frameNumber;
1257        totalTime = 0.0;
1258    }
1259
1260   
1261    // search to see if filename already exist in the file loaded list.
1262    bool foundEntry = false;
1263
1264    if (databaseRequestRef.valid())
1265    {
1266        DatabaseRequest* databaseRequest = dynamic_cast<DatabaseRequest*>(databaseRequestRef.get());
1267        if (databaseRequest)
1268        {
1269            osg::notify(osg::INFO)<<"DatabasePager::fileRequest("<<fileName<<") updating already assigned."<<std::endl;
1270
1271            RequestQueue* requestQueue = databaseRequest->_requestQueue;
1272            if (requestQueue)
1273            {
1274                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(requestQueue->_requestMutex);
1275
1276                databaseRequest->_frameNumberLastRequest = frameNumber;
1277                databaseRequest->_timestampLastRequest = timestamp;
1278                databaseRequest->_priorityLastRequest = priority;
1279                ++(databaseRequest->_numOfRequests);
1280            }
1281            else
1282            {
1283                databaseRequest->_frameNumberLastRequest = frameNumber;
1284                databaseRequest->_timestampLastRequest = timestamp;
1285                databaseRequest->_priorityLastRequest = priority;
1286                ++(databaseRequest->_numOfRequests);
1287            }
1288           
1289            foundEntry = true;
1290
1291            if (databaseRequestRef->referenceCount()==1)
1292            {
1293                osg::notify(osg::INFO)<<"DatabasePager::fileRquest("<<fileName<<") orphaned, resubmitting."<<std::endl;
1294
1295                databaseRequest->_frameNumberFirstRequest = frameNumber;
1296                databaseRequest->_timestampFirstRequest = timestamp;
1297                databaseRequest->_priorityFirstRequest = priority;
1298                databaseRequest->_frameNumberLastRequest = frameNumber;
1299                databaseRequest->_timestampLastRequest = timestamp;
1300                databaseRequest->_priorityLastRequest = priority;
1301                databaseRequest->_groupForAddingLoadedSubgraph = group;
1302                databaseRequest->_loadOptions = loadOptions;
1303                databaseRequest->_requestQueue = _fileRequestQueue.get();
1304
1305                _fileRequestQueue->add(databaseRequest);
1306            }
1307           
1308        }
1309    }
1310
1311    if (!foundEntry)
1312    {
1313        osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("<<fileName<<")"<<std::endl;
1314       
1315        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_requestMutex);
1316       
1317        if (!databaseRequestRef.valid() || databaseRequestRef->referenceCount()==1)
1318        {
1319            osg::ref_ptr<DatabaseRequest> databaseRequest = new DatabaseRequest;
1320
1321            databaseRequestRef = databaseRequest.get();
1322
1323            databaseRequest->_fileName = fileName;
1324            databaseRequest->_frameNumberFirstRequest = frameNumber;
1325            databaseRequest->_timestampFirstRequest = timestamp;
1326            databaseRequest->_priorityFirstRequest = priority;
1327            databaseRequest->_frameNumberLastRequest = frameNumber;
1328            databaseRequest->_timestampLastRequest = timestamp;
1329            databaseRequest->_priorityLastRequest = priority;
1330            databaseRequest->_groupForAddingLoadedSubgraph = group;
1331            databaseRequest->_loadOptions = loadOptions;
1332            databaseRequest->_requestQueue = _fileRequestQueue.get();
1333
1334            _fileRequestQueue->_requestList.push_back(databaseRequest.get());
1335
1336            _fileRequestQueue->updateBlock();
1337        }
1338       
1339    }
1340   
1341    if (!_startThreadCalled)
1342    {
1343        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
1344       
1345        if (!_startThreadCalled)
1346        {
1347            _startThreadCalled = true;
1348            _done = false;
1349            osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl;
1350           
1351            if (_databaseThreads.empty())
1352            {
1353                setUpThreads(
1354                    osg::DisplaySettings::instance()->getNumOfDatabaseThreadsHint(),
1355                    osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint());
1356            }
1357
1358            for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin();
1359                dt_itr != _databaseThreads.end();
1360                ++dt_itr)
1361            {
1362                (*dt_itr)->startThread();
1363            }
1364        }
1365    }
1366
1367    totalTime += osg::Timer::instance()->delta_m(start_tick, osg::Timer::instance()->tick());
1368}
1369
1370void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp)
1371{
1372    if (framestamp)
1373    {
1374        //osg::notify(osg::INFO) << "signalBeginFrame "<<framestamp->getFrameNumber()<<">>>>>>>>>>>>>>>>"<<std::endl;
1375        _frameNumber = framestamp->getFrameNumber();
1376       
1377    } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<<std::endl;
1378}
1379
1380void DatabasePager::signalEndFrame()
1381{
1382    //osg::notify(osg::INFO) << "signalEndFrame <<<<<<<<<<<<<<<<<<<< "<<std::endl;
1383}
1384
1385void DatabasePager::setDatabasePagerThreadPause(bool pause)
1386{
1387    if (_databasePagerThreadPaused == pause) return;
1388   
1389    _databasePagerThreadPaused = pause;
1390    _fileRequestQueue->updateBlock();
1391    _httpRequestQueue->updateBlock();
1392}
1393
1394
1395bool DatabasePager::requiresUpdateSceneGraph() const
1396{
1397    {
1398        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1399        if (!_dataToMergeList->_requestList.empty()) return true;
1400    }
1401   
1402    return false;
1403   
1404}
1405 
1406
1407void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp)
1408{
1409    double timeStamp = frameStamp.getReferenceTime();
1410    int frameNumber = frameStamp.getFrameNumber();
1411
1412    osg::Timer_t before = osg::Timer::instance()->tick();
1413
1414    RequestQueue::RequestList localFileLoadedList;
1415
1416    // get the data for the _dataToCompileList, leaving it empty via a std::vector<>.swap.
1417    {
1418        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1419        localFileLoadedList.swap(_dataToMergeList->_requestList);
1420    }
1421       
1422    osg::Timer_t mid = osg::Timer::instance()->tick();
1423
1424    // add the loaded data into the scene graph.
1425    for(RequestQueue::RequestList::iterator itr=localFileLoadedList.begin();
1426        itr!=localFileLoadedList.end();
1427        ++itr)
1428    {
1429        DatabaseRequest* databaseRequest = itr->get();
1430
1431        // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<<std::endl;
1432       
1433        if (osgDB::Registry::instance()->getSharedStateManager())
1434            osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get());
1435
1436       
1437        registerPagedLODs(databaseRequest->_loadedModel.get(), frameStamp.getFrameNumber());
1438       
1439        osg::ref_ptr<osg::Group> group = databaseRequest->_groupForAddingLoadedSubgraph.get();
1440        if (group.valid())
1441        {
1442            osg::PagedLOD* plod = dynamic_cast<osg::PagedLOD*>(group.get());
1443            if (plod)
1444            {
1445                plod->setTimeStamp(plod->getNumChildren(), timeStamp);
1446                plod->setFrameNumber(plod->getNumChildren(), frameNumber);
1447                plod->getDatabaseRequest(plod->getNumChildren()) = 0;
1448            }
1449            else
1450            {
1451                osg::ProxyNode* proxyNode = dynamic_cast<osg::ProxyNode*>(group.get());
1452                if (proxyNode)
1453                {
1454                    proxyNode->getDatabaseRequest(proxyNode->getNumChildren()) = 0;
1455                }
1456            }
1457
1458            group->addChild(databaseRequest->_loadedModel.get());
1459
1460            // osg::notify(osg::NOTICE)<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<<std::endl;
1461
1462            double timeToMerge = timeStamp-databaseRequest->_timestampFirstRequest;
1463
1464            if (timeToMerge<_minimumTimeToMergeTile) _minimumTimeToMergeTile = timeToMerge;
1465            if (timeToMerge>_maximumTimeToMergeTile) _maximumTimeToMergeTile = timeToMerge;
1466
1467            _totalTimeToMergeTiles += timeToMerge;
1468            ++_numTilesMerges;
1469        }
1470               
1471        // reset the loadedModel pointer
1472        databaseRequest->_loadedModel = 0;
1473
1474        // osg::notify(osg::NOTICE)<<"curr = "<<timeToMerge<<" min "<<getMinimumTimeToMergeTile()*1000.0<<" max = "<<getMaximumTimeToMergeTile()*1000.0<<" average = "<<getAverageTimToMergeTiles()*1000.0<<std::endl;
1475    }
1476
1477    osg::Timer_t last = osg::Timer::instance()->tick();
1478
1479    osg::notify(osg::DEBUG_INFO)<<"Done DatabasePager::addLoadedDataToSceneGraph"<<
1480        osg::Timer::instance()->delta_m(before,mid)<<"ms,\t"<<
1481        osg::Timer::instance()->delta_m(mid,last)<<"ms"<<
1482        "  objects"<<localFileLoadedList.size()<<std::endl<<std::endl;
1483   
1484}
1485
1486class DatabasePager::MarkPagedLODsVisitor : public osg::NodeVisitor
1487{
1488public:
1489    MarkPagedLODsVisitor(const std::string& marker):
1490        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1491        _marker(marker),
1492        _numPagedLODsMarked(0)
1493    {
1494    }
1495
1496    META_NodeVisitor("osgDB","FindCompileableGLObjectsVisitor")
1497
1498    virtual void apply(osg::PagedLOD& plod)
1499    {
1500        if (plod.getName()!=_marker)
1501        {
1502            ++_numPagedLODsMarked;
1503            plod.setName(_marker);
1504   
1505            traverse(plod);
1506        }
1507    }
1508   
1509    std::string _marker;
1510    int _numPagedLODsMarked;
1511};
1512
1513void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1514{
1515    if (_targetMaximumNumberOfPageLOD>0)
1516    {
1517        capped_removeExpiredSubgraphs(frameStamp);
1518    }
1519    else
1520    {
1521        expiry_removeExpiredSubgraphs(frameStamp);
1522    }
1523}
1524
1525void DatabasePager::capped_removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1526{
1527    static double s_total_iter_stage_a = 0.0;
1528    static double s_total_time_stage_a = 0.0;
1529    static double s_total_max_stage_a = 0.0;
1530   
1531    static double s_total_iter_stage_b = 0.0;
1532    static double s_total_time_stage_b = 0.0;
1533    static double s_total_max_stage_b = 0.0;
1534
1535    static double s_total_iter_stage_c = 0.0;
1536    static double s_total_time_stage_c = 0.0;
1537    static double s_total_max_stage_c = 0.0;
1538
1539    osg::Timer_t startTick = osg::Timer::instance()->tick();
1540
1541
1542    unsigned int numPagedLODs = _activePagedLODList.size() + _inactivePagedLODList.size();
1543   
1544
1545    PagedLODList::iterator itr = _activePagedLODList.begin();
1546    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1547        itr != _activePagedLODList.end();
1548        )
1549    {
1550        osg::PagedLOD* plod = itr->get();
1551       
1552        int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
1553        if (delta>1)
1554        {
1555            if (_releaseDelay!=DBL_MAX)
1556            {
1557                plod->releaseGLObjects();
1558                osg::notify(osg::NOTICE)<<"DatabasePager::removeExpiredSubgraphs(), releasing gl objects"<<std::endl;
1559            }
1560
1561            _inactivePagedLODList.push_back(plod);
1562           
1563            itr = _activePagedLODList.erase(itr);
1564        }
1565        else
1566        {
1567            ++itr;
1568        }
1569    }
1570
1571    for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1572        itr != _inactivePagedLODList.end();
1573        )
1574    {
1575        osg::PagedLOD* plod = itr->get();
1576       
1577        int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
1578        if (delta>1)
1579        {
1580            ++itr;
1581        }
1582        else
1583        {
1584            _activePagedLODList.push_back(plod);
1585           
1586            itr = _inactivePagedLODList.erase(itr);
1587        }
1588    }
1589
1590    int inactivePLOD = _inactivePagedLODList.size();
1591
1592   
1593    osg::Timer_t end_a_Tick = osg::Timer::instance()->tick();
1594    double time_a = osg::Timer::instance()->delta_m(startTick,end_a_Tick);
1595
1596    s_total_iter_stage_a += 1.0;
1597    s_total_time_stage_a += time_a;
1598    if (s_total_max_stage_a<time_a) s_total_max_stage_a = time_a;
1599   
1600
1601    if (numPagedLODs <= _targetMaximumNumberOfPageLOD)
1602    {
1603        // nothing to do
1604        return;
1605    }
1606   
1607    int numToPrune = numPagedLODs - _targetMaximumNumberOfPageLOD;
1608    if (numToPrune > inactivePLOD)
1609    {
1610        numToPrune = inactivePLOD;
1611    }
1612
1613
1614    osg::NodeList childrenRemoved;
1615   
1616    double expiryTime = frameStamp.getReferenceTime() - 0.1;
1617    int expiryFrame = frameStamp.getFrameNumber() - 1;
1618
1619    MarkPagedLODsVisitor markerVistor("NeedToRemove");
1620
1621    for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1622        itr!=_inactivePagedLODList.end() && markerVistor._numPagedLODsMarked<numToPrune;
1623        ++itr)
1624    {
1625        osg::PagedLOD* plod = itr->get();
1626
1627        osg::NodeList localChildrenRemoved;
1628        plod->removeExpiredChildren(expiryTime, expiryFrame, localChildrenRemoved);
1629        if (!localChildrenRemoved.empty())
1630        {
1631            for(osg::NodeList::iterator critr = localChildrenRemoved.begin();
1632                critr!=localChildrenRemoved.end();
1633                ++critr)
1634            {
1635                (*critr)->accept(markerVistor);
1636            }
1637           
1638            std::copy(localChildrenRemoved.begin(),localChildrenRemoved.end(),std::back_inserter(childrenRemoved));
1639        }
1640    }
1641   
1642    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1643        itr!=_activePagedLODList.end() && markerVistor._numPagedLODsMarked<numToPrune;
1644        ++itr)
1645    {
1646        osg::PagedLOD* plod = itr->get();
1647
1648        osg::NodeList localChildrenRemoved;
1649        plod->removeExpiredChildren(expiryTime, expiryFrame, localChildrenRemoved);
1650        if (!localChildrenRemoved.empty())
1651        {
1652            for(osg::NodeList::iterator critr = localChildrenRemoved.begin();
1653                critr!=localChildrenRemoved.end();
1654                ++critr)
1655            {
1656                (*critr)->accept(markerVistor);
1657            }
1658           
1659            std::copy(localChildrenRemoved.begin(),localChildrenRemoved.end(),std::back_inserter(childrenRemoved));
1660        }
1661    }
1662   
1663    osg::Timer_t end_b_Tick = osg::Timer::instance()->tick();
1664    double time_b = osg::Timer::instance()->delta_m(end_a_Tick,end_b_Tick);
1665
1666    s_total_iter_stage_b += 1.0;
1667    s_total_time_stage_b += time_b;
1668    if (s_total_max_stage_b<time_b) s_total_max_stage_b = time_b;
1669
1670
1671
1672    //osg::notify(osg::NOTICE)<<"numToPrune "<<numToPrune<< " markerVistor._numPagedLODsMarked="<<markerVistor._numPagedLODsMarked<< " childrenRemoved.size()="<<childrenRemoved.size()<<std::endl;
1673
1674    if (!childrenRemoved.empty())
1675    {
1676        bool updateBlock = false;
1677
1678        // pass the objects across to the database pager delete list
1679        if (_deleteRemovedSubgraphsInDatabaseThread)
1680        {
1681            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_childrenToDeleteListMutex);
1682            for (osg::NodeList::iterator critr = childrenRemoved.begin();
1683                 critr!=childrenRemoved.end();
1684                 ++critr)
1685            {
1686                _fileRequestQueue->_childrenToDeleteList.push_back(critr->get());
1687            }
1688           
1689            updateBlock = true;
1690
1691        }
1692
1693        int numRemoved = 0;
1694        int numToRemove = markerVistor._numPagedLODsMarked;
1695       
1696       
1697        //osg::notify(osg::NOTICE)<<"Children to remove "<<childrenRemoved.size()<<" numToRemove="<<numToRemove<<std::endl;
1698
1699        // osg::notify(osg::NOTICE)<<"   time 2 "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
1700        int numSkipped = 0;
1701        for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1702            itr!=_inactivePagedLODList.end() && numRemoved<numToRemove;
1703            )
1704        {
1705            osg::PagedLOD* plod = itr->get();
1706            if (plod && plod->getName() != markerVistor._marker)
1707            {
1708                ++itr;
1709               
1710                ++numSkipped;
1711               
1712                // osg::notify(osg::NOTICE)<<"skipping"<<std::endl;
1713            }
1714            else
1715            {
1716                // osg::notify(osg::NOTICE)<<"removing"<<std::endl;
1717
1718                ++numRemoved;
1719
1720                itr = _inactivePagedLODList.erase(itr);
1721            }
1722        }
1723
1724        osg::notify(osg::INFO)<<"Number of PagedLODs skipped="<<numSkipped<<" removed "<<numRemoved<<std::endl;
1725
1726
1727        childrenRemoved.clear();
1728
1729
1730        if (updateBlock)
1731        {
1732            _fileRequestQueue->updateBlock();
1733        }
1734    }
1735   
1736    osg::Timer_t end_c_Tick = osg::Timer::instance()->tick();
1737    double time_c = osg::Timer::instance()->delta_m(end_b_Tick,end_c_Tick);
1738
1739    s_total_iter_stage_c += 1.0;
1740    s_total_time_stage_c += time_c;
1741    if (s_total_max_stage_c<time_c) s_total_max_stage_c = time_c;
1742
1743
1744
1745    osg::notify(osg::INFO)<<"active="<<_activePagedLODList.size()<<" inactive="<<_inactivePagedLODList.size()<<" overall = "<<osg::Timer::instance()->delta_m(startTick,end_c_Tick)<<
1746                              " A="<<time_a<<" avg="<<s_total_time_stage_a/s_total_iter_stage_a<<" max = "<<s_total_max_stage_a<<
1747                              " B="<<time_b<<" avg="<<s_total_time_stage_b/s_total_iter_stage_b<<" max = "<<s_total_max_stage_b<<
1748                              " C="<<time_c<<" avg="<<s_total_time_stage_c/s_total_iter_stage_c<<" max = "<<s_total_max_stage_c<<std::endl;
1749
1750   
1751    if (osgDB::Registry::instance()->getSharedStateManager())
1752        osgDB::Registry::instance()->getSharedStateManager()->prune();
1753
1754    // update the Registry object cache.
1755    osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime());
1756    osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime);
1757}
1758
1759void DatabasePager::expiry_removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1760{
1761//    osg::notify(osg::NOTICE)<<"DatabasePager::new_removeExpiredSubgraphs()"<<std::endl;
1762
1763    static double s_total_iter = 0.0;
1764    static double s_total_time = 0.0;
1765    static double s_total_max = 0.0;
1766   
1767    osg::Timer_t startTick = osg::Timer::instance()->tick();
1768
1769    double expiryTime = frameStamp.getReferenceTime() - _expiryDelay;
1770    int expiryFrame = frameStamp.getFrameNumber() - _expiryFrames;
1771
1772    double releaseTime = frameStamp.getReferenceTime() - _releaseDelay;
1773    int releaseFrame = frameStamp.getFrameNumber() - _releaseFrames;
1774
1775    osg::NodeList childrenRemoved;
1776   
1777    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1778        itr!=_activePagedLODList.end();
1779        ++itr)
1780    {
1781        osg::PagedLOD* plod = itr->get();
1782       
1783       
1784        if (_releaseDelay!=DBL_MAX && plod->releaseGLObjectsOnExpiredChildren(releaseTime, releaseFrame))
1785        {
1786            osg::notify(osg::INFO)<<"DatabasePager::removeExpiredSubgraphs(), releasing gl objects"<<std::endl;
1787        }
1788       
1789        plod->removeExpiredChildren(expiryTime, expiryFrame, childrenRemoved);
1790    }
1791   
1792    if (!childrenRemoved.empty())
1793    {
1794        MarkPagedLODsVisitor markerVistor("NeedToRemove");
1795        for(osg::NodeList::iterator critr = childrenRemoved.begin();
1796            critr!=childrenRemoved.end();
1797            ++critr)
1798        {
1799            (*critr)->accept(markerVistor);
1800        }   
1801   
1802        // osg::notify(osg::NOTICE)<<"Children to remove "<<childrenRemoved.size()<<std::endl;
1803   
1804        // pass the objects across to the database pager delete list
1805        if (_deleteRemovedSubgraphsInDatabaseThread)
1806        {
1807            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_childrenToDeleteListMutex);
1808            for (osg::NodeList::iterator critr = childrenRemoved.begin();
1809                 critr!=childrenRemoved.end();
1810                 ++critr)
1811            {
1812                _fileRequestQueue->_childrenToDeleteList.push_back(critr->get());
1813            }
1814
1815            _fileRequestQueue->updateBlock();
1816        }
1817
1818        // osg::notify(osg::NOTICE)<<"   time 2 "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
1819        for(PagedLODList::iterator itr = _activePagedLODList.begin();
1820            itr!=_activePagedLODList.end();
1821            )
1822        {
1823            osg::PagedLOD* plod = itr->get();
1824            if (plod && plod->getName() != markerVistor._marker)
1825            {
1826                ++itr;
1827            }
1828            else
1829            {
1830                PagedLODList::iterator itr_to_erase = itr;
1831                ++itr;
1832
1833                _activePagedLODList.erase(itr_to_erase);           
1834            }
1835        }
1836
1837        childrenRemoved.clear();
1838
1839
1840    }
1841
1842    osg::Timer_t endTick = osg::Timer::instance()->tick();
1843    double time = osg::Timer::instance()->delta_m(startTick,endTick);
1844
1845    s_total_iter += 1.0;
1846    s_total_time += time;
1847    if (s_total_max<time) s_total_max = time;
1848
1849    osg::notify(osg::INFO)<<"_activePagedLODList.size()="<<_activePagedLODList.size()<<" overall = "<<time<<
1850                              " avg="<<s_total_time/s_total_iter<<" max = "<<s_total_max<<std::endl;
1851     
1852   
1853    if (osgDB::Registry::instance()->getSharedStateManager())
1854        osgDB::Registry::instance()->getSharedStateManager()->prune();
1855
1856    // update the Registry object cache.
1857    osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime());
1858    osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime);
1859
1860
1861}
1862
1863class DatabasePager::FindPagedLODsVisitor : public osg::NodeVisitor
1864{
1865public:
1866
1867    FindPagedLODsVisitor(DatabasePager::PagedLODList& pagedLODList, int frameNumber):
1868        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1869        _activePagedLODList(pagedLODList),
1870        _frameNumber(frameNumber)
1871    {
1872    }
1873   
1874    META_NodeVisitor("osgDB","FindPagedLODsVisitor")
1875
1876    virtual void apply(osg::PagedLOD& plod)
1877    {
1878        plod.setFrameNumberOfLastTraversal(_frameNumber);
1879       
1880        _activePagedLODList.push_back(&plod);
1881   
1882        traverse(plod);
1883    }
1884   
1885    DatabasePager::PagedLODList& _activePagedLODList;
1886    int _frameNumber;
1887       
1888protected:
1889   
1890    FindPagedLODsVisitor& operator = (const FindPagedLODsVisitor&) { return *this; }
1891};
1892
1893void DatabasePager::registerPagedLODs(osg::Node* subgraph, int frameNumber)
1894{
1895    if (!subgraph) return;
1896   
1897    FindPagedLODsVisitor fplv(_activePagedLODList, frameNumber);
1898    subgraph->accept(fplv);
1899}
1900
1901bool DatabasePager::requiresCompileGLObjects() const
1902{
1903    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
1904    return !_dataToCompileList->_requestList.empty();
1905}
1906
1907void DatabasePager::setCompileGLObjectsForContextID(unsigned int contextID, bool on)
1908{
1909    if (on)
1910    {
1911        _activeGraphicsContexts.insert(contextID);
1912    }
1913    else
1914    {
1915        _activeGraphicsContexts.erase(contextID);
1916    }
1917}
1918
1919bool DatabasePager::getCompileGLObjectsForContextID(unsigned int contextID)
1920{
1921    return _activeGraphicsContexts.count(contextID)!=0;
1922}
1923
1924
1925DatabasePager::CompileOperation::CompileOperation(osgDB::DatabasePager* databasePager):
1926    osg::GraphicsOperation("DatabasePager::CompileOperation",false),
1927    _databasePager(databasePager)
1928{
1929}
1930
1931void DatabasePager::CompileOperation::operator () (osg::GraphicsContext* context)
1932{
1933    // osg::notify(osg::NOTICE)<<"Background thread compiling"<<std::endl;
1934
1935    if (_databasePager.valid()) _databasePager->compileAllGLObjects(*(context->getState()));
1936   
1937}
1938
1939bool DatabasePager::requiresExternalCompileGLObjects(unsigned int contextID) const
1940{
1941    if (_activeGraphicsContexts.count(contextID)==0) return false;
1942
1943    return osg::GraphicsContext::getCompileContext(contextID)==0;
1944}
1945
1946void DatabasePager::compileAllGLObjects(osg::State& state)
1947{
1948    double availableTime = DBL_MAX;
1949    compileGLObjects(state, availableTime);
1950}
1951
1952void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
1953{
1954    // osg::notify(osg::NOTICE)<<"DatabasePager::compileGLObjects "<<_frameNumber<<std::endl;
1955
1956    bool compileAll = (availableTime==DBL_MAX);
1957
1958    SharedStateManager *sharedManager
1959        = Registry::instance()->getSharedStateManager();
1960    osg::RenderInfo renderInfo;
1961    renderInfo.setState(&state);
1962
1963    if (availableTime>0.0)
1964    {
1965
1966        const osg::Timer& timer = *osg::Timer::instance();
1967        osg::Timer_t start_tick = timer.tick();
1968        double elapsedTime = 0.0;
1969        double estimatedTextureDuration = 0.0001;
1970        double estimatedDrawableDuration = 0.0001;
1971
1972        osg::ref_ptr<DatabaseRequest> databaseRequest;
1973
1974        // get the first compilable entry.
1975        {
1976            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
1977       
1978            // advance to the next entry to compile if one is available.
1979            databaseRequest = _dataToCompileList->_requestList.empty() ? 0 : _dataToCompileList->_requestList.front().get();
1980        };
1981
1982        unsigned int numObjectsCompiled = 0;
1983
1984        // while there are valid databaseRequest's in the to compile list and there is
1985        // sufficient time left compile each databaseRequest's stateset and drawables.
1986        while (databaseRequest.valid() && (compileAll || (elapsedTime<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)) )
1987        {
1988            DataToCompileMap& dcm = databaseRequest->_dataToCompileMap;
1989            DataToCompile& dtc = dcm[state.getContextID()];
1990            if (!dtc.first.empty() && (elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)
1991            {
1992
1993                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
1994
1995                // we have StateSet's to compile
1996                StateSetList& sslist = dtc.first;
1997                //osg::notify(osg::INFO)<<"Compiling statesets"<<std::endl;
1998                StateSetList::iterator itr=sslist.begin();
1999                unsigned int objTemp = numObjectsCompiled;
2000                for(;
2001                    itr!=sslist.end() && (compileAll || ((elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
2002                    ++itr)
2003                {
2004                    //osg::notify(osg::INFO)<<"    Compiling stateset "<<(*itr).get()<<std::endl;
2005                    if (isCompiled(itr->get(), state.getContextID())
2006                        || (sharedManager && sharedManager->isShared(itr->get())))
2007                    {
2008                        elapsedTime = timer.delta_s(start_tick,timer.tick());
2009                        continue;
2010                    }
2011                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
2012
2013                    (*itr)->compileGLObjects(state);
2014
2015                    GLint p;
2016                    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p);
2017
2018                    elapsedTime = timer.delta_s(start_tick,timer.tick());
2019
2020
2021                    // estimate the duration of the compile based on current compile duration.
2022                    estimatedTextureDuration = (elapsedTime-startCompileTime);
2023
2024                    ++numObjectsCompiled;
2025                }
2026                if (osg::getNotifyLevel() >= osg::DEBUG_INFO
2027                    && numObjectsCompiled > objTemp)
2028                    osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
2029                                                << numObjectsCompiled - objTemp
2030                                                << " StateSets" << std::endl;
2031                // remove the compiled statesets from the list.
2032                sslist.erase(sslist.begin(),itr);
2033            }
2034
2035            if (!dtc.second.empty() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)))
2036            {
2037                // we have Drawable's to compile
2038                //osg::notify(osg::INFO)<<"Compiling drawables"<<std::endl;
2039                DrawableList& dwlist = dtc.second;
2040                DrawableList::iterator itr=dwlist.begin();
2041                unsigned int objTemp = numObjectsCompiled;
2042                for(;
2043                    itr!=dwlist.end() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
2044                    ++itr)
2045                {
2046                    //osg::notify(osg::INFO)<<"    Compiling drawable "<<(*itr).get()<<std::endl;
2047                    if (isCompiled(itr->get(), state.getContextID()))
2048                    {
2049                        elapsedTime = timer.delta_s(start_tick,timer.tick());
2050                        continue;
2051                    }
2052                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
2053                    (*itr)->compileGLObjects(renderInfo);
2054                    elapsedTime = timer.delta_s(start_tick,timer.tick());
2055
2056                    // estimate the duration of the compile based on current compile duration.
2057                    estimatedDrawableDuration = (elapsedTime-startCompileTime);
2058
2059                    ++numObjectsCompiled;
2060
2061                }
2062                if (osg::getNotifyLevel() >= osg::DEBUG_INFO
2063                    && numObjectsCompiled > objTemp)
2064                    osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
2065                                                << numObjectsCompiled - objTemp
2066                                                << " Drawables" << std::endl;
2067                // remove the compiled drawables from the list.
2068                dwlist.erase(dwlist.begin(),itr);
2069            }
2070
2071            //osg::notify(osg::INFO)<<"Checking if compiled"<<std::endl;
2072
2073            // now check the to compile entries for all active graphics contexts
2074            // to make sure that all have been compiled. They won't be
2075            // if we ran out of time or if another thread is still
2076            // compiling for its graphics context.
2077            bool allCompiled = true;
2078            for(DataToCompileMap::iterator itr=dcm.begin();
2079                itr!=dcm.end() && allCompiled;
2080                ++itr)
2081            {
2082                if (!(itr->second.first.empty())) allCompiled=false;
2083                if (!(itr->second.second.empty())) allCompiled=false;
2084            }
2085
2086            //if (numObjectsCompiled > 0)
2087            //osg::notify(osg::NOTICE)<< _frameNumber << "compiled " << numObjectsCompiled << " objects" << std::endl;
2088           
2089            if (allCompiled)
2090            {
2091                // we've compiled all of the current databaseRequest so we can now pop it off the
2092                // to compile list and place it on the merge list.
2093                // osg::notify(osg::NOTICE)<<"All compiled"<<std::endl;
2094
2095
2096                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
2097
2098                // The request might have been removed from the
2099                // _dataToCompile list by another graphics thread, in
2100                // which case it's already on the merge list, or by
2101                // the pager, which means that the request has
2102                // expired. Also, the compile list might have been
2103                // shuffled by the pager, so the current request is
2104                // not guaranteed to still be at the beginning of the
2105                // list.
2106               
2107                RequestQueue::RequestList::iterator requestIter
2108                    = std::find(_dataToCompileList->_requestList.begin(), _dataToCompileList->_requestList.end(),
2109                           databaseRequest);
2110                if (requestIter != _dataToCompileList->_requestList.end())
2111                {
2112                    {
2113                        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
2114                        databaseRequest->_requestQueue = _dataToMergeList.get();
2115                        _dataToMergeList->_requestList.push_back(databaseRequest);
2116                    }
2117                    _dataToCompileList->_requestList.erase(requestIter);
2118                }
2119               
2120                if (!_dataToCompileList->_requestList.empty()) databaseRequest = _dataToCompileList->_requestList.front();
2121                else databaseRequest = 0;
2122
2123            }
2124            else 
2125            {
2126                // osg::notify(osg::NOTICE)<<"Not all compiled"<<std::endl;
2127                databaseRequest = 0;
2128            }
2129
2130            elapsedTime = timer.delta_s(start_tick,timer.tick());
2131        }
2132
2133        availableTime -= elapsedTime;
2134
2135        //osg::notify(osg::NOTICE)<<"elapsedTime="<<elapsedTime<<"\ttime remaining ="<<availableTime<<"\tnumObjectsCompiled = "<<numObjectsCompiled<<std::endl;
2136        //osg::notify(osg::NOTICE)<<"estimatedTextureDuration="<<estimatedTextureDuration;
2137        //osg::notify(osg::NOTICE)<<"\testimatedDrawableDuration="<<estimatedDrawableDuration<<std::endl;
2138    }
2139    else
2140    {
2141        availableTime = 0.0f;
2142    }
2143}
Note: See TracBrowser for help on using the browser.