From 922dcb04237a14a759df2ea1d66853c712137aca Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 16 Apr 2008 18:13:41 +0000 Subject: [PATCH] Added new computation of time to allocate to flushing deleted and compiling OpenGL objects per frame. --- include/osgViewer/Renderer | 61 ++++++++++++++++-- src/osgViewer/Renderer.cpp | 89 ++++++++++++++++++-------- src/osgWrappers/osgViewer/Renderer.cpp | 66 +++++++++++++++++-- 3 files changed, 180 insertions(+), 36 deletions(-) diff --git a/include/osgViewer/Renderer b/include/osgViewer/Renderer index 958442a0c..d04e9ab63 100644 --- a/include/osgViewer/Renderer +++ b/include/osgViewer/Renderer @@ -15,6 +15,7 @@ #define OSGVIEWER_RENDERER 1 #include +#include #include #include @@ -65,22 +66,72 @@ class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation, public OpenGLQu void setGraphicsThreadDoesCull(bool flag); bool getGraphicsThreadDoesCull() const { return _graphicsThreadDoesCull; } - void cull(); - void draw(); - void cull_draw(); + virtual void cull(); + virtual void draw(); + virtual void cull_draw(); virtual void operator () (osg::Object* object); virtual void operator () (osg::GraphicsContext* context); virtual void release(); + + + /** 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). + * + * Note, the actual TargetFrameRate used is the minimum of this value and that set in the DatabasePager. */ + 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. + * + * Note, the actual TargetFrameRate used is the minimum of this value and that set in the DatabasePager. */ + 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; } + + /** FlushTimeRatio governs how much of the spare time in each frame is used for flushing deleted OpenGL objects. + * Default value is 0.5, valid range is 0.1 to 0.9.*/ + void setFlushTimeRatio(double ratio) { _flushTimeRatio = ratio; } + double getFlushTimeRatio() const { return _flushTimeRatio; } + + /** ConservativeTimeRatio governs how much of the measured spare time in each frame is used for flushing deleted and compile new OpenGL objects. + * Default value is 0.5, valid range is 0.1 to 1.0. + * A ratio near 1.0 will lead to paged databases being compiled and merged quicker but increase the chances of frame drop. + * A ratio near 0.1 will lead to paged databases being compiled and merged closer but reduse the chances of frame drop.*/ + void setConservativeTimeRatio(double ratio) { _conservativeTimeRatio = ratio; } + double getConservativeTimeRatio() const { return _conservativeTimeRatio; } protected: - void updateSceneView(osgUtil::SceneView* sceneView); - virtual ~Renderer(); + virtual void updateSceneView(osgUtil::SceneView* sceneView); + virtual void flushAndCompile(double currentElapsedFrameTime, osgUtil::SceneView* sceneView, osgDB::DatabasePager* databasePager, osg::GraphicsThread* compileThread); + + double _targetFrameRate; + double _minimumTimeAvailableForGLCompileAndDeletePerFrame; + double _flushTimeRatio; + double _conservativeTimeRatio; + osg::observer_ptr _camera; bool _done; diff --git a/src/osgViewer/Renderer.cpp b/src/osgViewer/Renderer.cpp index 3a88a6166..66636c2b5 100644 --- a/src/osgViewer/Renderer.cpp +++ b/src/osgViewer/Renderer.cpp @@ -161,6 +161,10 @@ static OpenThreads::Mutex s_drawSerializerMutex; Renderer::Renderer(osg::Camera* camera): osg::GraphicsOperation("Renderer",true), OpenGLQuerySupport(), + _targetFrameRate(100.0), + _minimumTimeAvailableForGLCompileAndDeletePerFrame(0.001), + _flushTimeRatio(0.5), + _conservativeTimeRatio(0.5), _camera(camera), _done(false), _graphicsThreadDoesCull(true) @@ -389,22 +393,13 @@ void Renderer::draw() _availableQueue.add(sceneView); - double availableTime = 0.004; // 4 ms + osg::Timer_t afterDispatchTick = osg::Timer::instance()->tick(); - if (compileThread) - { - compileThread->add(_flushOperation.get()); - } - else - { - sceneView->flushDeletedGLObjects(availableTime); - } - - if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID())) - { - databasePager->compileGLObjects(*(sceneView->getState()), availableTime); - } + double dispatchTime = osg::Timer::instance()->delta_s(beforeDrawTick, afterDispatchTick); + // now flush delete OpenGL objects and compile any objects as required by the DatabasePager + flushAndCompile(dispatchTime, sceneView, databasePager, compileThread); + if (acquireGPUStats) { endQuery(); @@ -512,20 +507,12 @@ void Renderer::cull_draw() sceneView->draw(); } - double availableTime = 0.004; // 4 ms - if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID())) - { - databasePager->compileGLObjects(*(sceneView->getState()), availableTime); - } + osg::Timer_t afterDispatchTick = osg::Timer::instance()->tick(); + double cullAndDispatchTime = osg::Timer::instance()->delta_s(beforeCullTick, afterDispatchTick); + + // now flush delete OpenGL objects and compile any objects as required by the DatabasePager + flushAndCompile(cullAndDispatchTime, sceneView, databasePager, compileThread); - if (compileThread) - { - compileThread->add(_flushOperation.get()); - } - else - { - sceneView->flushDeletedGLObjects(availableTime); - } if (acquireGPUStats) { @@ -552,6 +539,54 @@ void Renderer::cull_draw() } +void Renderer::flushAndCompile(double currentElapsedFrameTime, osgUtil::SceneView* sceneView, osgDB::DatabasePager* databasePager, osg::GraphicsThread* compileThread) +{ + + double targetFrameRate = _targetFrameRate; + double minimumTimeAvailableForGLCompileAndDeletePerFrame = _minimumTimeAvailableForGLCompileAndDeletePerFrame; + + if (databasePager) + { + targetFrameRate = std::min(targetFrameRate, databasePager->getTargetFrameRate()); + minimumTimeAvailableForGLCompileAndDeletePerFrame = std::min(minimumTimeAvailableForGLCompileAndDeletePerFrame, databasePager->getMinimumTimeAvailableForGLCompileAndDeletePerFrame()); + } + + double targetFrameTime = 1.0/targetFrameRate; + + double availableTime = std::max((targetFrameTime - currentElapsedFrameTime)*_conservativeTimeRatio, + minimumTimeAvailableForGLCompileAndDeletePerFrame); + + double flushTime = availableTime * _flushTimeRatio; + double compileTime = availableTime - flushTime; + +#if 0 + osg::notify(osg::NOTICE)<<"total availableTime = "<)