123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
- *
- * This library is open source and may be redistributed and/or modified under
- * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
- * (at your option) any later version. The full license is in LICENSE file
- * included with this distribution, and on the openscenegraph.org website.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * OpenSceneGraph Public License for more details.
- */
- #ifndef OSGDB_DATABASEPAGER
- #define OSGDB_DATABASEPAGER 1
- #include <osg/NodeVisitor>
- #include <osg/Group>
- #include <osg/PagedLOD>
- #include <osg/Drawable>
- #include <osg/GraphicsThread>
- #include <osg/FrameStamp>
- #include <osg/ObserverNodePath>
- #include <osg/observer_ptr>
- #include <OpenThreads/Thread>
- #include <OpenThreads/Mutex>
- #include <OpenThreads/ScopedLock>
- #include <OpenThreads/Condition>
- #include <osgUtil/IncrementalCompileOperation>
- #include <osgDB/SharedStateManager>
- #include <osgDB/ReaderWriter>
- #include <osgDB/Options>
- #include <map>
- #include <list>
- #include <algorithm>
- #include <functional>
- namespace osgDB {
- /** Database paging class which manages the loading of files in a background thread,
- * and synchronizing of loaded models with the main scene graph.*/
- class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler
- {
- public :
- typedef OpenThreads::Thread::ThreadPriority ThreadPriority;
- DatabasePager();
- DatabasePager(const DatabasePager& rhs);
- virtual const char* className() const { return "DatabasePager"; }
- /** Create a shallow copy on the DatabasePager.*/
- virtual DatabasePager* clone() const { return new DatabasePager(*this); }
- /** get the prototype singleton used by DatabasePager::create().*/
- static osg::ref_ptr<DatabasePager>& prototype();
- /** create a DatabasePager by cloning DatabasePager::prototype().*/
- static DatabasePager* create();
- /** Add a request to load a node file to end the database request list.*/
- virtual void requestNodeFile(const std::string& fileName, osg::NodePath& nodePath,
- float priority, const osg::FrameStamp* framestamp,
- osg::ref_ptr<osg::Referenced>& databaseRequest,
- const osg::Referenced* options);
- /** Set the priority of the database pager thread(s).*/
- int setSchedulePriority(OpenThreads::Thread::ThreadPriority priority);
- /** Cancel the database pager thread(s).*/
- virtual int cancel();
- virtual bool isRunning() const;
- /** Clear all internally cached structures.*/
- virtual void clear();
- class OSGDB_EXPORT DatabaseThread : public osg::Referenced, public OpenThreads::Thread
- {
- public:
- enum Mode
- {
- HANDLE_ALL_REQUESTS,
- HANDLE_NON_HTTP,
- HANDLE_ONLY_HTTP
- };
- DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name);
- DatabaseThread(const DatabaseThread& dt, DatabasePager* pager);
- void setName(const std::string& name) { _name = name; }
- const std::string& getName() const { return _name; }
- void setDone(bool done) { _done.exchange(done?1:0); }
- bool getDone() const { return _done!=0; }
- void setActive(bool active) { _active = active; }
- bool getActive() const { return _active; }
- virtual int cancel();
- virtual void run();
- protected:
- virtual ~DatabaseThread();
- OpenThreads::Atomic _done;
- volatile bool _active;
- DatabasePager* _pager;
- Mode _mode;
- std::string _name;
- };
- virtual void setProcessorAffinity(const OpenThreads::Affinity& affinity);
- OpenThreads::Affinity& getProcessorAffinity() { return _affinity; }
- const OpenThreads::Affinity& getProcessorAffinity() const { return _affinity; }
- void setUpThreads(unsigned int totalNumThreads=2, unsigned int numHttpThreads=1);
- virtual unsigned int addDatabaseThread(DatabaseThread::Mode mode, const std::string& name);
- DatabaseThread* getDatabaseThread(unsigned int i) { return _databaseThreads[i].get(); }
- const DatabaseThread* getDatabaseThread(unsigned int i) const { return _databaseThreads[i].get(); }
- unsigned int getNumDatabaseThreads() const { return static_cast<unsigned int>(_databaseThreads.size()); }
- /** Set whether the database pager thread should be paused or not.*/
- void setDatabasePagerThreadPause(bool pause);
- /** Get whether the database pager thread should is paused or not.*/
- bool getDatabasePagerThreadPause() const { return _databasePagerThreadPaused; }
- /** Set whether new database request calls are accepted or ignored.*/
- void setAcceptNewDatabaseRequests(bool acceptNewRequests) { _acceptNewRequests = acceptNewRequests; }
- /** Get whether new database request calls are accepted or ignored.*/
- bool getAcceptNewDatabaseRequests() const { return _acceptNewRequests; }
- /** Get the number of frames that are currently active.*/
- int getNumFramesActive() const { return _numFramesActive; }
- /** Signal the database thread that the update, cull and draw has begun for a new frame.
- * Note, this is called by the application so that the database pager can go to sleep while the CPU is busy on the main rendering threads. */
- virtual void signalBeginFrame(const osg::FrameStamp* framestamp);
- /** Signal the database thread that the update, cull and draw dispatch has completed.
- * Note, this is called by the application so that the database pager can go to wake back up now the main rendering threads are iddle waiting for the next frame.*/
- virtual void signalEndFrame();
- /** Find all PagedLOD nodes in a subgraph and register them with
- * the DatabasePager so it can keep track of expired nodes.
- * note, should be only be called from the update thread. */
- virtual void registerPagedLODs(osg::Node* subgraph, unsigned int frameNumber = 0);
- /** Set the incremental compile operation.
- * Used to manage the OpenGL object compilation and merging of subgraphs in a way that avoids overloading
- * the rendering of frame with too many new objects in one frame. */
- void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico);
- /** Get the incremental compile operation. */
- osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation() { return _incrementalCompileOperation.get(); }
- /** Set whether the database pager should pre compile OpenGL objects before allowing
- * them to be merged into the scene graph.
- * Pre compilation helps reduce the chances of frame drops, but also slows the
- * speed at which tiles are merged as they have to be compiled first.*/
- void setDoPreCompile(bool flag) { _doPreCompile = flag; }
- /** Get whether the database pager should pre compile OpenGL objects before allowing
- * them to be merged into the scene graph.*/
- bool getDoPreCompile() const { return _doPreCompile; }
- /** Set the target maximum number of PagedLOD to maintain in memory.
- * Note, if more than the target number are required for rendering of a frame then these active PagedLOD are excempt from being expiried.
- * But once the number of active drops back below the target the inactive PagedLOD will be trimmed back to the target number.*/
- void setTargetMaximumNumberOfPageLOD(unsigned int target) { _targetMaximumNumberOfPageLOD = target; }
- /** Get the target maximum number of PagedLOD to maintain in memory.*/
- unsigned int getTargetMaximumNumberOfPageLOD() const { return _targetMaximumNumberOfPageLOD; }
- /** Set whether the removed subgraphs should be deleted in the database thread or not.*/
- void setDeleteRemovedSubgraphsInDatabaseThread(bool flag) { _deleteRemovedSubgraphsInDatabaseThread = flag; }
- /** Get whether the removed subgraphs should be deleted in the database thread or not.*/
- bool getDeleteRemovedSubgraphsInDatabaseThread() const { return _deleteRemovedSubgraphsInDatabaseThread; }
- enum DrawablePolicy
- {
- DO_NOT_MODIFY_DRAWABLE_SETTINGS,
- USE_DISPLAY_LISTS,
- USE_VERTEX_BUFFER_OBJECTS,
- USE_VERTEX_ARRAYS
- };
- /** Set how loaded drawables should be handled w.r.t their display list/vertex buffer object/vertex array settings.*/
- void setDrawablePolicy(DrawablePolicy policy) { _drawablePolicy = policy; }
- /** Get how loaded drawables should be handled w.r.t their display list/vertex buffer object/vertex array settings.*/
- DrawablePolicy getDrawablePolicy() const { return _drawablePolicy; }
- /** Set whether newly loaded textures should have a PixelBufferObject assigned to them to aid download to the GPU.*/
- void setApplyPBOToImages(bool assignPBOToImages) { _assignPBOToImages = assignPBOToImages; }
- /** Get whether newly loaded textures should have a PixelBufferObject assigned to them.*/
- bool getApplyPBOToImages() const { return _assignPBOToImages; }
- /** Set whether newly loaded textures should have their UnrefImageDataAfterApply set to a specified value.*/
- void setUnrefImageDataAfterApplyPolicy(bool changeAutoUnRef, bool valueAutoUnRef) { _changeAutoUnRef = changeAutoUnRef; _valueAutoUnRef = valueAutoUnRef; }
- /** Get whether newly loaded textures should have their UnrefImageDataAfterApply set to a specified value.*/
- void getUnrefImageDataAfterApplyPolicy(bool& changeAutoUnRef, bool& valueAutoUnRef) const { changeAutoUnRef = _changeAutoUnRef; valueAutoUnRef = _valueAutoUnRef; }
- /** Set whether newly loaded textures should have their MaxAnisotopy set to a specified value.*/
- void setMaxAnisotropyPolicy(bool changeAnisotropy, float valueAnisotropy) { _changeAnisotropy = changeAnisotropy; _valueAnisotropy = valueAnisotropy; }
- /** Set whether newly loaded textures should have their MaxAnisotopy set to a specified value.*/
- void getMaxAnisotropyPolicy(bool& changeAnisotropy, float& valueAnisotropy) const { changeAnisotropy = _changeAnisotropy; valueAnisotropy = _valueAnisotropy; }
- /** Return true if there are pending updates to the scene graph that require a call to updateSceneGraph(double). */
- bool requiresUpdateSceneGraph() const;
- /** Merge the changes to the scene graph by calling calling removeExpiredSubgraphs then addLoadedDataToSceneGraph.
- * Note, must only be called from single thread update phase. */
- virtual void updateSceneGraph(const osg::FrameStamp& frameStamp);
- /** Return true if there are GL objects that need to be compiled by a draw traversal. */
- bool requiresRedraw() const;
- /** Report how many items are in the _fileRequestList queue */
- unsigned int getFileRequestListSize() const { return static_cast<unsigned int>(_fileRequestQueue->size() + _httpRequestQueue->size()); }
- /** Report how many items are in the _dataToCompileList queue */
- unsigned int getDataToCompileListSize() const { return static_cast<unsigned int>(_dataToCompileList->size()); }
- /** Report how many items are in the _dataToMergeList queue */
- unsigned int getDataToMergeListSize() const { return static_cast<unsigned int>(_dataToMergeList->size()); }
- /** Report whether any requests are in the pager.*/
- bool getRequestsInProgress() const;
- /** Get the minimum time between the first request for a tile to be loaded and the time of its merge into the main scene graph.*/
- double getMinimumTimeToMergeTile() const { return _minimumTimeToMergeTile; }
- /** Get the maximum time between the first request for a tile to be loaded and the time of its merge into the main scene graph.*/
- double getMaximumTimeToMergeTile() const { return _maximumTimeToMergeTile; }
- /** Get the average time between the first request for a tile to be loaded and the time of its merge into the main scene graph.*/
- double getAverageTimeToMergeTiles() const { return (_numTilesMerges > 0) ? _totalTimeToMergeTiles/static_cast<double>(_numTilesMerges) : 0; }
- /** Reset the Stats variables.*/
- void resetStats();
- typedef std::set< osg::ref_ptr<osg::StateSet> > StateSetList;
- typedef std::vector< osg::ref_ptr<osg::Drawable> > DrawableList;
- class ExpirePagedLODsVisitor;
- typedef std::list< osg::ref_ptr<osg::Object> > ObjectList;
- struct PagedLODList : public osg::Referenced
- {
- virtual PagedLODList* clone() = 0;
- virtual void clear() = 0;
- virtual unsigned int size() = 0;
- virtual void removeExpiredChildren(int numberChildrenToRemove, double expiryTime, unsigned int expiryFrame, ObjectList& childrenRemoved, bool visitActive) = 0;
- virtual void removeNodes(osg::NodeList& nodesToRemove) = 0;
- virtual void insertPagedLOD(const osg::observer_ptr<osg::PagedLOD>& plod) = 0;
- virtual bool containsPagedLOD(const osg::observer_ptr<osg::PagedLOD>& plod) const = 0;
- };
- void setMarkerObject(osg::Object* mo) { _markerObject = mo; }
- osg::Object* getMarkerObject() { return _markerObject.get(); }
- const osg::Object* getMarkerObject() const { return _markerObject.get(); }
- protected:
- virtual ~DatabasePager();
- friend class DatabaseThread;
- friend struct DatabaseRequest;
- struct RequestQueue;
- struct OSGDB_EXPORT DatabaseRequest : public osg::Referenced
- {
- DatabaseRequest():
- osg::Referenced(true),
- _valid(false),
- _frameNumberFirstRequest(0),
- _timestampFirstRequest(0.0),
- _priorityFirstRequest(0.f),
- _frameNumberLastRequest(0),
- _timestampLastRequest(0.0),
- _priorityLastRequest(0.0f),
- _numOfRequests(0),
- _groupExpired(false)
- {}
- void invalidate();
- bool valid() const { return _valid; }
- bool isRequestCurrent (int frameNumber) const
- {
- return _valid && (frameNumber - _frameNumberLastRequest <= 1);
- }
- bool _valid;
- std::string _fileName;
- unsigned int _frameNumberFirstRequest;
- double _timestampFirstRequest;
- float _priorityFirstRequest;
- unsigned int _frameNumberLastRequest;
- double _timestampLastRequest;
- float _priorityLastRequest;
- unsigned int _numOfRequests;
- osg::observer_ptr<osg::Node> _terrain;
- osg::observer_ptr<osg::Group> _group;
- osg::ref_ptr<osg::Node> _loadedModel;
- osg::ref_ptr<Options> _loadOptions;
- osg::ref_ptr<ObjectCache> _objectCache;
- osg::observer_ptr<osgUtil::IncrementalCompileOperation::CompileSet> _compileSet;
- bool _groupExpired; // flag used only in update thread
- };
- struct OSGDB_EXPORT RequestQueue : public osg::Referenced
- {
- public:
- RequestQueue(DatabasePager* pager);
- void add(DatabaseRequest* databaseRequest);
- void remove(DatabaseRequest* databaseRequest);
- void addNoLock(DatabaseRequest* databaseRequest);
- void takeFirst(osg::ref_ptr<DatabaseRequest>& databaseRequest);
- /// prune all the old requests and then return true if requestList left empty
- bool pruneOldRequestsAndCheckIfEmpty();
- virtual void updateBlock() {}
- void invalidate(DatabaseRequest* dr);
- bool empty();
- unsigned int size();
- void clear();
- typedef std::list< osg::ref_ptr<DatabaseRequest> > RequestList;
- void swap(RequestList& requestList);
- DatabasePager* _pager;
- RequestList _requestList;
- OpenThreads::Mutex _requestMutex;
- unsigned int _frameNumberLastPruned;
- protected:
- virtual ~RequestQueue();
- };
- typedef std::vector< osg::ref_ptr<DatabaseThread> > DatabaseThreadList;
- struct OSGDB_EXPORT ReadQueue : public RequestQueue
- {
- ReadQueue(DatabasePager* pager, const std::string& name);
- void block() { _block->block(); }
- void release() { _block->release(); }
- virtual void updateBlock();
- osg::ref_ptr<osg::RefBlock> _block;
- std::string _name;
- OpenThreads::Mutex _childrenToDeleteListMutex;
- ObjectList _childrenToDeleteList;
- };
- // forward declare inner helper classes
- class FindCompileableGLObjectsVisitor;
- friend class FindCompileableGLObjectsVisitor;
- struct DatabasePagerCompileCompletedCallback;
- friend struct DatabasePagerCompileCompletedCallback;
- class FindPagedLODsVisitor;
- friend class FindPagedLODsVisitor;
- struct SortFileRequestFunctor;
- friend struct SortFileRequestFunctor;
- OpenThreads::Mutex _run_mutex;
- OpenThreads::Mutex _dr_mutex;
- bool _startThreadCalled;
- void compileCompleted(DatabaseRequest* databaseRequest);
- /** Iterate through the active PagedLOD nodes children removing
- * children which haven't been visited since specified expiryTime.
- * note, should be only be called from the update thread. */
- virtual void removeExpiredSubgraphs(const osg::FrameStamp &frameStamp);
- /** Add the loaded data to the scene graph.*/
- void addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp);
- OpenThreads::Affinity _affinity;
- bool _done;
- bool _acceptNewRequests;
- bool _databasePagerThreadPaused;
- DatabaseThreadList _databaseThreads;
- int _numFramesActive;
- mutable OpenThreads::Mutex _numFramesActiveMutex;
- OpenThreads::Atomic _frameNumber;
- osg::ref_ptr<ReadQueue> _fileRequestQueue;
- osg::ref_ptr<ReadQueue> _httpRequestQueue;
- osg::ref_ptr<RequestQueue> _dataToCompileList;
- osg::ref_ptr<RequestQueue> _dataToMergeList;
- DrawablePolicy _drawablePolicy;
- bool _assignPBOToImages;
- bool _changeAutoUnRef;
- bool _valueAutoUnRef;
- bool _changeAnisotropy;
- float _valueAnisotropy;
- bool _deleteRemovedSubgraphsInDatabaseThread;
- osg::ref_ptr<PagedLODList> _activePagedLODList;
- unsigned int _targetMaximumNumberOfPageLOD;
- bool _doPreCompile;
- osg::ref_ptr<osgUtil::IncrementalCompileOperation> _incrementalCompileOperation;
- double _minimumTimeToMergeTile;
- double _maximumTimeToMergeTile;
- double _totalTimeToMergeTiles;
- unsigned int _numTilesMerges;
- osg::ref_ptr<osg::Object> _markerObject;
- };
- }
- #endif
|