diff --git a/include/osgDB/DatabasePager b/include/osgDB/DatabasePager index fbef2e9cc..5992bdd28 100644 --- a/include/osgDB/DatabasePager +++ b/include/osgDB/DatabasePager @@ -156,6 +156,43 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl virtual void registerPagedLODs(osg::Node* subgraph); + /** Set the target frame rate that the DatabasePager should assume. + * Typically one would set this to the value refresh rate of your display system i.e. 60Hz. + * Default value is 100. + * Usage notes. The TargetFrameRate and the MinimumTimeAvailableForGLCompileAndDeletePerFrame + * parameters are not directly used by DatabasePager, but are should be used as a guide for how + * long to set aside per frame for compiling and deleting OpenGL objects - ie. the value to use + * when calling DatabasePager::compileGLObjectgs(state,availableTime,). The longer amount of + * time to set aside cthe faster databases will be paged in but with increased chance of frame drops, + * the lower the amount of time the set aside the slower databases will paged it but with better + * chance of avoid any frame drops. The default values are chosen to achieve the later when running + * on a modern mid to high end PC. + * The way to compute the amount of available time use a scheme such as : + * availableTime = maximum(1.0/targetFrameRate - timeTakenDuringUpdateCullAndDraw, minimumTimeAvailableForGLCompileAndDeletePerFrame). + */ + void setTargetFrameRate(double tfr) { _targetFrameRate = tfr; } + + /** Get the target frame rate that the DatabasePager should assume.*/ + double getTargetFrameRate() const { return _targetFrameRate; } + + /** Set the minimum amount of time (in seconds) that should be made available for compiling and delete OpenGL objects per frame. + * Default value is 0.001 (1 millisecond). + * For usage see notes in setTargetFrameRate.*/ + void setMinimumTimeAvailableForGLCompileAndDeletePerFrame(double ta) { _minimumTimeAvailableForGLCompileAndDeletePerFrame = ta; } + + /** Get the minimum amount of time that should be made available for compiling and delete OpenGL objects per frame. + * For usage see notes in setTargetFrameRate.*/ + double getMinimumTimeAvailableForGLCompileAndDeletePerFrame() const { return _minimumTimeAvailableForGLCompileAndDeletePerFrame; } + + /** Set the maximum number of OpenGL objects that the page should attempt to compile per frame. + * Note, Lower values reduces chances of a frame drop but lower the rate that database will be paged in at. + * Default value is 8. */ + void setMaximumNumOfObjectsToCompilePerFrame(unsigned int num) { _maximumNumOfObjectsToCompilePerFrame = num; } + + /** Get the maximum number of OpenGL objects that the page should attempt to compile per frame.*/ + unsigned int getMaximumNumOfObjectsToCompilePerFrame() const { return _maximumNumOfObjectsToCompilePerFrame; } + + /** Set the amount of time that a subgraph will be kept without being visited in the cull traversal * before being removed.*/ void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; } @@ -327,6 +364,10 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl double _expiryDelay; ActiveGraphicsContexts _activeGraphicsContexts; + + double _targetFrameRate; + double _minimumTimeAvailableForGLCompileAndDeletePerFrame; + unsigned int _maximumNumOfObjectsToCompilePerFrame; }; } diff --git a/src/osgDB/DatabasePager.cpp b/src/osgDB/DatabasePager.cpp index 42e585ffa..2058b207e 100644 --- a/src/osgDB/DatabasePager.cpp +++ b/src/osgDB/DatabasePager.cpp @@ -50,6 +50,10 @@ DatabasePager::DatabasePager() _expiryDelay = 10; + _targetFrameRate = 100.0; + _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms. + _maximumNumOfObjectsToCompilePerFrame = 8; + // make sure a SharedStateManager exists. //osgDB::Registry::instance()->getOrCreateSharedStateManager(); @@ -834,7 +838,7 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime) // while there are valid databaseRequest's in the to compile list and there is // sufficient time left compile each databaseRequest's stateset and drawables. - while (databaseRequest.valid() && elapsedTime_dataToCompileMap; DataToCompile& dtc = dcm[state.getContextID()]; diff --git a/src/osgProducer/OsgSceneHandler.cpp b/src/osgProducer/OsgSceneHandler.cpp index dbf7a0599..4245c8d91 100644 --- a/src/osgProducer/OsgSceneHandler.cpp +++ b/src/osgProducer/OsgSceneHandler.cpp @@ -84,14 +84,53 @@ void OsgSceneHandler::drawImplementation(Producer::Camera &) osgDB::DatabasePager* dp = osgDB::Registry::instance()->getDatabasePager(); if (dp) { + +#if 1 + double timeForCullAndDraw = osg::Timer::instance()->delta_s(_frameStartTick, osg::Timer::instance()->tick()); + + double targeFrameTime = 1.0/dp->getTargetFrameRate(); + + double drawCostFactor = 2.0; // must be greater than 1 to account for the extra cost of emptying the OpenGL fifo. + double frameFactor = 0.9; // must be less than 1, to compensate for extra time spent in update and swap buffers etc. + double timeLeftTillEndOfFrame = targeFrameTime*frameFactor - timeForCullAndDraw*drawCostFactor; + double availableTime = timeLeftTillEndOfFrame / drawCostFactor; // account for the fifo when download texture objects. + + // clamp the available time by the prescribed minimum + if (availableTimegetMinimumTimeAvailableForGLCompileAndDeletePerFrame()) + { + availableTime = dp->getMinimumTimeAvailableForGLCompileAndDeletePerFrame(); + } + + static unsigned int _numFramesThatNoTimeAvailable = 0; + static unsigned int _maxNumFramesThatNoTimeAvailable = 10; + + if (_numFramesThatNoTimeAvailable>_maxNumFramesThatNoTimeAvailable) + { + availableTime = 0.0025; // 2.5ms. + } + + if (availableTime>0.0) + { + _numFramesThatNoTimeAvailable = 0; + + // osg::notify(osg::NOTICE)<<"Time available = "<compileGLObjects(*(getSceneView()->getState()),availableTime); + + // flush deleted GL objects. + getSceneView()->flushDeletedGLObjects(availableTime); + } + else + { + ++_numFramesThatNoTimeAvailable; + } +#else double timeForPreviousFrame = osg::Timer::instance()->delta_s(_previousFrameStartTick, _frameStartTick); double timeForCullAndDraw = osg::Timer::instance()->delta_s(_frameStartTick, osg::Timer::instance()->tick()); double minimumTargetMaxFrameTime = 0.010; // 10ms. double targetMaxFrameTime = osg::minimum(timeForPreviousFrame, minimumTargetMaxFrameTime); - // Unused variable warning - //double maximumAvailableTime = 0.0025; // 2.5ms. double drawCostFactor = 2.0; // must be greater than 1 to account for the extra cost of emptying the OpenGL fifo. double frameFactor = 0.9; // must be less than 1, to compensate for extra time spent in update and swap buffers etc. double timeLeftTillEndOfFrame = targetMaxFrameTime*frameFactor - timeForCullAndDraw*drawCostFactor; @@ -120,7 +159,7 @@ void OsgSceneHandler::drawImplementation(Producer::Camera &) { ++_numFramesThatNoTimeAvailable; } - +#endif dp->signalEndFrame(); } }