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

Revision 10764, 77.7 kB (checked in by robert, 5 years ago)

<iterator>, <stdlib.h> and <ctype.h> includes required for QNX compiler

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