root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osgDB/DatabasePager.cpp @ 10151

Revision 10151, 76.8 kB (checked in by robert, 5 years ago)

From Stephan Huber, "while debugging a problem in finding plugins on OS X I discovered, that
the conditional directives for setting the prepend-string in
createLibraryNameForExtension were not in effect, because of the mixture
of different #ifdef styles.

I removed the conditional part for APPLE completely to be more
standard-conform with other platforms (plugins should be located in
osgPlugins-X.X.X/). Because of the wrong syntax of the conditional
compile the old code was not used anyway -- so no functional change.
"

Merged from svn/trunk using:

svn merge -r 10149:10150 http://www.openscenegraph.org/svn/osg/OpenSceneGraph/trunk/src/osgDB

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