Introduce new run frame rate management support to allow control of maximum frame rate and to support on demand rendering of frames

This commit is contained in:
Robert Osfield 2009-04-24 16:20:50 +00:00
parent 860ae27faf
commit a50f0ccfaf
10 changed files with 198 additions and 57 deletions

View File

@ -73,9 +73,9 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
const osg::FrameStamp* getFrameStamp() const { return _frameStamp.get(); }
virtual double elapsedTime();
virtual osg::FrameStamp* getViewerFrameStamp() { return getFrameStamp(); }
/** Execute a main frame loop.
* Equivalent to while (!viewer.done()) viewer.frame();
@ -84,17 +84,20 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
*/
virtual int run();
/** check to see if the new frame is required, called by run(..) when FrameScheme is set to ON_DEMAND.*/
virtual bool checkNeedToDoFrame();
virtual void advance(double simulationTime=USE_REFERENCE_TIME);
virtual void eventTraversal();
virtual void updateTraversal();
void setCameraWithFocus(osg::Camera* camera);
osg::Camera* getCameraWithFocus() { return _cameraWithFocus.get(); }
const osg::Camera* getCameraWithFocus() const { return _cameraWithFocus.get(); }
osgViewer::View* getViewWithFocus() { return _viewWithFocus.get(); }
const osgViewer::View* getViewWithFocus() const { return _viewWithFocus.get(); }

View File

@ -233,6 +233,7 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter
osg::ref_ptr<osg::DisplaySettings> _displaySettings;
osgUtil::SceneView::FusionDistanceMode _fusionDistanceMode;
float _fusionDistanceValue;
};
}

View File

@ -35,7 +35,7 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
Viewer(const osgViewer::Viewer& viewer, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
virtual ~Viewer();
META_Object(osgViewer,Viewer);
/** Take all the settings, Camera and Slaves from the passed in view(er), leaving it empty. */
@ -74,9 +74,8 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
virtual double elapsedTime();
virtual osg::FrameStamp* getViewerFrameStamp() { return getFrameStamp(); }
virtual osg::FrameStamp* getViewerFrameStamp() { return getFrameStamp(); }
/** Execute a main frame loop.
* Equivalent to while (!viewer.done()) viewer.frame();
@ -85,18 +84,21 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
*/
virtual int run();
/** check to see if the new frame is required, called by run(..) when FrameScheme is set to ON_DEMAND.*/
virtual bool checkNeedToDoFrame();
virtual void advance(double simulationTime=USE_REFERENCE_TIME);
virtual void eventTraversal();
virtual void updateTraversal();
void setCameraWithFocus(osg::Camera* camera) { _cameraWithFocus = camera; }
osg::Camera* getCameraWithFocus() { return _cameraWithFocus.get(); }
const osg::Camera* getCameraWithFocus() const { return _cameraWithFocus.get(); }
virtual void getCameras(Cameras& cameras, bool onlyActive=true);
virtual void getContexts(Contexts& contexts, bool onlyValid=true);
virtual void getAllThreads(Threads& threads, bool onlyActive=true);

View File

@ -199,14 +199,27 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
/** Check to see if windows are still open, if not set viewer done to true. */
void checkWindowStatus();
enum FrameScheme
{
ON_DEMAND,
CONTINUOUS
};
void setRunFrameScheme(FrameScheme fs) { _runFrameScheme = fs; }
FrameScheme getRunFrameScheme() const { return _runFrameScheme; }
void setRunMaxFrameRate(double frameRate) { _runMaxFrameRate = frameRate; }
double getRunMaxFrameRate() const { return _runMaxFrameRate; }
/** Execute a main frame loop.
* Equivalent to while (!viewer.done()) viewer.frame();
* Also calls realize() if the viewer is not already realized,
* and installs trackball manipulator if one is not already assigned.
*/
virtual int run() = 0;
virtual int run();
/** check to see if the new frame is required, called by run(..) when FrameScheme is set to ON_DEMAND.*/
virtual bool checkNeedToDoFrame() = 0;
/** Render a complete new frame.
* Calls advance(), eventTraversal(), updateTraversal(), renderingTraversals(). */
@ -249,16 +262,20 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
virtual void getUsage(osg::ApplicationUsage& usage) const = 0;
protected:
void viewerBaseInit();
friend class osgViewer::View;
inline void makeCurrent(osg::GraphicsContext* gc)
{
if (_currentContext==gc) return;
releaseContext();
if (gc && gc->valid() && gc->makeCurrent()) _currentContext = gc;
}
inline void releaseContext()
{
if (_currentContext.valid() && _currentContext->valid())
@ -275,21 +292,28 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
int _keyEventSetsDone;
bool _quitEventSetsDone;
bool _releaseContextAtEndOfFrameHint;
ThreadingModel _threadingModel;
bool _threadsRunning;
bool _requestRedraw;
bool _requestContinousUpdate;
FrameScheme _runFrameScheme;
double _runMaxFrameRate;
BarrierPosition _endBarrierPosition;
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
osg::ref_ptr<osg::EndOfDynamicDrawBlock> _endDynamicDrawBlock;
osg::ref_ptr<osgGA::EventVisitor> _eventVisitor;
osg::ref_ptr<osg::OperationQueue> _updateOperations;
osg::ref_ptr<osgUtil::UpdateVisitor> _updateVisitor;
osg::ref_ptr<osg::Operation> _realizeOperation;
osg::ref_ptr<osgUtil::IncrementalCompileOperation> _incrementalCompileOperation;

View File

@ -37,7 +37,17 @@ CompositeViewer::CompositeViewer(const CompositeViewer& cv,const osg::CopyOp& co
CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments)
{
constructorInit();
arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required.");
arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously.");
arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissable frame rate, 0.0 is default and switching off frame rate capping.");
std::string filename;
bool readConfig = false;
while (arguments.read("-c",filename))
@ -50,6 +60,14 @@ CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments)
while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext);
while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext);
while(arguments.read("--run-on-demand")) { setRunFrameScheme(ON_DEMAND); }
while(arguments.read("--run-continuous")) { setRunFrameScheme(CONTINUOUS); }
double runMaxFrameRate;
while(arguments.read("--run-max-frame-rate", runMaxFrameRate)) { setRunMaxFrameRate(runMaxFrameRate); }
osg::DisplaySettings::instance()->readCommandLine(arguments);
osgDB::readCommandLine(arguments);
}
@ -222,6 +240,34 @@ bool CompositeViewer::isRealized() const
return numRealizedWindows > 0;
}
bool CompositeViewer::checkNeedToDoFrame()
{
if (_requestRedraw) return true;
if (_requestContinousUpdate) return true;
for(RefViews::iterator itr = _views.begin();
itr != _views.end();
++itr)
{
osgViewer::View* view = itr->get();
if (view)
{
// If the database pager is going to update the scene the render flag is
// set so that the updates show up
if (view->getDatabasePager()->requiresUpdateSceneGraph() ||
view->getDatabasePager()->getRequestsInProgress()) return true;
}
}
// now do a eventTraversal to see if any events might require a new frame.
eventTraversal();
if (_requestRedraw) return true;
if (_requestContinousUpdate) return true;
return false;
}
int CompositeViewer::run()
{
for(RefViews::iterator itr = _views.begin();

View File

@ -183,7 +183,7 @@ bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdap
break;
}
aa.requestRedraw();
}
return true;
}

View File

@ -1696,10 +1696,12 @@ void View::assignSceneDataToCameras()
void View::requestRedraw()
{
getViewerBase()->_requestRedraw = true;
}
void View::requestContinuousUpdate(bool)
void View::requestContinuousUpdate(bool flag)
{
getViewerBase()->_requestContinousUpdate = flag;
}
void View::requestWarpPointer(float x,float y)

View File

@ -53,6 +53,11 @@ Viewer::Viewer(osg::ArgumentParser& arguments)
arguments.getApplicationUsage()->addCommandLineOption("--clear-color <color>","Set the background color of the viewer in the form \"r,g,b[,a]\".");
arguments.getApplicationUsage()->addCommandLineOption("--screen <num>","Set the screen to use when multiple screens are present.");
arguments.getApplicationUsage()->addCommandLineOption("--window <x y w h>","Set the position (x,y) and size (w,h) of the viewer window.");
arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required.");
arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously.");
arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissable frame rate, 0.0 is default and switching off frame rate capping.");
// FIXME: Uncomment these lines when the options have been documented properly
//arguments.getApplicationUsage()->addCommandLineOption("--3d-sd","");
//arguments.getApplicationUsage()->addCommandLineOption("--panoramic-sd","");
@ -84,13 +89,21 @@ Viewer::Viewer(osg::ArgumentParser& arguments)
if( cnt==3 || cnt==4 ) getCamera()->setClearColor( osg::Vec4(r,g,b,a) );
else osg::notify(osg::WARN)<<"Invalid clear color \""<<colorStr<<"\""<<std::endl;
}
while(arguments.read("--run-on-demand")) { setRunFrameScheme(ON_DEMAND); }
while(arguments.read("--run-continuous")) { setRunFrameScheme(CONTINUOUS); }
double runMaxFrameRate;
while(arguments.read("--run-max-frame-rate", runMaxFrameRate)) { setRunMaxFrameRate(runMaxFrameRate); }
int screenNum = -1;
while (arguments.read("--screen",screenNum)) {}
int x = -1, y = -1, width = -1, height = -1;
while (arguments.read("--window",x,y,width,height)) {}
bool ss3d = false;
bool wowvx20 = false;
bool wowvx42 = false;
@ -309,22 +322,40 @@ bool Viewer::isRealized() const
return numRealizedWindows > 0;
}
bool Viewer::checkNeedToDoFrame()
{
if (_requestRedraw) return true;
if (_requestContinousUpdate) return true;
// If the database pager is going to update the scene the render flag is
// set so that the updates show up
if(getDatabasePager()->requiresUpdateSceneGraph() || getDatabasePager()->getRequestsInProgress()) return true;
// now do a eventTraversal to see if any events might require a new frame.
eventTraversal();
if (_requestRedraw) return true;
if (_requestContinousUpdate) return true;
return false;
}
int Viewer::run()
{
if (!getCameraManipulator() && getCamera()->getAllowEventFocus())
{
setCameraManipulator(new osgGA::TrackballManipulator());
}
setReleaseContextAtEndOfFrameHint(false);
return ViewerBase::run();
}
void Viewer::setStartTick(osg::Timer_t tick)
{
View::setStartTick(tick);
Contexts contexts;
getContexts(contexts,false);

View File

@ -33,25 +33,24 @@ static osg::ApplicationUsageProxy ViewerBase_e0(osg::ApplicationUsage::ENVIRONME
static osg::ApplicationUsageProxy ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING <value>","Set the threading model using by Viewer, <value> can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext.");
static osg::ApplicationUsageProxy ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN <value>","Set the default screen that windows should open up on.");
static osg::ApplicationUsageProxy ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on.");
static osg::ApplicationUsageProxy ViewerBase_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_FRAME_SCHEME","Frame rate manage scheme that viewer run should use, ON_DEMAND or CONTINUOUS (default).");
static osg::ApplicationUsageProxy ViewerBase_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_MAX_FRAME_RATE","Set the maximum number of frame as second that viewer run. 0.0 is default and disables an frame rate capping.");
using namespace osgViewer;
ViewerBase::ViewerBase():
osg::Object(true)
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_releaseContextAtEndOfFrameHint = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
viewerBaseInit();
}
ViewerBase::ViewerBase(const ViewerBase& base):
osg::Object(true)
{
viewerBaseInit();
}
void ViewerBase::viewerBaseInit()
{
_firstFrame = true;
_done = false;
@ -61,6 +60,24 @@ ViewerBase::ViewerBase(const ViewerBase& base):
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
_requestRedraw = true;
_requestContinousUpdate = false;
_runFrameScheme = CONTINUOUS;
_runMaxFrameRate = 0.0f;
const char* str = getenv("OSG_RUN_FRAME_SCHEME");
if (str)
{
if (strcmp(str, "ON_DEMAND")==0) _runFrameScheme = ON_DEMAND;
else if (strcmp(str, "CONTINUOUS")==0) _runFrameScheme = CONTINUOUS;
}
str = getenv("OSG_RUN_MAX_FRAME_RATE");
if (str)
{
_runMaxFrameRate = atof(str);
}
}
void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
@ -573,30 +590,28 @@ int ViewerBase::run()
realize();
}
#if 0
while (!done())
{
frame();
}
#else
const char* str = getenv("OSG_RUN_FRAME_COUNT");
if (str)
int runTillFrameNumber = str==0 ? -1 : atoi(str);
while(!done() || (runTillFrameNumber>=0 && getViewerFrameStamp()->getFrameNumber()>runTillFrameNumber))
{
int runTillFrameNumber = atoi(str);
while (!done() && getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber)
double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
if (_runFrameScheme==ON_DEMAND)
{
if (checkNeedToDoFrame()) frame();
}
else
{
frame();
}
// work out if we need to force a sleep to hold back the frame rate
osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(1000000.0*(minFrameTime-frameTime));
}
else
{
while (!done())
{
frame();
}
}
#endif
return 0;
}
@ -842,5 +857,7 @@ void ViewerBase::renderingTraversals()
getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
_requestRedraw = false;
}

View File

@ -100,6 +100,8 @@ bool WindowSizeHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActio
{
toggleFullscreen(*itr);
}
aa.requestRedraw();
return true;
}
else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionUp)
@ -114,6 +116,8 @@ bool WindowSizeHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActio
{
changeWindowedResolution(*itr, true);
}
aa.requestRedraw();
return true;
}
else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionDown)
@ -128,6 +132,8 @@ bool WindowSizeHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActio
{
changeWindowedResolution(*itr, false);
}
aa.requestRedraw();
return true;
}
break;
@ -317,6 +323,7 @@ bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIAction
if (_changeThreadingModel == true && ea.getKey() == _keyEventChangeThreadingModel && delta > 1.0)
{
_tickOrLastKeyPress = osg::Timer::instance()->tick();
switch(viewerBase->getThreadingModel())
@ -348,6 +355,8 @@ bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIAction
#endif
break;
}
aa.requestRedraw();
return true;
}
if (viewer && _changeEndBarrierPosition == true && ea.getKey() == _keyEventChangeEndBarrierPosition)
@ -363,6 +372,8 @@ bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIAction
osg::notify(osg::NOTICE)<<"Threading model 'BeforeSwapBuffers' selected."<<std::endl;
break;
}
aa.requestRedraw();
return true;
}
break;
@ -575,6 +586,8 @@ bool LODScaleHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionA
{
camera->setLODScale(camera->getLODScale()*1.1);
osg::notify(osg::NOTICE)<<"LODScale = "<<camera->getLODScale()<<std::endl;
aa.requestRedraw();
return true;
}
@ -582,8 +595,10 @@ bool LODScaleHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionA
{
camera->setLODScale(camera->getLODScale()/1.1);
osg::notify(osg::NOTICE)<<"LODScale = "<<camera->getLODScale()<<std::endl;
aa.requestRedraw();
return true;
}
}
break;
}