Hi Robert,
attaching improved StatsVisitor. Changes:
- apply() and reset() methods made virtual to allow overriding
- added apply(StateSet&) to make more easier to gather StateAttribute
statistics in user-derived classes
I adjusted the code formatting on some places as well. Cheers,
John
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGUTIL_STATISTICS
#define OSGUTIL_STATISTICS 1
#include <osgUtil/Export>
#include <osg/PrimitiveSet>
#include <osg/Drawable>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/LOD>
#include <osg/Switch>
#include <osg/Geometry>
#include <osg/Transform>
#include <map>
#include <set>
#include <ostream>
namespace osgUtil {
/**
* Statistics base class. Used to extract primitive information from
* the renderBin(s). Add a case of getStats(osgUtil::Statistics *stat)
* for any new drawable (or drawable derived class) that you generate
* (eg see Geometry.cpp). There are 20 types of drawable counted - actually only
* 14 cases can occur in reality. these represent sets of GL_POINTS, GL_LINES
* GL_LINESTRIPS, LOOPS, TRIANGLES, TRI-fans, tristrips, quads, quadstrips etc
* The number of triangles rendered is inferred:
* each triangle = 1 triangle (number of vertices/3)
* each quad = 2 triangles (nverts/2)
* each trifan or tristrip = (length-2) triangles and so on.
*/
class OSGUTIL_EXPORT Statistics : public osg::PrimitiveFunctor
{
public:
typedef std::pair<unsigned int,unsigned int> PrimitivePair;
typedef std::map<GLenum,PrimitivePair> PrimitiveValueMap;
typedef std::map<GLenum, unsigned int> PrimitiveCountMap;
Statistics();
enum StatsType
{
STAT_NONE, // default
STAT_FRAMERATE,
STAT_GRAPHS,
STAT_PRIMS,
STAT_PRIMSPERVIEW,
STAT_PRIMSPERBIN,
STAT_DC,
STAT_RESTART // hint to restart the stats
};
void reset();
void setType(StatsType t) { stattype=t; }
virtual void setVertexArray(unsigned int count,const osg::Vec3*) { _vertexCount += count; }
virtual void setVertexArray(unsigned int count,const osg::Vec2*) { _vertexCount += count; }
virtual void setVertexArray(unsigned int count,const osg::Vec4*) { _vertexCount += count; }
virtual void setVertexArray(unsigned int count,const osg::Vec3d*) { _vertexCount += count; }
virtual void setVertexArray(unsigned int count,const osg::Vec2d*) { _vertexCount += count; }
virtual void setVertexArray(unsigned int count,const osg::Vec4d*) { _vertexCount += count; }
virtual void drawArrays(GLenum mode,GLint,GLsizei count);
virtual void drawElements(GLenum mode,GLsizei count,const GLubyte*);
virtual void drawElements(GLenum mode,GLsizei count,const GLushort*);
virtual void drawElements(GLenum mode,GLsizei count,const GLuint*);
virtual void begin(GLenum mode);
inline void vertex()
{
PrimitivePair& prim = _primitiveCount[_currentPrimitiveFunctorMode];
++prim.second;
_number_of_vertexes++;
}
virtual void vertex(float,float,float) { vertex(); }
virtual void vertex(const osg::Vec3&) { vertex(); }
virtual void vertex(const osg::Vec2&) { vertex(); }
virtual void vertex(const osg::Vec4&) { vertex(); }
virtual void vertex(float,float) { vertex(); }
virtual void vertex(float,float,float,float) { vertex(); }
virtual void end();
void addDrawable() { numDrawables++;}
void addFastDrawable() { numFastDrawables++;}
void addMatrix() { nummat++;}
void addLight(int np) { nlights+=np;}
void addImpostor(int np) { nimpostor+= np; }
inline int getBins() { return nbins;}
void setDepth(int d) { depth=d; }
void addBins(int np) { nbins+= np; }
void setBinNo(int n) { _binNo=n;}
void addStateGraphs(int n) { numStateGraphs += n; }
void addOrderedLeaves(int n) { numOrderedLeaves += n; }
void add(const Statistics& stats);
public:
PrimitiveCountMap& getPrimitiveCountMap() { return _primitives_count; }
const PrimitiveCountMap& getPrimitiveCountMap() const { return _primitives_count; }
PrimitiveValueMap& getPrimitiveValueMap() { return _primitiveCount; }
const PrimitiveValueMap& getPrimitiveValueMap() const { return _primitiveCount; }
/// deprecated
PrimitiveCountMap::iterator GetPrimitivesBegin() { return _primitives_count.begin(); }
/// deprecated
PrimitiveCountMap::iterator GetPrimitivesEnd() { return _primitives_count.end(); }
int numDrawables, nummat, nbins, numStateGraphs;
int numFastDrawables;
int nlights;
int depth; // depth into bins - eg 1.1,1.2,1.3 etc
int _binNo;
StatsType stattype;
int nimpostor; // number of impostors rendered
int numOrderedLeaves; // leaves from RenderBin fine grain ordering
unsigned int _vertexCount;
PrimitiveValueMap _primitiveCount;
GLenum _currentPrimitiveFunctorMode;
private:
PrimitiveCountMap _primitives_count;
unsigned int _total_primitives_count;
unsigned int _number_of_vertexes;
inline unsigned int _calculate_primitives_number_by_mode(GLenum, GLsizei);
};
inline unsigned int Statistics::_calculate_primitives_number_by_mode(GLenum mode, GLsizei count)
{
switch (mode)
{
case GL_POINTS:
case GL_LINE_LOOP:
case GL_POLYGON: return count;
case GL_LINES: return count / 2;
case GL_LINE_STRIP: return count - 1;
case GL_TRIANGLES: return count / 3;
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN: return count - 2;
case GL_QUADS: return count / 4;
case GL_QUAD_STRIP: return count / 2 - 1;
default: return 0;
}
}
/** StatsVisitor for collecting statistics about scene graph.*/
class OSGUTIL_EXPORT StatsVisitor : public osg::NodeVisitor
{
public:
typedef std::set<osg::Node*> NodeSet;
typedef std::set<osg::Drawable*> DrawableSet;
typedef std::set<osg::StateSet*> StateSetSet;
StatsVisitor();
META_NodeVisitor("osgUtil","StatsVisitor")
virtual void reset();
virtual void apply(osg::Node& node);
virtual void apply(osg::Group& node);
virtual void apply(osg::Transform& node);
virtual void apply(osg::LOD& node);
virtual void apply(osg::Switch& node);
virtual void apply(osg::Geode& node);
virtual void apply(osg::Drawable& drawable);
virtual void apply(osg::StateSet& ss);
virtual void totalUpStats();
virtual void print(std::ostream& out);
unsigned int _numInstancedGroup;
unsigned int _numInstancedSwitch;
unsigned int _numInstancedLOD;
unsigned int _numInstancedTransform;
unsigned int _numInstancedGeode;
unsigned int _numInstancedDrawable;
unsigned int _numInstancedGeometry;
unsigned int _numInstancedFastGeometry;
unsigned int _numInstancedStateSet;
NodeSet _groupSet;
NodeSet _transformSet;
NodeSet _lodSet;
NodeSet _switchSet;
NodeSet _geodeSet;
DrawableSet _drawableSet;
DrawableSet _geometrySet;
DrawableSet _fastGeometrySet;
StateSetSet _statesetSet;
osgUtil::Statistics _uniqueStats;
osgUtil::Statistics _instancedStats;
};
}
#endif
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <osgUtil/Statistics>
#include <osg/PrimitiveSet>
#include <osg/Drawable>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/LOD>
#include <osg/Switch>
#include <osg/Geometry>
#include <osg/Transform>
#include <map>
#include <set>
#include <ostream>
#include <iomanip>
using namespace osgUtil;
Statistics::Statistics()
{
reset();
}
void Statistics::reset()
{
numDrawables=0;
numFastDrawables=0;
nummat=0;
depth=0;
stattype=STAT_NONE;
nlights=0;
nbins=0;
nimpostor=0;
numStateGraphs=0;
numOrderedLeaves=0;
_vertexCount=0;
_primitiveCount.clear();
_currentPrimitiveFunctorMode=0;
_primitives_count.clear();
_total_primitives_count=0;
_number_of_vertexes=0;
}
void Statistics::drawArrays(GLenum mode,GLint,GLsizei count)
{
PrimitivePair& prim = _primitiveCount[mode];
++prim.first;
prim.second+=count;
_primitives_count[mode] += _calculate_primitives_number_by_mode(mode, count);
}
void Statistics::drawElements(GLenum mode,GLsizei count,const GLubyte*)
{
PrimitivePair& prim = _primitiveCount[mode];
++prim.first;
prim.second+=count;
_primitives_count[mode] += _calculate_primitives_number_by_mode(mode, count);
}
void Statistics::drawElements(GLenum mode,GLsizei count,const GLushort*)
{
PrimitivePair& prim = _primitiveCount[mode];
++prim.first;
prim.second+=count;
_primitives_count[mode] += _calculate_primitives_number_by_mode(mode, count);
}
void Statistics::drawElements(GLenum mode,GLsizei count,const GLuint*)
{
PrimitivePair& prim = _primitiveCount[mode];
++prim.first;
prim.second+=count;
_primitives_count[mode] += _calculate_primitives_number_by_mode(mode, count);
}
void Statistics::begin(GLenum mode)
{
_currentPrimitiveFunctorMode=mode;
PrimitivePair& prim = _primitiveCount[mode];
++prim.first;
_number_of_vertexes = 0;
}
void Statistics::end()
{
_primitives_count[_currentPrimitiveFunctorMode] +=
_calculate_primitives_number_by_mode(_currentPrimitiveFunctorMode, _number_of_vertexes);
_vertexCount += _number_of_vertexes;
}
void Statistics::add(const Statistics& stats)
{
numDrawables += stats.numDrawables;
numFastDrawables += stats.numFastDrawables;
nummat += stats.nummat;
depth += stats.depth;
nlights += stats.nlights;
nbins += stats.nbins;
nimpostor += stats.nimpostor;
numStateGraphs += stats.numStateGraphs;
numOrderedLeaves += stats.numOrderedLeaves;
_vertexCount += stats._vertexCount;
for(PrimitiveValueMap::const_iterator pitr = stats._primitiveCount.begin();
pitr != stats._primitiveCount.end();
++pitr)
{
_primitiveCount[pitr->first].first += pitr->second.first;
_primitiveCount[pitr->first].second += pitr->second.second;
}
_currentPrimitiveFunctorMode += stats._currentPrimitiveFunctorMode;
for(PrimitiveCountMap::const_iterator citr = stats._primitives_count.begin();
citr != stats._primitives_count.end();
++citr)
{
_primitives_count[citr->first] += citr->second;
}
_total_primitives_count += stats._total_primitives_count;
_number_of_vertexes += stats._number_of_vertexes;
}
StatsVisitor::StatsVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_numInstancedGroup(0),
_numInstancedSwitch(0),
_numInstancedLOD(0),
_numInstancedTransform(0),
_numInstancedGeode(0),
_numInstancedDrawable(0),
_numInstancedGeometry(0),
_numInstancedFastGeometry(0),
_numInstancedStateSet(0)
{}
void StatsVisitor::reset()
{
_numInstancedGroup = 0;
_numInstancedSwitch = 0;
_numInstancedLOD = 0;
_numInstancedTransform = 0;
_numInstancedGeode = 0;
_numInstancedDrawable = 0;
_numInstancedGeometry = 0;
_numInstancedFastGeometry = 0;
_numInstancedStateSet = 0;
_groupSet.clear();
_transformSet.clear();
_lodSet.clear();
_switchSet.clear();
_geodeSet.clear();
_drawableSet.clear();
_geometrySet.clear();
_fastGeometrySet.clear();
_statesetSet.clear();
_uniqueStats.reset();
_instancedStats.reset();
}
void StatsVisitor::apply(osg::Node& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
traverse(node);
}
void StatsVisitor::apply(osg::Group& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
++_numInstancedGroup;
_groupSet.insert(&node);
traverse(node);
}
void StatsVisitor::apply(osg::Transform& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
++_numInstancedTransform;
_transformSet.insert(&node);
traverse(node);
}
void StatsVisitor::apply(osg::LOD& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
++_numInstancedLOD;
_lodSet.insert(&node);
traverse(node);
}
void StatsVisitor::apply(osg::Switch& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
++_numInstancedSwitch;
_switchSet.insert(&node);
traverse(node);
}
void StatsVisitor::apply(osg::Geode& node)
{
if (node.getStateSet())
{
apply(*node.getStateSet());
}
++_numInstancedGeode;
_geodeSet.insert(&node);
for(unsigned int i=0; i<node.getNumDrawables();++i)
{
apply(*node.getDrawable(i));
}
traverse(node);
}
void StatsVisitor::apply(osg::Drawable& drawable)
{
if (drawable.getStateSet())
{
apply(*drawable.getStateSet());
}
++_numInstancedDrawable;
drawable.accept(_instancedStats);
_drawableSet.insert(&drawable);
osg::Geometry* geometry = drawable.asGeometry();
if (geometry)
{
++_numInstancedGeometry;
_geometrySet.insert(geometry);
if (geometry->areFastPathsUsed())
{
++_numInstancedFastGeometry;
_fastGeometrySet.insert(geometry);
}
}
}
void StatsVisitor::apply(osg::StateSet& stateSet)
{
++_numInstancedStateSet;
_statesetSet.insert(&stateSet);
}
void StatsVisitor::totalUpStats()
{
_uniqueStats.reset();
for(DrawableSet::iterator itr = _drawableSet.begin();
itr != _drawableSet.end();
++itr)
{
(*itr)->accept(_uniqueStats);
}
}
void StatsVisitor::print(std::ostream& out)
{
unsigned int unique_primitives = 0;
osgUtil::Statistics::PrimitiveCountMap::iterator pcmitr;
for(pcmitr = _uniqueStats.GetPrimitivesBegin();
pcmitr != _uniqueStats.GetPrimitivesEnd();
++pcmitr)
{
unique_primitives += pcmitr->second;
}
unsigned int instanced_primitives = 0;
for(pcmitr = _instancedStats.GetPrimitivesBegin();
pcmitr != _instancedStats.GetPrimitivesEnd();
++pcmitr)
{
instanced_primitives += pcmitr->second;
}
out << std::setw(12) << "Object Type" << std::setw(10) << "Unique" << std::setw(10) << "Instanced" << std::endl;
out << std::setw(12) << "-----------" << std::setw(10) << "------" << std::setw(10) << "---------" << std::endl;
out << std::setw(12) << "StateSet " << std::setw(10) << _statesetSet.size() << std::setw(10) << _numInstancedStateSet << std::endl;
out << std::setw(12) << "Group " << std::setw(10) << _groupSet.size() << std::setw(10) << _numInstancedGroup << std::endl;
out << std::setw(12) << "Transform " << std::setw(10) << _transformSet.size() << std::setw(10) << _numInstancedTransform << std::endl;
out << std::setw(12) << "LOD " << std::setw(10) << _lodSet.size() << std::setw(10) << _numInstancedLOD << std::endl;
out << std::setw(12) << "Switch " << std::setw(10) << _switchSet.size() << std::setw(10) << _numInstancedSwitch << std::endl;
out << std::setw(12) << "Geode " << std::setw(10) << _geodeSet.size() << std::setw(10) << _numInstancedGeode << std::endl;
out << std::setw(12) << "Drawable " << std::setw(10) << _drawableSet.size() << std::setw(10) << _numInstancedDrawable << std::endl;
out << std::setw(12) << "Geometry " << std::setw(10) << _geometrySet.size() << std::setw(10) << _numInstancedGeometry << std::endl;
out << std::setw(12) << "Fast geom. " << std::setw(10) << _fastGeometrySet.size() << std::setw(10) << _numInstancedFastGeometry << std::endl;
out << std::setw(12) << "Vertices " << std::setw(10) << _uniqueStats._vertexCount << std::setw(10) << _instancedStats._vertexCount << std::endl;
out << std::setw(12) << "Primitives " << std::setw(10) << unique_primitives << std::setw(10) << instanced_primitives << std::endl;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org