DatabasePager 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
  2. *
  3. * This library is open source and may be redistributed and/or modified under
  4. * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
  5. * (at your option) any later version. The full license is in LICENSE file
  6. * included with this distribution, and on the openscenegraph.org website.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * OpenSceneGraph Public License for more details.
  12. */
  13. #ifndef OSGDB_DATABASEPAGER
  14. #define OSGDB_DATABASEPAGER 1
  15. #include <osg/NodeVisitor>
  16. #include <osg/Group>
  17. #include <osg/PagedLOD>
  18. #include <osg/Drawable>
  19. #include <osg/GraphicsThread>
  20. #include <osg/FrameStamp>
  21. #include <osg/ObserverNodePath>
  22. #include <osg/observer_ptr>
  23. #include <OpenThreads/Thread>
  24. #include <OpenThreads/Mutex>
  25. #include <OpenThreads/ScopedLock>
  26. #include <OpenThreads/Condition>
  27. #include <osgUtil/IncrementalCompileOperation>
  28. #include <osgDB/SharedStateManager>
  29. #include <osgDB/ReaderWriter>
  30. #include <osgDB/Options>
  31. #include <map>
  32. #include <list>
  33. #include <algorithm>
  34. #include <functional>
  35. namespace osgDB {
  36. /** Database paging class which manages the loading of files in a background thread,
  37. * and synchronizing of loaded models with the main scene graph.*/
  38. class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler
  39. {
  40. public :
  41. typedef OpenThreads::Thread::ThreadPriority ThreadPriority;
  42. DatabasePager();
  43. DatabasePager(const DatabasePager& rhs);
  44. virtual const char* className() const { return "DatabasePager"; }
  45. /** Create a shallow copy on the DatabasePager.*/
  46. virtual DatabasePager* clone() const { return new DatabasePager(*this); }
  47. /** get the prototype singleton used by DatabasePager::create().*/
  48. static osg::ref_ptr<DatabasePager>& prototype();
  49. /** create a DatabasePager by cloning DatabasePager::prototype().*/
  50. static DatabasePager* create();
  51. /** Add a request to load a node file to end the database request list.*/
  52. virtual void requestNodeFile(const std::string& fileName, osg::NodePath& nodePath,
  53. float priority, const osg::FrameStamp* framestamp,
  54. osg::ref_ptr<osg::Referenced>& databaseRequest,
  55. const osg::Referenced* options);
  56. /** Set the priority of the database pager thread(s).*/
  57. int setSchedulePriority(OpenThreads::Thread::ThreadPriority priority);
  58. /** Cancel the database pager thread(s).*/
  59. virtual int cancel();
  60. virtual bool isRunning() const;
  61. /** Clear all internally cached structures.*/
  62. virtual void clear();
  63. class OSGDB_EXPORT DatabaseThread : public osg::Referenced, public OpenThreads::Thread
  64. {
  65. public:
  66. enum Mode
  67. {
  68. HANDLE_ALL_REQUESTS,
  69. HANDLE_NON_HTTP,
  70. HANDLE_ONLY_HTTP
  71. };
  72. DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name);
  73. DatabaseThread(const DatabaseThread& dt, DatabasePager* pager);
  74. void setName(const std::string& name) { _name = name; }
  75. const std::string& getName() const { return _name; }
  76. void setDone(bool done) { _done.exchange(done?1:0); }
  77. bool getDone() const { return _done!=0; }
  78. void setActive(bool active) { _active = active; }
  79. bool getActive() const { return _active; }
  80. virtual int cancel();
  81. virtual void run();
  82. protected:
  83. virtual ~DatabaseThread();
  84. OpenThreads::Atomic _done;
  85. volatile bool _active;
  86. DatabasePager* _pager;
  87. Mode _mode;
  88. std::string _name;
  89. };
  90. virtual void setProcessorAffinity(const OpenThreads::Affinity& affinity);
  91. OpenThreads::Affinity& getProcessorAffinity() { return _affinity; }
  92. const OpenThreads::Affinity& getProcessorAffinity() const { return _affinity; }
  93. void setUpThreads(unsigned int totalNumThreads=2, unsigned int numHttpThreads=1);
  94. virtual unsigned int addDatabaseThread(DatabaseThread::Mode mode, const std::string& name);
  95. DatabaseThread* getDatabaseThread(unsigned int i) { return _databaseThreads[i].get(); }
  96. const DatabaseThread* getDatabaseThread(unsigned int i) const { return _databaseThreads[i].get(); }
  97. unsigned int getNumDatabaseThreads() const { return static_cast<unsigned int>(_databaseThreads.size()); }
  98. /** Set whether the database pager thread should be paused or not.*/
  99. void setDatabasePagerThreadPause(bool pause);
  100. /** Get whether the database pager thread should is paused or not.*/
  101. bool getDatabasePagerThreadPause() const { return _databasePagerThreadPaused; }
  102. /** Set whether new database request calls are accepted or ignored.*/
  103. void setAcceptNewDatabaseRequests(bool acceptNewRequests) { _acceptNewRequests = acceptNewRequests; }
  104. /** Get whether new database request calls are accepted or ignored.*/
  105. bool getAcceptNewDatabaseRequests() const { return _acceptNewRequests; }
  106. /** Get the number of frames that are currently active.*/
  107. int getNumFramesActive() const { return _numFramesActive; }
  108. /** Signal the database thread that the update, cull and draw has begun for a new frame.
  109. * 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. */
  110. virtual void signalBeginFrame(const osg::FrameStamp* framestamp);
  111. /** Signal the database thread that the update, cull and draw dispatch has completed.
  112. * 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.*/
  113. virtual void signalEndFrame();
  114. /** Find all PagedLOD nodes in a subgraph and register them with
  115. * the DatabasePager so it can keep track of expired nodes.
  116. * note, should be only be called from the update thread. */
  117. virtual void registerPagedLODs(osg::Node* subgraph, unsigned int frameNumber = 0);
  118. /** Set the incremental compile operation.
  119. * Used to manage the OpenGL object compilation and merging of subgraphs in a way that avoids overloading
  120. * the rendering of frame with too many new objects in one frame. */
  121. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico);
  122. /** Get the incremental compile operation. */
  123. osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation() { return _incrementalCompileOperation.get(); }
  124. /** Set whether the database pager should pre compile OpenGL objects before allowing
  125. * them to be merged into the scene graph.
  126. * Pre compilation helps reduce the chances of frame drops, but also slows the
  127. * speed at which tiles are merged as they have to be compiled first.*/
  128. void setDoPreCompile(bool flag) { _doPreCompile = flag; }
  129. /** Get whether the database pager should pre compile OpenGL objects before allowing
  130. * them to be merged into the scene graph.*/
  131. bool getDoPreCompile() const { return _doPreCompile; }
  132. /** Set the target maximum number of PagedLOD to maintain in memory.
  133. * Note, if more than the target number are required for rendering of a frame then these active PagedLOD are excempt from being expiried.
  134. * But once the number of active drops back below the target the inactive PagedLOD will be trimmed back to the target number.*/
  135. void setTargetMaximumNumberOfPageLOD(unsigned int target) { _targetMaximumNumberOfPageLOD = target; }
  136. /** Get the target maximum number of PagedLOD to maintain in memory.*/
  137. unsigned int getTargetMaximumNumberOfPageLOD() const { return _targetMaximumNumberOfPageLOD; }
  138. /** Set whether the removed subgraphs should be deleted in the database thread or not.*/
  139. void setDeleteRemovedSubgraphsInDatabaseThread(bool flag) { _deleteRemovedSubgraphsInDatabaseThread = flag; }
  140. /** Get whether the removed subgraphs should be deleted in the database thread or not.*/
  141. bool getDeleteRemovedSubgraphsInDatabaseThread() const { return _deleteRemovedSubgraphsInDatabaseThread; }
  142. enum DrawablePolicy
  143. {
  144. DO_NOT_MODIFY_DRAWABLE_SETTINGS,
  145. USE_DISPLAY_LISTS,
  146. USE_VERTEX_BUFFER_OBJECTS,
  147. USE_VERTEX_ARRAYS
  148. };
  149. /** Set how loaded drawables should be handled w.r.t their display list/vertex buffer object/vertex array settings.*/
  150. void setDrawablePolicy(DrawablePolicy policy) { _drawablePolicy = policy; }
  151. /** Get how loaded drawables should be handled w.r.t their display list/vertex buffer object/vertex array settings.*/
  152. DrawablePolicy getDrawablePolicy() const { return _drawablePolicy; }
  153. /** Set whether newly loaded textures should have a PixelBufferObject assigned to them to aid download to the GPU.*/
  154. void setApplyPBOToImages(bool assignPBOToImages) { _assignPBOToImages = assignPBOToImages; }
  155. /** Get whether newly loaded textures should have a PixelBufferObject assigned to them.*/
  156. bool getApplyPBOToImages() const { return _assignPBOToImages; }
  157. /** Set whether newly loaded textures should have their UnrefImageDataAfterApply set to a specified value.*/
  158. void setUnrefImageDataAfterApplyPolicy(bool changeAutoUnRef, bool valueAutoUnRef) { _changeAutoUnRef = changeAutoUnRef; _valueAutoUnRef = valueAutoUnRef; }
  159. /** Get whether newly loaded textures should have their UnrefImageDataAfterApply set to a specified value.*/
  160. void getUnrefImageDataAfterApplyPolicy(bool& changeAutoUnRef, bool& valueAutoUnRef) const { changeAutoUnRef = _changeAutoUnRef; valueAutoUnRef = _valueAutoUnRef; }
  161. /** Set whether newly loaded textures should have their MaxAnisotopy set to a specified value.*/
  162. void setMaxAnisotropyPolicy(bool changeAnisotropy, float valueAnisotropy) { _changeAnisotropy = changeAnisotropy; _valueAnisotropy = valueAnisotropy; }
  163. /** Set whether newly loaded textures should have their MaxAnisotopy set to a specified value.*/
  164. void getMaxAnisotropyPolicy(bool& changeAnisotropy, float& valueAnisotropy) const { changeAnisotropy = _changeAnisotropy; valueAnisotropy = _valueAnisotropy; }
  165. /** Return true if there are pending updates to the scene graph that require a call to updateSceneGraph(double). */
  166. bool requiresUpdateSceneGraph() const;
  167. /** Merge the changes to the scene graph by calling calling removeExpiredSubgraphs then addLoadedDataToSceneGraph.
  168. * Note, must only be called from single thread update phase. */
  169. virtual void updateSceneGraph(const osg::FrameStamp& frameStamp);
  170. /** Return true if there are GL objects that need to be compiled by a draw traversal. */
  171. bool requiresRedraw() const;
  172. /** Report how many items are in the _fileRequestList queue */
  173. unsigned int getFileRequestListSize() const { return static_cast<unsigned int>(_fileRequestQueue->size() + _httpRequestQueue->size()); }
  174. /** Report how many items are in the _dataToCompileList queue */
  175. unsigned int getDataToCompileListSize() const { return static_cast<unsigned int>(_dataToCompileList->size()); }
  176. /** Report how many items are in the _dataToMergeList queue */
  177. unsigned int getDataToMergeListSize() const { return static_cast<unsigned int>(_dataToMergeList->size()); }
  178. /** Report whether any requests are in the pager.*/
  179. bool getRequestsInProgress() const;
  180. /** 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.*/
  181. double getMinimumTimeToMergeTile() const { return _minimumTimeToMergeTile; }
  182. /** 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.*/
  183. double getMaximumTimeToMergeTile() const { return _maximumTimeToMergeTile; }
  184. /** 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.*/
  185. double getAverageTimeToMergeTiles() const { return (_numTilesMerges > 0) ? _totalTimeToMergeTiles/static_cast<double>(_numTilesMerges) : 0; }
  186. /** Reset the Stats variables.*/
  187. void resetStats();
  188. typedef std::set< osg::ref_ptr<osg::StateSet> > StateSetList;
  189. typedef std::vector< osg::ref_ptr<osg::Drawable> > DrawableList;
  190. class ExpirePagedLODsVisitor;
  191. typedef std::list< osg::ref_ptr<osg::Object> > ObjectList;
  192. struct PagedLODList : public osg::Referenced
  193. {
  194. virtual PagedLODList* clone() = 0;
  195. virtual void clear() = 0;
  196. virtual unsigned int size() = 0;
  197. virtual void removeExpiredChildren(int numberChildrenToRemove, double expiryTime, unsigned int expiryFrame, ObjectList& childrenRemoved, bool visitActive) = 0;
  198. virtual void removeNodes(osg::NodeList& nodesToRemove) = 0;
  199. virtual void insertPagedLOD(const osg::observer_ptr<osg::PagedLOD>& plod) = 0;
  200. virtual bool containsPagedLOD(const osg::observer_ptr<osg::PagedLOD>& plod) const = 0;
  201. };
  202. void setMarkerObject(osg::Object* mo) { _markerObject = mo; }
  203. osg::Object* getMarkerObject() { return _markerObject.get(); }
  204. const osg::Object* getMarkerObject() const { return _markerObject.get(); }
  205. protected:
  206. virtual ~DatabasePager();
  207. friend class DatabaseThread;
  208. friend struct DatabaseRequest;
  209. struct RequestQueue;
  210. struct OSGDB_EXPORT DatabaseRequest : public osg::Referenced
  211. {
  212. DatabaseRequest():
  213. osg::Referenced(true),
  214. _valid(false),
  215. _frameNumberFirstRequest(0),
  216. _timestampFirstRequest(0.0),
  217. _priorityFirstRequest(0.f),
  218. _frameNumberLastRequest(0),
  219. _timestampLastRequest(0.0),
  220. _priorityLastRequest(0.0f),
  221. _numOfRequests(0),
  222. _groupExpired(false)
  223. {}
  224. void invalidate();
  225. bool valid() const { return _valid; }
  226. bool isRequestCurrent (int frameNumber) const
  227. {
  228. return _valid && (frameNumber - _frameNumberLastRequest <= 1);
  229. }
  230. bool _valid;
  231. std::string _fileName;
  232. unsigned int _frameNumberFirstRequest;
  233. double _timestampFirstRequest;
  234. float _priorityFirstRequest;
  235. unsigned int _frameNumberLastRequest;
  236. double _timestampLastRequest;
  237. float _priorityLastRequest;
  238. unsigned int _numOfRequests;
  239. osg::observer_ptr<osg::Node> _terrain;
  240. osg::observer_ptr<osg::Group> _group;
  241. osg::ref_ptr<osg::Node> _loadedModel;
  242. osg::ref_ptr<Options> _loadOptions;
  243. osg::ref_ptr<ObjectCache> _objectCache;
  244. osg::observer_ptr<osgUtil::IncrementalCompileOperation::CompileSet> _compileSet;
  245. bool _groupExpired; // flag used only in update thread
  246. };
  247. struct OSGDB_EXPORT RequestQueue : public osg::Referenced
  248. {
  249. public:
  250. RequestQueue(DatabasePager* pager);
  251. void add(DatabaseRequest* databaseRequest);
  252. void remove(DatabaseRequest* databaseRequest);
  253. void addNoLock(DatabaseRequest* databaseRequest);
  254. void takeFirst(osg::ref_ptr<DatabaseRequest>& databaseRequest);
  255. /// prune all the old requests and then return true if requestList left empty
  256. bool pruneOldRequestsAndCheckIfEmpty();
  257. virtual void updateBlock() {}
  258. void invalidate(DatabaseRequest* dr);
  259. bool empty();
  260. unsigned int size();
  261. void clear();
  262. typedef std::list< osg::ref_ptr<DatabaseRequest> > RequestList;
  263. void swap(RequestList& requestList);
  264. DatabasePager* _pager;
  265. RequestList _requestList;
  266. OpenThreads::Mutex _requestMutex;
  267. unsigned int _frameNumberLastPruned;
  268. protected:
  269. virtual ~RequestQueue();
  270. };
  271. typedef std::vector< osg::ref_ptr<DatabaseThread> > DatabaseThreadList;
  272. struct OSGDB_EXPORT ReadQueue : public RequestQueue
  273. {
  274. ReadQueue(DatabasePager* pager, const std::string& name);
  275. void block() { _block->block(); }
  276. void release() { _block->release(); }
  277. virtual void updateBlock();
  278. osg::ref_ptr<osg::RefBlock> _block;
  279. std::string _name;
  280. OpenThreads::Mutex _childrenToDeleteListMutex;
  281. ObjectList _childrenToDeleteList;
  282. };
  283. // forward declare inner helper classes
  284. class FindCompileableGLObjectsVisitor;
  285. friend class FindCompileableGLObjectsVisitor;
  286. struct DatabasePagerCompileCompletedCallback;
  287. friend struct DatabasePagerCompileCompletedCallback;
  288. class FindPagedLODsVisitor;
  289. friend class FindPagedLODsVisitor;
  290. struct SortFileRequestFunctor;
  291. friend struct SortFileRequestFunctor;
  292. OpenThreads::Mutex _run_mutex;
  293. OpenThreads::Mutex _dr_mutex;
  294. bool _startThreadCalled;
  295. void compileCompleted(DatabaseRequest* databaseRequest);
  296. /** Iterate through the active PagedLOD nodes children removing
  297. * children which haven't been visited since specified expiryTime.
  298. * note, should be only be called from the update thread. */
  299. virtual void removeExpiredSubgraphs(const osg::FrameStamp &frameStamp);
  300. /** Add the loaded data to the scene graph.*/
  301. void addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp);
  302. OpenThreads::Affinity _affinity;
  303. bool _done;
  304. bool _acceptNewRequests;
  305. bool _databasePagerThreadPaused;
  306. DatabaseThreadList _databaseThreads;
  307. int _numFramesActive;
  308. mutable OpenThreads::Mutex _numFramesActiveMutex;
  309. OpenThreads::Atomic _frameNumber;
  310. osg::ref_ptr<ReadQueue> _fileRequestQueue;
  311. osg::ref_ptr<ReadQueue> _httpRequestQueue;
  312. osg::ref_ptr<RequestQueue> _dataToCompileList;
  313. osg::ref_ptr<RequestQueue> _dataToMergeList;
  314. DrawablePolicy _drawablePolicy;
  315. bool _assignPBOToImages;
  316. bool _changeAutoUnRef;
  317. bool _valueAutoUnRef;
  318. bool _changeAnisotropy;
  319. float _valueAnisotropy;
  320. bool _deleteRemovedSubgraphsInDatabaseThread;
  321. osg::ref_ptr<PagedLODList> _activePagedLODList;
  322. unsigned int _targetMaximumNumberOfPageLOD;
  323. bool _doPreCompile;
  324. osg::ref_ptr<osgUtil::IncrementalCompileOperation> _incrementalCompileOperation;
  325. double _minimumTimeToMergeTile;
  326. double _maximumTimeToMergeTile;
  327. double _totalTimeToMergeTiles;
  328. unsigned int _numTilesMerges;
  329. osg::ref_ptr<osg::Object> _markerObject;
  330. };
  331. }
  332. #endif