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

Revision 10415, 78.0 kB (checked in by robert, 5 years ago)

From Mathias Froehlich, "We are currently getting issues with locale settings and some osg plugins.
Therefore I have changed all the occurances of atof by asciiToFloat or
asciiToDouble.

I believe that it is safe to do so at least for all the plugins.
Included here are also asciiToFloat conversion of environment variables. One
might argue that these should be locale dependent. But IMO these should be
set and interpreted by osg independent of the current locale.
"

  • 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    _changeAutoUnRef = true;
892    _valueAutoUnRef = false;
893 
894    _changeAnisotropy = false;
895    _valueAnisotropy = 1.0f;
896
897    const char* ptr=0;
898
899    _deleteRemovedSubgraphsInDatabaseThread = true;
900    if( (ptr = getenv("OSG_DELETE_IN_DATABASE_THREAD")) != 0)
901    {
902        _deleteRemovedSubgraphsInDatabaseThread = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
903                        strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
904
905    }
906
907    _expiryDelay = 10.0;
908    if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0)
909    {
910        _expiryDelay = osg::asciiToDouble(ptr);
911        osg::notify(osg::NOTICE)<<"Expiry delay = "<<_expiryDelay<<std::endl;
912    }
913
914    _expiryFrames = 1; // Last frame will not be expired
915    if( (ptr = getenv("OSG_EXPIRY_FRAMES")) != 0)
916    {
917        _expiryFrames = atoi(ptr);
918        osg::notify(osg::NOTICE)<<"Expiry frames = "<<_expiryFrames<<std::endl;
919    }
920
921    if( (ptr = getenv("OSG_RELEASE_DELAY")) != 0)
922    {
923        if (strcmp(ptr,"OFF")==0 || strcmp(ptr,"Off")==0  || strcmp(ptr,"off")==0)
924        {
925            setReleaseDelay(DBL_MAX);
926        }
927        else
928        {
929            setReleaseDelay(osg::asciiToDouble(ptr));
930        }
931           
932        osg::notify(osg::NOTICE)<<"Release delay = "<<_releaseDelay<<std::endl;
933    }
934    else
935    {
936        setReleaseDelay(DBL_MAX);
937    }
938   
939
940    _releaseFrames = 1; // Last frame will not be release
941    if( (ptr = getenv("OSG_RELEASE_FRAMES")) != 0)
942    {
943        _releaseFrames = atoi(ptr);
944        osg::notify(osg::NOTICE)<<"Release frames = "<<_releaseFrames<<std::endl;
945    }
946
947
948    _targetMaximumNumberOfPageLOD = 300;
949    if( (ptr = getenv("OSG_MAX_PAGEDLOD")) != 0)
950    {
951        _targetMaximumNumberOfPageLOD = atoi(ptr);
952        osg::notify(osg::NOTICE)<<"_targetMaximumNumberOfPageLOD = "<<_targetMaximumNumberOfPageLOD<<std::endl;
953    }
954
955
956    _doPreCompile = false;
957    if( (ptr = getenv("OSG_DO_PRE_COMPILE")) != 0)
958    {
959        _doPreCompile = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 ||
960                        strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0;
961    }
962
963    _targetFrameRate = 100.0;
964    _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms.
965    _maximumNumOfObjectsToCompilePerFrame = 4;
966    if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0)
967    {
968        _minimumTimeAvailableForGLCompileAndDeletePerFrame = osg::asciiToDouble(ptr);
969    }
970
971    if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0)
972    {
973        _maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
974    }
975
976    // initialize the stats variables
977    resetStats();
978
979    // make sure a SharedStateManager exists.
980    //osgDB::Registry::instance()->getOrCreateSharedStateManager();
981   
982    //if (osgDB::Registry::instance()->getSharedStateManager())
983        //osgDB::Registry::instance()->setUseObjectCacheHint(true);
984       
985    _fileRequestQueue = new ReadQueue(this,"fileRequestQueue");
986    _httpRequestQueue = new ReadQueue(this,"httpRequestQueue");
987   
988    _dataToCompileList = new RequestQueue;
989    _dataToMergeList = new RequestQueue;
990   
991    setUpThreads(
992        osg::DisplaySettings::instance()->getNumOfDatabaseThreadsHint(),
993        osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint());
994
995}
996
997DatabasePager::DatabasePager(const DatabasePager& rhs)
998{
999    //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<<std::endl;
1000   
1001    _startThreadCalled = false;
1002
1003    _done = false;
1004    _acceptNewRequests = true;
1005    _databasePagerThreadPaused = false;
1006   
1007    _numFramesActive = 0;
1008    _frameNumber = 0;
1009
1010    _drawablePolicy = rhs._drawablePolicy;
1011
1012    _changeAutoUnRef = rhs._changeAutoUnRef;
1013    _valueAutoUnRef = rhs._valueAutoUnRef;
1014    _changeAnisotropy = rhs._changeAnisotropy;
1015    _valueAnisotropy = rhs._valueAnisotropy;
1016
1017
1018    _deleteRemovedSubgraphsInDatabaseThread = rhs._deleteRemovedSubgraphsInDatabaseThread;
1019   
1020    _expiryDelay = rhs._expiryDelay;
1021    _expiryFrames = rhs._expiryFrames;
1022
1023    _releaseDelay = rhs._releaseDelay;
1024    _releaseFrames = rhs._releaseFrames;
1025
1026    _targetMaximumNumberOfPageLOD = rhs._targetMaximumNumberOfPageLOD;
1027
1028    _doPreCompile = rhs._doPreCompile;
1029    _targetFrameRate = rhs._targetFrameRate;
1030    _minimumTimeAvailableForGLCompileAndDeletePerFrame = rhs._minimumTimeAvailableForGLCompileAndDeletePerFrame;
1031    _maximumNumOfObjectsToCompilePerFrame = rhs._maximumNumOfObjectsToCompilePerFrame;
1032
1033    _fileRequestQueue = new ReadQueue(this,"fileRequestQueue");
1034    _httpRequestQueue = new ReadQueue(this,"httpRequestQueue");
1035   
1036    _dataToCompileList = new RequestQueue;
1037    _dataToMergeList = new RequestQueue;
1038
1039    for(DatabaseThreadList::const_iterator dt_itr = rhs._databaseThreads.begin();
1040        dt_itr != rhs._databaseThreads.end();
1041        ++dt_itr)
1042    {
1043        _databaseThreads.push_back(new DatabaseThread(**dt_itr,this));
1044    }
1045
1046    // initialize the stats variables
1047    resetStats();
1048}
1049
1050
1051DatabasePager::~DatabasePager()
1052{
1053    cancel();
1054}
1055
1056osg::ref_ptr<DatabasePager>& DatabasePager::prototype()
1057{
1058    static osg::ref_ptr<DatabasePager> s_DatabasePager = new DatabasePager;
1059    return s_DatabasePager;
1060}
1061
1062DatabasePager* DatabasePager::create()
1063{
1064    return DatabasePager::prototype().valid() ?
1065           DatabasePager::prototype()->clone() :
1066           new DatabasePager;
1067}
1068
1069void DatabasePager::setUpThreads(unsigned int totalNumThreads, unsigned int numHttpThreads)
1070{
1071    _databaseThreads.clear();
1072   
1073    unsigned int numGeneralThreads = numHttpThreads < totalNumThreads ?
1074        totalNumThreads - numHttpThreads :
1075        1;
1076   
1077    if (numHttpThreads==0)
1078    {
1079        for(unsigned int i=0; i<numGeneralThreads; ++i)
1080        {
1081            addDatabaseThread(DatabaseThread::HANDLE_ALL_REQUESTS,"HANDLE_ALL_REQUESTS");
1082        }
1083    }
1084    else
1085    {
1086        for(unsigned int i=0; i<numGeneralThreads; ++i)
1087        {
1088            addDatabaseThread(DatabaseThread::HANDLE_NON_HTTP, "HANDLE_NON_HTTP");
1089        }
1090
1091        for(unsigned int i=0; i<numHttpThreads; ++i)
1092        {
1093            addDatabaseThread(DatabaseThread::HANDLE_ONLY_HTTP, "HANDLE_ONLY_HTTP");
1094        }
1095    }   
1096}
1097
1098unsigned int DatabasePager::addDatabaseThread(DatabaseThread::Mode mode, const std::string& name)
1099{
1100    osg::notify(osg::INFO)<<"DatabasePager::addDatabaseThread() "<<name<<std::endl;
1101
1102    unsigned int pos = _databaseThreads.size();
1103   
1104    DatabaseThread* thread = new DatabaseThread(this, mode,name);
1105    _databaseThreads.push_back(thread);
1106   
1107    if (_startThreadCalled)
1108    {
1109        osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl;
1110        thread->startThread();
1111    }
1112   
1113    return pos;
1114}
1115
1116void DatabasePager::setReleaseDelay(double releaseDelay)
1117{
1118    _releaseDelay = releaseDelay;
1119
1120    if (_releaseDelay==DBL_MAX)
1121    {
1122        _changeAutoUnRef = true;
1123        _valueAutoUnRef = true;
1124    }
1125    else
1126    {
1127        // when GLObject release is used make sure Images aren't unref'd as they may be needed later.
1128        _changeAutoUnRef = true;
1129        _valueAutoUnRef = false;
1130    }
1131}
1132
1133int DatabasePager::setSchedulePriority(OpenThreads::Thread::ThreadPriority priority)
1134{
1135    int result = 0;
1136    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1137        dt_itr != _databaseThreads.end();
1138        ++dt_itr)
1139    {
1140        result = (*dt_itr)->setSchedulePriority(priority);
1141    }
1142    return result;
1143}
1144
1145bool DatabasePager::isRunning() const
1146{
1147    for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin();
1148        dt_itr != _databaseThreads.end();
1149        ++dt_itr)
1150    {
1151        if ((*dt_itr)->isRunning()) return true;
1152    }
1153   
1154    return false;
1155}
1156
1157int DatabasePager::cancel()
1158{
1159    int result = 0;
1160
1161    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1162        dt_itr != _databaseThreads.end();
1163        ++dt_itr)
1164    {
1165        (*dt_itr)->setDone(true);
1166    }
1167
1168    // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
1169    _fileRequestQueue->release();
1170    _httpRequestQueue->release();
1171
1172    for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
1173        dt_itr != _databaseThreads.end();
1174        ++dt_itr)
1175    {
1176        (*dt_itr)->cancel();
1177    }
1178
1179    _done = true;
1180    _startThreadCalled = false;
1181
1182    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
1183    return result;
1184}
1185
1186void DatabasePager::clear()
1187{
1188    _fileRequestQueue->clear();
1189    _httpRequestQueue->clear();
1190       
1191    {
1192        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
1193        for(RequestQueue::RequestList::iterator citr = _dataToCompileList->_requestList.begin();
1194            citr != _dataToCompileList->_requestList.end();
1195            ++citr)
1196        {
1197            (*citr)->_loadedModel = 0;
1198            (*citr)->_requestQueue = 0;
1199        }
1200        _dataToCompileList->_requestList.clear();
1201    }
1202
1203    {
1204        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1205        for(RequestQueue::RequestList::iterator citr = _dataToMergeList->_requestList.begin();
1206            citr != _dataToMergeList->_requestList.end();
1207            ++citr)
1208        {
1209            (*citr)->_loadedModel = 0;
1210            (*citr)->_requestQueue = 0;
1211        }
1212        _dataToMergeList->_requestList.clear();
1213    }
1214
1215    // note, no need to use a mutex as the list is only accessed from the update thread.
1216    _activePagedLODList.clear();
1217    _inactivePagedLODList.clear();
1218
1219    // ??
1220    // _activeGraphicsContexts
1221}
1222
1223void DatabasePager::resetStats()
1224{
1225    // initialize the stats variables
1226    _minimumTimeToMergeTile = DBL_MAX;
1227    _maximumTimeToMergeTile = -DBL_MAX;
1228    _totalTimeToMergeTiles = 0.0;
1229    _numTilesMerges = 0;
1230}
1231
1232bool DatabasePager::getRequestsInProgress() const
1233{
1234    if (getFileRequestListSize()>0) return true;
1235
1236    if (getDataToCompileListSize()>0)
1237    {
1238        return true;
1239    }
1240
1241    if (getDataToMergeListSize()>0) return true;
1242
1243    for(DatabaseThreadList::const_iterator itr = _databaseThreads.begin();
1244        itr != _databaseThreads.end();
1245        ++itr)
1246    {
1247        if ((*itr)->getActive()) return true;
1248    }
1249    return false;
1250}
1251
1252
1253void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group,
1254                                    float priority, const osg::FrameStamp* framestamp,
1255                                    osg::ref_ptr<osg::Referenced>& databaseRequestRef,
1256                                    const osg::Referenced* options)
1257{
1258    osgDB::Options* loadOptions = dynamic_cast<osgDB::Options*>(const_cast<osg::Referenced*>(options));
1259    if (!loadOptions)
1260    {
1261       loadOptions = Registry::instance()->getOptions();
1262
1263        // osg::notify(osg::NOTICE)<<"Using options from Registry "<<std::endl;
1264    }
1265    else
1266    {
1267        // osg::notify(osg::NOTICE)<<"options from requestNodeFile "<<std::endl;
1268    }
1269
1270
1271    if (!_acceptNewRequests) return;
1272   
1273    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1274
1275    double timestamp = framestamp?framestamp->getReferenceTime():0.0;
1276    int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber;
1277 
1278#ifdef WITH_REQUESTNODEFILE_TIMING
1279    static int previousFrame = -1;
1280    static double totalTime = 0.0;
1281   
1282    if (previousFrame!=frameNumber)
1283    {
1284        osg::notify(osg::NOTICE)<<"requestNodeFiles for "<<previousFrame<<" time = "<<totalTime<<std::endl;
1285
1286        previousFrame = frameNumber;
1287        totalTime = 0.0;
1288    }
1289#endif
1290   
1291    // search to see if filename already exist in the file loaded list.
1292    bool foundEntry = false;
1293
1294    if (databaseRequestRef.valid())
1295    {
1296        DatabaseRequest* databaseRequest = dynamic_cast<DatabaseRequest*>(databaseRequestRef.get());
1297        if (databaseRequest)
1298        {
1299            osg::notify(osg::INFO)<<"DatabasePager::requestNodeFile("<<fileName<<") updating already assigned."<<std::endl;
1300
1301            RequestQueue* requestQueue = databaseRequest->_requestQueue;
1302            if (requestQueue)
1303            {
1304                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(requestQueue->_requestMutex);
1305
1306                databaseRequest->_frameNumberLastRequest = frameNumber;
1307                databaseRequest->_timestampLastRequest = timestamp;
1308                databaseRequest->_priorityLastRequest = priority;
1309                ++(databaseRequest->_numOfRequests);
1310            }
1311            else
1312            {
1313                databaseRequest->_frameNumberLastRequest = frameNumber;
1314                databaseRequest->_timestampLastRequest = timestamp;
1315                databaseRequest->_priorityLastRequest = priority;
1316                ++(databaseRequest->_numOfRequests);
1317            }
1318           
1319            foundEntry = true;
1320
1321            if (databaseRequestRef->referenceCount()==1)
1322            {
1323                osg::notify(osg::INFO)<<"DatabasePager::requestNodeFile("<<fileName<<") orphaned, resubmitting."<<std::endl;
1324
1325                databaseRequest->_frameNumberFirstRequest = frameNumber;
1326                databaseRequest->_timestampFirstRequest = timestamp;
1327                databaseRequest->_priorityFirstRequest = priority;
1328                databaseRequest->_frameNumberLastRequest = frameNumber;
1329                databaseRequest->_timestampLastRequest = timestamp;
1330                databaseRequest->_priorityLastRequest = priority;
1331                databaseRequest->_groupForAddingLoadedSubgraph = group;
1332                databaseRequest->_loadOptions = loadOptions;
1333                databaseRequest->_requestQueue = _fileRequestQueue.get();
1334
1335                _fileRequestQueue->add(databaseRequest);
1336            }
1337           
1338        }
1339    }
1340
1341    if (!foundEntry)
1342    {
1343        osg::notify(osg::INFO)<<"In DatabasePager::requestNodeFile("<<fileName<<")"<<std::endl;
1344       
1345        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_requestMutex);
1346       
1347        if (!databaseRequestRef.valid() || databaseRequestRef->referenceCount()==1)
1348        {
1349            osg::ref_ptr<DatabaseRequest> databaseRequest = new DatabaseRequest;
1350
1351            databaseRequestRef = databaseRequest.get();
1352
1353            databaseRequest->_fileName = fileName;
1354            databaseRequest->_frameNumberFirstRequest = frameNumber;
1355            databaseRequest->_timestampFirstRequest = timestamp;
1356            databaseRequest->_priorityFirstRequest = priority;
1357            databaseRequest->_frameNumberLastRequest = frameNumber;
1358            databaseRequest->_timestampLastRequest = timestamp;
1359            databaseRequest->_priorityLastRequest = priority;
1360            databaseRequest->_groupForAddingLoadedSubgraph = group;
1361            databaseRequest->_loadOptions = loadOptions;
1362            databaseRequest->_requestQueue = _fileRequestQueue.get();
1363
1364            _fileRequestQueue->_requestList.push_back(databaseRequest.get());
1365
1366            _fileRequestQueue->updateBlock();
1367        }
1368       
1369    }
1370   
1371    if (!_startThreadCalled)
1372    {
1373        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
1374       
1375        if (!_startThreadCalled)
1376        {
1377            _startThreadCalled = true;
1378            _done = false;
1379            osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl;
1380           
1381            if (_databaseThreads.empty())
1382            {
1383                setUpThreads(
1384                    osg::DisplaySettings::instance()->getNumOfDatabaseThreadsHint(),
1385                    osg::DisplaySettings::instance()->getNumOfHttpDatabaseThreadsHint());
1386            }
1387
1388            for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin();
1389                dt_itr != _databaseThreads.end();
1390                ++dt_itr)
1391            {
1392                (*dt_itr)->startThread();
1393            }
1394        }
1395    }
1396
1397#ifdef WITH_REQUESTNODEFILE_TIMING
1398    totalTime += osg::Timer::instance()->delta_m(start_tick, osg::Timer::instance()->tick());
1399#endif
1400}
1401
1402void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp)
1403{
1404    if (framestamp)
1405    {
1406        //osg::notify(osg::INFO) << "signalBeginFrame "<<framestamp->getFrameNumber()<<">>>>>>>>>>>>>>>>"<<std::endl;
1407        _frameNumber = framestamp->getFrameNumber();
1408       
1409    } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<<std::endl;
1410}
1411
1412void DatabasePager::signalEndFrame()
1413{
1414    //osg::notify(osg::INFO) << "signalEndFrame <<<<<<<<<<<<<<<<<<<< "<<std::endl;
1415}
1416
1417void DatabasePager::setDatabasePagerThreadPause(bool pause)
1418{
1419    if (_databasePagerThreadPaused == pause) return;
1420   
1421    _databasePagerThreadPaused = pause;
1422    _fileRequestQueue->updateBlock();
1423    _httpRequestQueue->updateBlock();
1424}
1425
1426
1427bool DatabasePager::requiresUpdateSceneGraph() const
1428{
1429    {
1430        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1431        if (!_dataToMergeList->_requestList.empty()) return true;
1432    }
1433   
1434    return false;
1435   
1436}
1437 
1438
1439void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp)
1440{
1441    double timeStamp = frameStamp.getReferenceTime();
1442    int frameNumber = frameStamp.getFrameNumber();
1443
1444    osg::Timer_t before = osg::Timer::instance()->tick();
1445
1446    RequestQueue::RequestList localFileLoadedList;
1447
1448    // get the data for the _dataToCompileList, leaving it empty via a std::vector<>.swap.
1449    {
1450        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
1451        localFileLoadedList.swap(_dataToMergeList->_requestList);
1452    }
1453       
1454    osg::Timer_t mid = osg::Timer::instance()->tick();
1455
1456    // add the loaded data into the scene graph.
1457    for(RequestQueue::RequestList::iterator itr=localFileLoadedList.begin();
1458        itr!=localFileLoadedList.end();
1459        ++itr)
1460    {
1461        DatabaseRequest* databaseRequest = itr->get();
1462
1463        // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<<std::endl;
1464       
1465        if (osgDB::Registry::instance()->getSharedStateManager())
1466            osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get());
1467
1468       
1469        registerPagedLODs(databaseRequest->_loadedModel.get(), frameStamp.getFrameNumber());
1470       
1471        osg::ref_ptr<osg::Group> group = databaseRequest->_groupForAddingLoadedSubgraph.get();
1472        if (group.valid())
1473        {
1474            osg::PagedLOD* plod = dynamic_cast<osg::PagedLOD*>(group.get());
1475            if (plod)
1476            {
1477                plod->setTimeStamp(plod->getNumChildren(), timeStamp);
1478                plod->setFrameNumber(plod->getNumChildren(), frameNumber);
1479                plod->getDatabaseRequest(plod->getNumChildren()) = 0;
1480            }
1481            else
1482            {
1483                osg::ProxyNode* proxyNode = dynamic_cast<osg::ProxyNode*>(group.get());
1484                if (proxyNode)
1485                {
1486                    proxyNode->getDatabaseRequest(proxyNode->getNumChildren()) = 0;
1487                }
1488            }
1489
1490            group->addChild(databaseRequest->_loadedModel.get());
1491
1492            // osg::notify(osg::NOTICE)<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<<std::endl;
1493
1494            double timeToMerge = timeStamp-databaseRequest->_timestampFirstRequest;
1495
1496            if (timeToMerge<_minimumTimeToMergeTile) _minimumTimeToMergeTile = timeToMerge;
1497            if (timeToMerge>_maximumTimeToMergeTile) _maximumTimeToMergeTile = timeToMerge;
1498
1499            _totalTimeToMergeTiles += timeToMerge;
1500            ++_numTilesMerges;
1501        }
1502               
1503        // reset the loadedModel pointer
1504        databaseRequest->_loadedModel = 0;
1505
1506        // osg::notify(osg::NOTICE)<<"curr = "<<timeToMerge<<" min "<<getMinimumTimeToMergeTile()*1000.0<<" max = "<<getMaximumTimeToMergeTile()*1000.0<<" average = "<<getAverageTimToMergeTiles()*1000.0<<std::endl;
1507    }
1508
1509    osg::Timer_t last = osg::Timer::instance()->tick();
1510
1511    if (!localFileLoadedList.empty())
1512    {
1513        osg::notify(osg::DEBUG_INFO)<<"Done DatabasePager::addLoadedDataToSceneGraph"<<
1514            osg::Timer::instance()->delta_m(before,mid)<<"ms,\t"<<
1515            osg::Timer::instance()->delta_m(mid,last)<<"ms"<<
1516            "  objects"<<localFileLoadedList.size()<<std::endl<<std::endl;
1517    }
1518}
1519
1520class DatabasePager::MarkPagedLODsVisitor : public osg::NodeVisitor
1521{
1522public:
1523    MarkPagedLODsVisitor(const std::string& marker):
1524        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1525        _marker(marker),
1526        _numPagedLODsMarked(0)
1527    {
1528    }
1529
1530    META_NodeVisitor("osgDB","MarkPagedLODsVisitor")
1531
1532    virtual void apply(osg::PagedLOD& plod)
1533    {
1534        if (plod.getName()!=_marker)
1535        {
1536            ++_numPagedLODsMarked;
1537            plod.setName(_marker);
1538   
1539            traverse(plod);
1540        }
1541    }
1542   
1543    std::string _marker;
1544    int _numPagedLODsMarked;
1545};
1546
1547void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1548{
1549    if (_targetMaximumNumberOfPageLOD>0)
1550    {
1551        capped_removeExpiredSubgraphs(frameStamp);
1552    }
1553    else
1554    {
1555        expiry_removeExpiredSubgraphs(frameStamp);
1556    }
1557}
1558
1559void DatabasePager::capped_removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1560{
1561    static double s_total_iter_stage_a = 0.0;
1562    static double s_total_time_stage_a = 0.0;
1563    static double s_total_max_stage_a = 0.0;
1564   
1565    static double s_total_iter_stage_b = 0.0;
1566    static double s_total_time_stage_b = 0.0;
1567    static double s_total_max_stage_b = 0.0;
1568
1569    static double s_total_iter_stage_c = 0.0;
1570    static double s_total_time_stage_c = 0.0;
1571    static double s_total_max_stage_c = 0.0;
1572
1573    osg::Timer_t startTick = osg::Timer::instance()->tick();
1574
1575
1576    unsigned int numPagedLODs = _activePagedLODList.size() + _inactivePagedLODList.size();
1577   
1578
1579    PagedLODList::iterator itr = _activePagedLODList.begin();
1580    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1581        itr != _activePagedLODList.end();
1582        )
1583    {
1584        osg::PagedLOD* plod = itr->get();
1585       
1586        int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
1587        if (delta>1)
1588        {
1589            if (_releaseDelay!=DBL_MAX)
1590            {
1591                plod->releaseGLObjects();
1592                osg::notify(osg::NOTICE)<<"DatabasePager::removeExpiredSubgraphs(), releasing gl objects"<<std::endl;
1593            }
1594
1595            _inactivePagedLODList.push_back(plod);
1596           
1597            itr = _activePagedLODList.erase(itr);
1598        }
1599        else
1600        {
1601            ++itr;
1602        }
1603    }
1604
1605    for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1606        itr != _inactivePagedLODList.end();
1607        )
1608    {
1609        osg::PagedLOD* plod = itr->get();
1610       
1611        int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal();
1612        if (delta>1)
1613        {
1614            ++itr;
1615        }
1616        else
1617        {
1618            _activePagedLODList.push_back(plod);
1619           
1620            itr = _inactivePagedLODList.erase(itr);
1621        }
1622    }
1623
1624    int inactivePLOD = _inactivePagedLODList.size();
1625
1626   
1627    osg::Timer_t end_a_Tick = osg::Timer::instance()->tick();
1628    double time_a = osg::Timer::instance()->delta_m(startTick,end_a_Tick);
1629
1630    s_total_iter_stage_a += 1.0;
1631    s_total_time_stage_a += time_a;
1632    if (s_total_max_stage_a<time_a) s_total_max_stage_a = time_a;
1633   
1634
1635    if (numPagedLODs <= _targetMaximumNumberOfPageLOD)
1636    {
1637        // nothing to do
1638        return;
1639    }
1640   
1641    int numToPrune = numPagedLODs - _targetMaximumNumberOfPageLOD;
1642    if (numToPrune > inactivePLOD)
1643    {
1644        numToPrune = inactivePLOD;
1645    }
1646
1647
1648    osg::NodeList childrenRemoved;
1649   
1650    double expiryTime = frameStamp.getReferenceTime() - 0.1;
1651    int expiryFrame = frameStamp.getFrameNumber() - 1;
1652
1653    MarkPagedLODsVisitor markerVistor("NeedToRemove");
1654
1655    for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1656        itr!=_inactivePagedLODList.end() && markerVistor._numPagedLODsMarked<numToPrune;
1657        ++itr)
1658    {
1659        osg::PagedLOD* plod = itr->get();
1660
1661        osg::NodeList localChildrenRemoved;
1662        plod->removeExpiredChildren(expiryTime, expiryFrame, localChildrenRemoved);
1663        if (!localChildrenRemoved.empty())
1664        {
1665            for(osg::NodeList::iterator critr = localChildrenRemoved.begin();
1666                critr!=localChildrenRemoved.end();
1667                ++critr)
1668            {
1669                (*critr)->accept(markerVistor);
1670            }
1671           
1672            std::copy(localChildrenRemoved.begin(),localChildrenRemoved.end(),std::back_inserter(childrenRemoved));
1673        }
1674    }
1675   
1676    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1677        itr!=_activePagedLODList.end() && markerVistor._numPagedLODsMarked<numToPrune;
1678        ++itr)
1679    {
1680        osg::PagedLOD* plod = itr->get();
1681
1682        osg::NodeList localChildrenRemoved;
1683        plod->removeExpiredChildren(expiryTime, expiryFrame, localChildrenRemoved);
1684        if (!localChildrenRemoved.empty())
1685        {
1686            for(osg::NodeList::iterator critr = localChildrenRemoved.begin();
1687                critr!=localChildrenRemoved.end();
1688                ++critr)
1689            {
1690                (*critr)->accept(markerVistor);
1691            }
1692           
1693            std::copy(localChildrenRemoved.begin(),localChildrenRemoved.end(),std::back_inserter(childrenRemoved));
1694        }
1695    }
1696   
1697    osg::Timer_t end_b_Tick = osg::Timer::instance()->tick();
1698    double time_b = osg::Timer::instance()->delta_m(end_a_Tick,end_b_Tick);
1699
1700    s_total_iter_stage_b += 1.0;
1701    s_total_time_stage_b += time_b;
1702    if (s_total_max_stage_b<time_b) s_total_max_stage_b = time_b;
1703
1704
1705
1706    //osg::notify(osg::NOTICE)<<"numToPrune "<<numToPrune<< " markerVistor._numPagedLODsMarked="<<markerVistor._numPagedLODsMarked<< " childrenRemoved.size()="<<childrenRemoved.size()<<std::endl;
1707
1708    if (!childrenRemoved.empty())
1709    {
1710        bool updateBlock = false;
1711
1712        // pass the objects across to the database pager delete list
1713        if (_deleteRemovedSubgraphsInDatabaseThread)
1714        {
1715            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_childrenToDeleteListMutex);
1716            for (osg::NodeList::iterator critr = childrenRemoved.begin();
1717                 critr!=childrenRemoved.end();
1718                 ++critr)
1719            {
1720                _fileRequestQueue->_childrenToDeleteList.push_back(critr->get());
1721            }
1722           
1723            updateBlock = true;
1724
1725        }
1726
1727        int numRemoved = 0;
1728        int numToRemove = markerVistor._numPagedLODsMarked;
1729       
1730       
1731        //osg::notify(osg::NOTICE)<<"Children to remove "<<childrenRemoved.size()<<" numToRemove="<<numToRemove<<std::endl;
1732
1733        // osg::notify(osg::NOTICE)<<"   time 2 "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
1734        int numSkipped = 0;
1735        for(PagedLODList::iterator itr = _inactivePagedLODList.begin();
1736            itr!=_inactivePagedLODList.end() && numRemoved<numToRemove;
1737            )
1738        {
1739            osg::PagedLOD* plod = itr->get();
1740            if (plod && plod->getName() != markerVistor._marker)
1741            {
1742                ++itr;
1743               
1744                ++numSkipped;
1745               
1746                // osg::notify(osg::NOTICE)<<"skipping"<<std::endl;
1747            }
1748            else
1749            {
1750                // osg::notify(osg::NOTICE)<<"removing"<<std::endl;
1751
1752                ++numRemoved;
1753
1754                itr = _inactivePagedLODList.erase(itr);
1755            }
1756        }
1757
1758        osg::notify(osg::INFO)<<"Number of PagedLODs skipped="<<numSkipped<<" removed "<<numRemoved<<std::endl;
1759
1760
1761        childrenRemoved.clear();
1762
1763
1764        if (updateBlock)
1765        {
1766            _fileRequestQueue->updateBlock();
1767        }
1768    }
1769   
1770    osg::Timer_t end_c_Tick = osg::Timer::instance()->tick();
1771    double time_c = osg::Timer::instance()->delta_m(end_b_Tick,end_c_Tick);
1772
1773    s_total_iter_stage_c += 1.0;
1774    s_total_time_stage_c += time_c;
1775    if (s_total_max_stage_c<time_c) s_total_max_stage_c = time_c;
1776
1777
1778
1779    osg::notify(osg::INFO)<<"active="<<_activePagedLODList.size()<<" inactive="<<_inactivePagedLODList.size()<<" overall = "<<osg::Timer::instance()->delta_m(startTick,end_c_Tick)<<
1780                              " A="<<time_a<<" avg="<<s_total_time_stage_a/s_total_iter_stage_a<<" max = "<<s_total_max_stage_a<<
1781                              " B="<<time_b<<" avg="<<s_total_time_stage_b/s_total_iter_stage_b<<" max = "<<s_total_max_stage_b<<
1782                              " C="<<time_c<<" avg="<<s_total_time_stage_c/s_total_iter_stage_c<<" max = "<<s_total_max_stage_c<<std::endl;
1783
1784   
1785    if (osgDB::Registry::instance()->getSharedStateManager())
1786        osgDB::Registry::instance()->getSharedStateManager()->prune();
1787
1788    // update the Registry object cache.
1789    osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime());
1790    osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime);
1791}
1792
1793void DatabasePager::expiry_removeExpiredSubgraphs(const osg::FrameStamp& frameStamp)
1794{
1795//    osg::notify(osg::NOTICE)<<"DatabasePager::new_removeExpiredSubgraphs()"<<std::endl;
1796
1797    static double s_total_iter = 0.0;
1798    static double s_total_time = 0.0;
1799    static double s_total_max = 0.0;
1800   
1801    osg::Timer_t startTick = osg::Timer::instance()->tick();
1802
1803    double expiryTime = frameStamp.getReferenceTime() - _expiryDelay;
1804    int expiryFrame = frameStamp.getFrameNumber() - _expiryFrames;
1805
1806    double releaseTime = frameStamp.getReferenceTime() - _releaseDelay;
1807    int releaseFrame = frameStamp.getFrameNumber() - _releaseFrames;
1808
1809    osg::NodeList childrenRemoved;
1810   
1811    for(PagedLODList::iterator itr = _activePagedLODList.begin();
1812        itr!=_activePagedLODList.end();
1813        ++itr)
1814    {
1815        osg::PagedLOD* plod = itr->get();
1816       
1817       
1818        if (_releaseDelay!=DBL_MAX && plod->releaseGLObjectsOnExpiredChildren(releaseTime, releaseFrame))
1819        {
1820            osg::notify(osg::INFO)<<"DatabasePager::removeExpiredSubgraphs(), releasing gl objects"<<std::endl;
1821        }
1822       
1823        plod->removeExpiredChildren(expiryTime, expiryFrame, childrenRemoved);
1824    }
1825   
1826    if (!childrenRemoved.empty())
1827    {
1828        MarkPagedLODsVisitor markerVistor("NeedToRemove");
1829        for(osg::NodeList::iterator critr = childrenRemoved.begin();
1830            critr!=childrenRemoved.end();
1831            ++critr)
1832        {
1833            (*critr)->accept(markerVistor);
1834        }   
1835   
1836        // osg::notify(osg::NOTICE)<<"Children to remove "<<childrenRemoved.size()<<std::endl;
1837   
1838        // pass the objects across to the database pager delete list
1839        if (_deleteRemovedSubgraphsInDatabaseThread)
1840        {
1841            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestQueue->_childrenToDeleteListMutex);
1842            for (osg::NodeList::iterator critr = childrenRemoved.begin();
1843                 critr!=childrenRemoved.end();
1844                 ++critr)
1845            {
1846                _fileRequestQueue->_childrenToDeleteList.push_back(critr->get());
1847            }
1848
1849            _fileRequestQueue->updateBlock();
1850        }
1851
1852        // osg::notify(osg::NOTICE)<<"   time 2 "<<osg::Timer::instance()->delta_m(before,osg::Timer::instance()->tick())<<" ms "<<std::endl;
1853        for(PagedLODList::iterator itr = _activePagedLODList.begin();
1854            itr!=_activePagedLODList.end();
1855            )
1856        {
1857            osg::PagedLOD* plod = itr->get();
1858            if (plod && plod->getName() != markerVistor._marker)
1859            {
1860                ++itr;
1861            }
1862            else
1863            {
1864                PagedLODList::iterator itr_to_erase = itr;
1865                ++itr;
1866
1867                _activePagedLODList.erase(itr_to_erase);           
1868            }
1869        }
1870
1871        childrenRemoved.clear();
1872
1873
1874    }
1875
1876    osg::Timer_t endTick = osg::Timer::instance()->tick();
1877    double time = osg::Timer::instance()->delta_m(startTick,endTick);
1878
1879    s_total_iter += 1.0;
1880    s_total_time += time;
1881    if (s_total_max<time) s_total_max = time;
1882
1883    osg::notify(osg::INFO)<<"_activePagedLODList.size()="<<_activePagedLODList.size()<<" overall = "<<time<<
1884                              " avg="<<s_total_time/s_total_iter<<" max = "<<s_total_max<<std::endl;
1885     
1886   
1887    if (osgDB::Registry::instance()->getSharedStateManager())
1888        osgDB::Registry::instance()->getSharedStateManager()->prune();
1889
1890    // update the Registry object cache.
1891    osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime());
1892    osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime);
1893
1894
1895}
1896
1897class DatabasePager::FindPagedLODsVisitor : public osg::NodeVisitor
1898{
1899public:
1900
1901    FindPagedLODsVisitor(DatabasePager::PagedLODList& pagedLODList, int frameNumber):
1902        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1903        _activePagedLODList(pagedLODList),
1904        _frameNumber(frameNumber)
1905    {
1906    }
1907   
1908    META_NodeVisitor("osgDB","FindPagedLODsVisitor")
1909
1910    virtual void apply(osg::PagedLOD& plod)
1911    {
1912        plod.setFrameNumberOfLastTraversal(_frameNumber);
1913       
1914        _activePagedLODList.push_back(&plod);
1915   
1916        traverse(plod);
1917    }
1918   
1919    DatabasePager::PagedLODList& _activePagedLODList;
1920    int _frameNumber;
1921       
1922protected:
1923   
1924    FindPagedLODsVisitor& operator = (const FindPagedLODsVisitor&) { return *this; }
1925};
1926
1927void DatabasePager::registerPagedLODs(osg::Node* subgraph, int frameNumber)
1928{
1929    if (!subgraph) return;
1930   
1931    FindPagedLODsVisitor fplv(_activePagedLODList, frameNumber);
1932    subgraph->accept(fplv);
1933}
1934
1935bool DatabasePager::requiresCompileGLObjects() const
1936{
1937    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
1938    return !_dataToCompileList->_requestList.empty();
1939}
1940
1941void DatabasePager::setCompileGLObjectsForContextID(unsigned int contextID, bool on)
1942{
1943    if (on)
1944    {
1945        _activeGraphicsContexts.insert(contextID);
1946    }
1947    else
1948    {
1949        _activeGraphicsContexts.erase(contextID);
1950    }
1951}
1952
1953bool DatabasePager::getCompileGLObjectsForContextID(unsigned int contextID)
1954{
1955    return _activeGraphicsContexts.count(contextID)!=0;
1956}
1957
1958
1959DatabasePager::CompileOperation::CompileOperation(osgDB::DatabasePager* databasePager):
1960    osg::GraphicsOperation("DatabasePager::CompileOperation",false),
1961    _databasePager(databasePager)
1962{
1963}
1964
1965void DatabasePager::CompileOperation::operator () (osg::GraphicsContext* context)
1966{
1967    // osg::notify(osg::NOTICE)<<"Background thread compiling"<<std::endl;
1968
1969    if (_databasePager.valid()) _databasePager->compileAllGLObjects(*(context->getState()));
1970   
1971}
1972
1973bool DatabasePager::requiresExternalCompileGLObjects(unsigned int contextID) const
1974{
1975    if (_activeGraphicsContexts.count(contextID)==0) return false;
1976
1977    return osg::GraphicsContext::getCompileContext(contextID)==0;
1978}
1979
1980void DatabasePager::compileAllGLObjects(osg::State& state)
1981{
1982    double availableTime = DBL_MAX;
1983    compileGLObjects(state, availableTime);
1984}
1985
1986void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
1987{
1988    // osg::notify(osg::NOTICE)<<"DatabasePager::compileGLObjects "<<_frameNumber<<std::endl;
1989
1990    bool compileAll = (availableTime==DBL_MAX);
1991
1992    SharedStateManager *sharedManager
1993        = Registry::instance()->getSharedStateManager();
1994    osg::RenderInfo renderInfo;
1995    renderInfo.setState(&state);
1996
1997    if (availableTime>0.0)
1998    {
1999
2000        const osg::Timer& timer = *osg::Timer::instance();
2001        osg::Timer_t start_tick = timer.tick();
2002        double elapsedTime = 0.0;
2003        double estimatedTextureDuration = 0.0001;
2004        double estimatedDrawableDuration = 0.0001;
2005
2006        osg::ref_ptr<DatabaseRequest> databaseRequest;
2007
2008        // get the first compilable entry.
2009        {
2010            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
2011       
2012            // advance to the next entry to compile if one is available.
2013            databaseRequest = _dataToCompileList->_requestList.empty() ? 0 : _dataToCompileList->_requestList.front().get();
2014        };
2015
2016        unsigned int numObjectsCompiled = 0;
2017
2018        // while there are valid databaseRequest's in the to compile list and there is
2019        // sufficient time left compile each databaseRequest's stateset and drawables.
2020        while (databaseRequest.valid() && (compileAll || (elapsedTime<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)) )
2021        {
2022            DataToCompileMap& dcm = databaseRequest->_dataToCompileMap;
2023            DataToCompile& dtc = dcm[state.getContextID()];
2024            if (!dtc.first.empty() && (elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)
2025            {
2026
2027                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
2028
2029                // we have StateSet's to compile
2030                StateSetList& sslist = dtc.first;
2031                //osg::notify(osg::INFO)<<"Compiling statesets"<<std::endl;
2032                StateSetList::iterator itr=sslist.begin();
2033                unsigned int objTemp = numObjectsCompiled;
2034                for(;
2035                    itr!=sslist.end() && (compileAll || ((elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
2036                    ++itr)
2037                {
2038                    //osg::notify(osg::INFO)<<"    Compiling stateset "<<(*itr).get()<<std::endl;
2039                    if (isCompiled(itr->get(), state.getContextID())
2040                        || (sharedManager && sharedManager->isShared(itr->get())))
2041                    {
2042                        elapsedTime = timer.delta_s(start_tick,timer.tick());
2043                        continue;
2044                    }
2045                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
2046
2047                    (*itr)->compileGLObjects(state);
2048
2049                    GLint p;
2050                    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p);
2051
2052                    elapsedTime = timer.delta_s(start_tick,timer.tick());
2053
2054
2055                    // estimate the duration of the compile based on current compile duration.
2056                    estimatedTextureDuration = (elapsedTime-startCompileTime);
2057
2058                    ++numObjectsCompiled;
2059                }
2060                if (osg::getNotifyLevel() >= osg::DEBUG_INFO
2061                    && numObjectsCompiled > objTemp)
2062                    osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
2063                                                << numObjectsCompiled - objTemp
2064                                                << " StateSets" << std::endl;
2065                // remove the compiled statesets from the list.
2066                sslist.erase(sslist.begin(),itr);
2067            }
2068
2069            if (!dtc.second.empty() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame)))
2070            {
2071                // we have Drawable's to compile
2072                //osg::notify(osg::INFO)<<"Compiling drawables"<<std::endl;
2073                DrawableList& dwlist = dtc.second;
2074                DrawableList::iterator itr=dwlist.begin();
2075                unsigned int objTemp = numObjectsCompiled;
2076                for(;
2077                    itr!=dwlist.end() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
2078                    ++itr)
2079                {
2080                    //osg::notify(osg::INFO)<<"    Compiling drawable "<<(*itr).get()<<std::endl;
2081                    if (isCompiled(itr->get(), state.getContextID()))
2082                    {
2083                        elapsedTime = timer.delta_s(start_tick,timer.tick());
2084                        continue;
2085                    }
2086                    double startCompileTime = timer.delta_s(start_tick,timer.tick());
2087                    (*itr)->compileGLObjects(renderInfo);
2088                    elapsedTime = timer.delta_s(start_tick,timer.tick());
2089
2090                    // estimate the duration of the compile based on current compile duration.
2091                    estimatedDrawableDuration = (elapsedTime-startCompileTime);
2092
2093                    ++numObjectsCompiled;
2094
2095                }
2096                if (osg::getNotifyLevel() >= osg::DEBUG_INFO
2097                    && numObjectsCompiled > objTemp)
2098                    osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
2099                                                << numObjectsCompiled - objTemp
2100                                                << " Drawables" << std::endl;
2101                // remove the compiled drawables from the list.
2102                dwlist.erase(dwlist.begin(),itr);
2103            }
2104
2105            //osg::notify(osg::INFO)<<"Checking if compiled"<<std::endl;
2106
2107            // now check the to compile entries for all active graphics contexts
2108            // to make sure that all have been compiled. They won't be
2109            // if we ran out of time or if another thread is still
2110            // compiling for its graphics context.
2111            bool allCompiled = true;
2112            for(DataToCompileMap::iterator itr=dcm.begin();
2113                itr!=dcm.end() && allCompiled;
2114                ++itr)
2115            {
2116                if (!(itr->second.first.empty())) allCompiled=false;
2117                if (!(itr->second.second.empty())) allCompiled=false;
2118            }
2119
2120            //if (numObjectsCompiled > 0)
2121            //osg::notify(osg::NOTICE)<< _frameNumber << "compiled " << numObjectsCompiled << " objects" << std::endl;
2122           
2123            if (allCompiled)
2124            {
2125                // we've compiled all of the current databaseRequest so we can now pop it off the
2126                // to compile list and place it on the merge list.
2127                // osg::notify(osg::NOTICE)<<"All compiled"<<std::endl;
2128
2129
2130                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileList->_requestMutex);
2131
2132                // The request might have been removed from the
2133                // _dataToCompile list by another graphics thread, in
2134                // which case it's already on the merge list, or by
2135                // the pager, which means that the request has
2136                // expired. Also, the compile list might have been
2137                // shuffled by the pager, so the current request is
2138                // not guaranteed to still be at the beginning of the
2139                // list.
2140               
2141                RequestQueue::RequestList::iterator requestIter
2142                    = std::find(_dataToCompileList->_requestList.begin(), _dataToCompileList->_requestList.end(),
2143                           databaseRequest);
2144                if (requestIter != _dataToCompileList->_requestList.end())
2145                {
2146                    {
2147                        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeList->_requestMutex);
2148                        databaseRequest->_requestQueue = _dataToMergeList.get();
2149                        _dataToMergeList->_requestList.push_back(databaseRequest);
2150                    }
2151                    _dataToCompileList->_requestList.erase(requestIter);
2152                }
2153               
2154                if (!_dataToCompileList->_requestList.empty()) databaseRequest = _dataToCompileList->_requestList.front();
2155                else databaseRequest = 0;
2156
2157            }
2158            else 
2159            {
2160                // osg::notify(osg::NOTICE)<<"Not all compiled"<<std::endl;
2161                databaseRequest = 0;
2162            }
2163
2164            elapsedTime = timer.delta_s(start_tick,timer.tick());
2165        }
2166
2167        availableTime -= elapsedTime;
2168
2169        //osg::notify(osg::NOTICE)<<"elapsedTime="<<elapsedTime<<"\ttime remaining ="<<availableTime<<"\tnumObjectsCompiled = "<<numObjectsCompiled<<std::endl;
2170        //osg::notify(osg::NOTICE)<<"estimatedTextureDuration="<<estimatedTextureDuration;
2171        //osg::notify(osg::NOTICE)<<"\testimatedDrawableDuration="<<estimatedDrawableDuration<<std::endl;
2172    }
2173    else
2174    {
2175        availableTime = 0.0f;
2176    }
2177}
Note: See TracBrowser for help on using the browser.