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

Revision 10174, 77.8 kB (checked in by robert, 6 years ago)

Moved Registry::ReadFileCallback? + WriteFileCallback?, and osgDB::ReaderWriter::Options into their own separate Options file and into the osgDB namespace.

Introduced a new callback osgDB::FindFileCallback? that overrides the default behavior of findDataFile/findLibraryFile.

Introduced support for assigning ReaderWriter::Options directory to PagedLOD.

Introduced new osgDB::FileLocationCallback? for assistancing the DatabasePager? to know when a file is hosted on a local or remote file system.

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