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

Revision 11236, 72.9 kB (checked in by robert, 4 years ago)

disabled timing debug info

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