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

Revision 11285, 70.5 kB (checked in by robert, 4 years ago)

Refactored the way that the RequestQueue?'s are pruned and highest prioty items taken from them so the operation is
now O(n) rather than O(nlogn) where n is the number of requests. The refactoring also cleans up the access of the
request lists so that the code is more readable/maintainable.

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