Added Stats::collectStats(string,bool) controls, getAveragedAttribute methods into osg::Stats class, and

related support into osgViewer::Viewer and osgViewer::StatsHandler.

Added lazy updating of text in StatsHandler HUD to minimize the impact of
slow text updating on observed frame rates.
This commit is contained in:
Robert Osfield 2007-01-30 11:40:23 +00:00
parent 7b9b13b6c0
commit ecedc8d86a
14 changed files with 253 additions and 26 deletions

View File

@ -27,7 +27,7 @@ class OSG_EXPORT Stats : public osg::Referenced
{
public:
Stats(const std::string& name, unsigned int numberOfFrames=100);
Stats(const std::string& name, unsigned int numberOfFrames=50);
void setName(const std::string& name) { _name = name; }
const std::string& getName() const { return _name; }
@ -43,9 +43,22 @@ class OSG_EXPORT Stats : public osg::Referenced
bool setAttribute(int frameNumber, const std::string& attributeName, double value);
bool getAttribute(int frameNumber, const std::string& attributeName, double& value) const;
bool getAveragedAttribute(const std::string& attributeName, double& value) const;
bool getAveragedAttribute(int startFrameNumber, int endFrameNumber, const std::string& attributeName, double& value) const;
AttributeMap& getAttributeMap(int frameNumber);
const AttributeMap& getAttributeMap(int frameNumber) const;
typedef std::map<std::string, bool> CollectMap;
void collectStats(const std::string& str, bool flag) { _collectMap[str] = flag; }
inline bool collectStats(const std::string& str) const
{
CollectMap::const_iterator itr = _collectMap.find(str);
return (itr != _collectMap.end()) ? itr->second : false;
}
void report(std::ostream& out, const char* indent=0) const ;
void report(std::ostream& out, unsigned int frameNumber, const char* indent=0) const;
@ -73,6 +86,8 @@ class OSG_EXPORT Stats : public osg::Referenced
AttributeMapList _attributeMapList;
AttributeMap _invalidAttributeMap;
CollectMap _collectMap;
};

View File

@ -130,6 +130,9 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View
typedef std::vector<osgViewer::GraphicsWindow*> Windows;
void getWindows(Windows& windows, bool onlyValid=true);
typedef std::vector<osg::Camera*> Cameras;
void getCameras(Cameras& cameras, bool onlyActive=true);
/** Set the graphics operation to call on realization of the viewers graphics windows.*/
void setRealizeOperation(osg::GraphicsOperation* op) { _realizeOperation = op; }

View File

@ -80,6 +80,37 @@ bool Stats::getAttribute(int frameNumber, const std::string& attributeName, doub
return true;
}
bool Stats::getAveragedAttribute(const std::string& attributeName, double& value) const
{
return getAveragedAttribute(getEarliestFrameNumber(), getLatestFrameNumber(), attributeName, value);
}
bool Stats::getAveragedAttribute(int startFrameNumber, int endFrameNumber, const std::string& attributeName, double& value) const
{
if (endFrameNumber<startFrameNumber)
{
std::swap(endFrameNumber, startFrameNumber);
}
double total = 0.0;
double numValidSamples = 0.0;
for(int i = startFrameNumber; i<=endFrameNumber; ++i)
{
double v = 0.0;
if (getAttribute(i,attributeName,v))
{
total += v;
numValidSamples += 1.0;
}
}
if (numValidSamples>0.0)
{
value = total/numValidSamples;
return true;
}
else return false;
}
Stats::AttributeMap& Stats::getAttributeMap(int frameNumber)
{
int index = getIndex(frameNumber);

View File

@ -53,22 +53,50 @@ bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdap
if (_statsType==LAST) _statsType = NO_STATS;
osgViewer::Viewer::Cameras cameras;
viewer->getCameras(cameras);
switch(_statsType)
{
case(NO_STATS):
{
viewer->getStats()->collectStats("frame_rate",false);
viewer->getStats()->collectStats("event",false);
viewer->getStats()->collectStats("update",false);
for(osgViewer::Viewer::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",false);
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",false);
}
_camera->setNodeMask(0x0);
_switch->setAllChildrenOff();
break;
}
case(FRAME_RATE):
{
viewer->getStats()->collectStats("frame_rate",true);
_camera->setNodeMask(0xffffffff);
_switch->setValue(_frameRateChildNum, true);
break;
}
case(VIEWER_STATS):
{
viewer->getStats()->collectStats("event",true);
viewer->getStats()->collectStats("update",true);
for(osgViewer::Viewer::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",true);
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",true);
}
_camera->setNodeMask(0xffffffff);
_switch->setValue(_viewerChildNum, true);
break;
@ -166,17 +194,25 @@ struct TextDrawCallback : public virtual osg::Drawable::DrawCallback
_stats(stats),
_attributeName(name),
_frameDelta(frameDelta),
_multiplier(multiplier) {}
_multiplier(multiplier),
_tickLastUpdated(0)
{
_tickLastUpdated = osg::Timer::instance()->tick();
}
/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osgText::Text* text = (osgText::Text*)drawable;
int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);
if (delta>50) // update every 50ms
{
_tickLastUpdated = tick;
double value;
if (_stats->getAttribute( frameNumber+_frameDelta, _attributeName, value))
if (_stats->getAveragedAttribute( _attributeName, value))
{
sprintf(_tmpText,"%4.2f",value * _multiplier);
text->setText(_tmpText);
@ -185,6 +221,7 @@ struct TextDrawCallback : public virtual osg::Drawable::DrawCallback
{
text->setText("");
}
}
text->drawImplementation(renderInfo);
}
@ -194,6 +231,7 @@ struct TextDrawCallback : public virtual osg::Drawable::DrawCallback
int _frameDelta;
double _multiplier;
mutable char _tmpText[128];
mutable osg::Timer_t _tickLastUpdated;
};
struct BlockDrawCallback : public virtual osg::Drawable::DrawCallback

View File

@ -467,6 +467,22 @@ void Viewer::getWindows(Windows& windows, bool onlyValid)
}
}
void Viewer::getCameras(Cameras& cameras, bool onlyActive)
{
cameras.clear();
if (onlyActive || _camera->getGraphicsContext()) cameras.push_back(_camera.get());
for(Slaves::iterator itr = _slaves.begin();
itr != _slaves.end();
++itr)
{
if (onlyActive || itr->_camera->getGraphicsContext()) cameras.push_back(itr->_camera.get());
}
}
// Draw operation, that does a draw on the scene graph.
struct ViewerRenderingOperation : public osg::GraphicsOperation
{
@ -476,6 +492,7 @@ struct ViewerRenderingOperation : public osg::GraphicsOperation
_databasePager(databasePager),
_startTick(startTick),
_initialized(false),
_timerQuerySupported(false),
_aquireGPUStats(false),
_extensions(0)
{
@ -565,12 +582,11 @@ struct ViewerRenderingOperation : public osg::GraphicsOperation
{
_initialized = true;
_extensions = stats ? osg::Drawable::getExtensions(state->getContextID(),true) : 0;
_aquireGPUStats = _extensions && _extensions->isTimerQuerySupported();
_timerQuerySupported = _extensions && _extensions->isTimerQuerySupported();
_previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
}
// _aquireGPUStats = false;
_aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu");
if (_aquireGPUStats)
{
@ -612,7 +628,7 @@ struct ViewerRenderingOperation : public osg::GraphicsOperation
osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();
if (stats)
if (stats && stats->collectStats("rendering"))
{
stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick));
stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick));
@ -631,6 +647,7 @@ struct ViewerRenderingOperation : public osg::GraphicsOperation
osg::Timer_t _startTick;
bool _initialized;
bool _timerQuerySupported;
bool _aquireGPUStats;
const osg::Drawable::Extensions* _extensions;
QueryFrameNumberList _queryFrameNumberList;
@ -864,7 +881,7 @@ void Viewer::advance(double simulationTime)
_frameStamp->setSimulationTime(simulationTime);
}
if (getStats())
if (getStats() && getStats()->collectStats("frame_rate"))
{
// update previous frame stats
double deltaFrameTime = _frameStamp->getReferenceTime() - prevousReferenceTime;
@ -1153,7 +1170,7 @@ void Viewer::eventTraversal()
}
if (getStats())
if (getStats() && getStats()->collectStats("event"))
{
double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
@ -1181,7 +1198,7 @@ void Viewer::updateTraversal()
updateSlaves();
if (getStats())
if (getStats() && getStats()->collectStats("update"))
{
double endUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
@ -1275,7 +1292,7 @@ void Viewer::renderingTraversals()
dp->signalEndFrame();
}
if (getStats())
if (getStats() && getStats()->collectStats("update"))
{
double endRenderingTraversals = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());

View File

@ -438,6 +438,26 @@ BEGIN_OBJECT_REFLECTOR(osg::State)
__bool__getAbortRendering,
"Get flag for early termination of the draw traversal, if true steps should be taken to complete rendering early. ",
"");
I_Method1(void, setDynamicObjectRenderingCompletedCallback, IN, osg::State::DynamicObjectRenderingCompletedCallback *, cb,
__void__setDynamicObjectRenderingCompletedCallback__DynamicObjectRenderingCompletedCallback_P1,
"Set the callback to be called when the dynamic object count hits 0. ",
"");
I_Method0(osg::State::DynamicObjectRenderingCompletedCallback *, getDynamicObjectRenderingCompletedCallback,
__DynamicObjectRenderingCompletedCallback_P1__getDynamicObjectRenderingCompletedCallback,
"Get the callback to be called when the dynamic object count hits 0. ",
"");
I_MethodWithDefaults2(void, setDynamicObjectCount, IN, unsigned int, count, , IN, bool, callCallbackOnZero, false,
__void__setDynamicObjectCount__unsigned_int__bool,
"Set the number of dynamic objects that will be rendered in this graphics context this frame. ",
"");
I_Method0(unsigned int, getDynamicObjectCount,
__unsigned_int__getDynamicObjectCount,
"Get the number of dynamic objects that will be rendered in this graphics context this frame. ",
"");
I_Method0(void, decrementDynamicObjectCount,
__void__decrementDynamicObjectCount,
"Decrement the number of dynamic objects left to render this frame, and once the count goes to zero call the DynamicObjectRenderingCompletedCallback to inform of completion. ",
"");
I_Method1(void, setCheckForGLErrors, IN, osg::State::CheckForGLErrors, check,
__void__setCheckForGLErrors__CheckForGLErrors,
"Set whether and how often OpenGL errors should be checked for. ",
@ -482,6 +502,12 @@ BEGIN_OBJECT_REFLECTOR(osg::State)
I_SimpleProperty(osg::DisplaySettings *, DisplaySettings,
0,
__void__setDisplaySettings__DisplaySettings_P1);
I_SimpleProperty(unsigned int, DynamicObjectCount,
__unsigned_int__getDynamicObjectCount,
0);
I_SimpleProperty(osg::State::DynamicObjectRenderingCompletedCallback *, DynamicObjectRenderingCompletedCallback,
__DynamicObjectRenderingCompletedCallback_P1__getDynamicObjectRenderingCompletedCallback,
__void__setDynamicObjectRenderingCompletedCallback__DynamicObjectRenderingCompletedCallback_P1);
I_SimpleProperty(osg::FrameStamp *, FrameStamp,
0,
__void__setFrameStamp__FrameStamp_P1);
@ -529,5 +555,16 @@ BEGIN_OBJECT_REFLECTOR(osg::State)
0);
END_REFLECTOR
BEGIN_ABSTRACT_OBJECT_REFLECTOR(osg::State::DynamicObjectRenderingCompletedCallback)
I_BaseType(osg::Referenced);
I_Constructor0(____DynamicObjectRenderingCompletedCallback,
"",
"");
I_Method1(void, completed, IN, osg::State *, x,
__void__completed__osg_State_P1,
"",
"");
END_REFLECTOR
STD_VECTOR_REFLECTOR(std::vector< const osg::StateSet * >);

View File

@ -78,6 +78,7 @@ BEGIN_ENUM_REFLECTOR(osgUtil::Optimizer::OptimizationOptions)
I_EnumLabel(osgUtil::Optimizer::MERGE_GEODES);
I_EnumLabel(osgUtil::Optimizer::FLATTEN_BILLBOARDS);
I_EnumLabel(osgUtil::Optimizer::TEXTURE_ATLAS_BUILDER);
I_EnumLabel(osgUtil::Optimizer::STATIC_OBJECT_DETECTION);
I_EnumLabel(osgUtil::Optimizer::DEFAULT_OPTIMIZATIONS);
I_EnumLabel(osgUtil::Optimizer::ALL_OPTIMIZATIONS);
END_REFLECTOR
@ -500,6 +501,22 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::Optimizer::StateVisitor)
"");
END_REFLECTOR
BEGIN_OBJECT_REFLECTOR(osgUtil::Optimizer::StaticObjectDetectionVisitor)
I_BaseType(osgUtil::BaseOptimizerVisitor);
I_ConstructorWithDefaults1(IN, osgUtil::Optimizer *, optimizer, 0,
____StaticObjectDetectionVisitor__Optimizer_P1,
"default to traversing all children. ",
"");
I_Method1(void, apply, IN, osg::Node &, node,
__void__apply__osg_Node_R1,
"",
"");
I_Method1(void, apply, IN, osg::Geode &, geode,
__void__apply__osg_Geode_R1,
"",
"");
END_REFLECTOR
TYPE_NAME_ALIAS(std::set< osg::Group * >, osgUtil::Optimizer::TessellateVisitor::GroupList);
BEGIN_OBJECT_REFLECTOR(osgUtil::Optimizer::TessellateVisitor)

View File

@ -217,6 +217,10 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::RenderBin)
__bool__getStats__Statistics_R1,
"Extract stats for current draw list. ",
"");
I_Method0(unsigned int, computeNumberOfDynamicRenderLeaves,
__unsigned_int__computeNumberOfDynamicRenderLeaves,
"Compute the number of dynamic RenderLeaves. ",
"");
I_Method0(void, copyLeavesFromStateGraphListToRenderLeafList,
__void__copyLeavesFromStateGraphListToRenderLeafList,
"",

View File

@ -48,5 +48,6 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::RenderLeaf)
I_PublicMemberProperty(osg::ref_ptr< osg::RefMatrix >, _projection);
I_PublicMemberProperty(osg::ref_ptr< osg::RefMatrix >, _modelview);
I_PublicMemberProperty(float, _depth);
I_PublicMemberProperty(bool, _dynamic);
END_REFLECTOR

View File

@ -306,6 +306,10 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::RenderStage)
__bool__getStats__Statistics_R1,
"Extract stats for current draw list. ",
"");
I_Method0(unsigned int, computeNumberOfDynamicRenderLeaves,
__unsigned_int__computeNumberOfDynamicRenderLeaves,
"Compute the number of dynamic RenderLeaves. ",
"");
I_Method2(void, attach, IN, osg::Camera::BufferComponent, buffer, IN, osg::Image *, image,
__void__attach__osg_Camera_BufferComponent__osg_Image_P1,
"",

View File

@ -123,6 +123,7 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::StateGraph)
I_PublicMemberProperty(float, _averageDistance);
I_PublicMemberProperty(float, _minimumDistance);
I_PublicMemberProperty(osg::ref_ptr< osg::Referenced >, _userData);
I_PublicMemberProperty(bool, _dynamic);
END_REFLECTOR
BEGIN_VALUE_REFLECTOR(osg::ref_ptr< osgUtil::RenderLeaf >)

View File

@ -12,6 +12,7 @@
#include <osg/Camera>
#include <osg/FrameStamp>
#include <osg/GraphicsThread>
#include <osg/Timer>
#include <osgGA/EventQueue>
#include <osgViewer/CompositeViewer>
@ -203,17 +204,25 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::CompositeViewer)
__void__getScenes__Scenes_R1__bool,
"",
"");
I_Method1(void, setRealizeOperation, IN, osg::GraphicsOperation *, op,
__void__setRealizeOperation__osg_GraphicsOperation_P1,
"Set the graphics operation to call on realization of the viewers graphics windows. ",
"");
I_Method0(osg::GraphicsOperation *, getRealizeOperation,
__osg_GraphicsOperation_P1__getRealizeOperation,
"Get the graphics operation to call on realization of the viewers graphics windows. ",
"");
I_Method0(void, stopThreading,
__void__stopThreading,
"",
"Stop any threads begin run by viewer. ",
"");
I_Method0(void, startThreading,
__void__startThreading,
"",
"Start any threads required by the viewer, as per viewers ThreadingModel. ",
"");
I_Method0(void, setUpRenderingSupport,
__void__setUpRenderingSupport,
"",
"Set up the GraphicsOperations to render the various viewer cameras on the viewers graphics windows. ",
"");
I_SimpleProperty(osg::Camera *, CameraWithFocus,
__osg_Camera_P1__getCameraWithFocus,
@ -236,6 +245,9 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::CompositeViewer)
I_SimpleProperty(bool, QuitEventSetsDone,
__bool__getQuitEventSetsDone,
__void__setQuitEventSetsDone__bool);
I_SimpleProperty(osg::GraphicsOperation *, RealizeOperation,
__osg_GraphicsOperation_P1__getRealizeOperation,
__void__setRealizeOperation__osg_GraphicsOperation_P1);
I_SimpleProperty(double, ReferenceTime,
0,
__void__setReferenceTime__double);

View File

@ -13,6 +13,7 @@
#include <osg/Camera>
#include <osg/DisplaySettings>
#include <osg/Node>
#include <osg/State>
#include <osgGA/EventQueue>
#include <osgGA/GUIEventHandler>
#include <osgGA/MatrixManipulator>
@ -28,6 +29,29 @@
#undef OUT
#endif
BEGIN_OBJECT_REFLECTOR(osgViewer::EndOfDynamicDrawBlock)
I_BaseType(osg::State::DynamicObjectRenderingCompletedCallback);
I_Constructor0(____EndOfDynamicDrawBlock,
"",
"");
I_Method1(void, completed, IN, osg::State *, state,
__void__completed__osg_State_P1,
"",
"");
I_Method0(void, block,
__void__block,
"",
"");
I_Method0(void, release,
__void__release,
"",
"");
I_Method1(void, set, IN, unsigned int, blockCount,
__void__set__unsigned_int,
"",
"");
END_REFLECTOR
TYPE_NAME_ALIAS(std::list< osg::ref_ptr< osgGA::GUIEventHandler > >, osgViewer::View::EventHandlers);
BEGIN_OBJECT_REFLECTOR(osgViewer::View)

View File

@ -12,6 +12,7 @@
#include <osg/Camera>
#include <osg/FrameStamp>
#include <osg/GraphicsThread>
#include <osg/Node>
#include <osg/Timer>
#include <osgViewer/Viewer>
@ -96,6 +97,14 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::Viewer)
__ThreadingModel__getThreadingModel,
"Get the threading model the rendering traversals will use. ",
"");
I_Method1(void, setUseMainThreadForRenderingTraversals, IN, bool, flag,
__void__setUseMainThreadForRenderingTraversals__bool,
"Set whether the main thread, calling frame(), should be used for the rendering traversals. ",
"");
I_Method0(bool, getUseMainThreadForRenderingTraversals,
__bool__getUseMainThreadForRenderingTraversals,
"Get whether the main thread, calling frame(), should be used for the rendering traversals. ",
"");
I_Method1(void, setEndBarrierPosition, IN, osgViewer::Viewer::BarrierPosition, bp,
__void__setEndBarrierPosition__BarrierPosition,
"Set the position of the end barrier. ",
@ -164,17 +173,25 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::Viewer)
__void__getWindows__Windows_R1__bool,
"",
"");
I_Method1(void, setRealizeOperation, IN, osg::GraphicsOperation *, op,
__void__setRealizeOperation__osg_GraphicsOperation_P1,
"Set the graphics operation to call on realization of the viewers graphics windows. ",
"");
I_Method0(osg::GraphicsOperation *, getRealizeOperation,
__osg_GraphicsOperation_P1__getRealizeOperation,
"Get the graphics operation to call on realization of the viewers graphics windows. ",
"");
I_Method0(void, stopThreading,
__void__stopThreading,
"",
"Stop any threads begin run by viewer. ",
"");
I_Method0(void, startThreading,
__void__startThreading,
"",
"Start any threads required by the viewer, as per viewers ThreadingModel. ",
"");
I_Method0(void, setUpRenderingSupport,
__void__setUpRenderingSupport,
"",
"Set up the GraphicsOperations to render the various viewer cameras on the viewers graphics windows. ",
"");
I_SimpleProperty(osg::Camera *, CameraWithFocus,
__osg_Camera_P1__getCameraWithFocus,
@ -194,6 +211,9 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::Viewer)
I_SimpleProperty(bool, QuitEventSetsDone,
__bool__getQuitEventSetsDone,
__void__setQuitEventSetsDone__bool);
I_SimpleProperty(osg::GraphicsOperation *, RealizeOperation,
__osg_GraphicsOperation_P1__getRealizeOperation,
__void__setRealizeOperation__osg_GraphicsOperation_P1);
I_SimpleProperty(double, ReferenceTime,
0,
__void__setReferenceTime__double);
@ -206,5 +226,8 @@ BEGIN_OBJECT_REFLECTOR(osgViewer::Viewer)
I_SimpleProperty(osgViewer::Viewer::ThreadingModel, ThreadingModel,
__ThreadingModel__getThreadingModel,
__void__setThreadingModel__ThreadingModel);
I_SimpleProperty(bool, UseMainThreadForRenderingTraversals,
__bool__getUseMainThreadForRenderingTraversals,
__void__setUseMainThreadForRenderingTraversals__bool);
END_REFLECTOR