Changeset 8997

Show
Ignore:
Timestamp:
10/07/08 15:37:04 (6 years ago)
Author:
robert
Message:

From Jean-Sebastirn Guay, "Inspired by the latest additions to the StatsHandler?, here is my own addition. It's a graph that helps show the variation of the various stats over time. It's clearer than just having bars for the last 10 frames or so, IMHO, since 10 frames go by pretty fast...

The graph is displayed "under" (behind) the normal bar chart you get when you press 's' twice. It doesn't hide the normal stats, you can still read them without any trouble, and that way, it doesn't take any more screen space. It starts from the left, and will scroll left when there is enough data to fill the screen width. The graph lines have the same colors we're used to (except I made the event color a bit bluer, so it's not exactly the same as the update color). A screen shot is attached.

The lines get a bit confused when they're all overlapping at the bottom of the graph, but I think that's the least of our concerns (if they're all at the bottom of the graph - except FPS of course - then great!).

The only thing I'm not very keen about is that to make things simple, I clamp the values to a given maximum. Right now, the maximums I have set are:

* Frame rate: 100 fps (people have 60, 75, 85Hz refresh rates, so there's no one right value, but I think 100 is OK)
* Stats: 0.016 seconds (what you need to get 60Hz minimum)

This could be changed so that the scale of the graph changes according to the maximum value in the last screenful of the graph instead of clamping values. We would then need to display the scale for each value on the side of the graph, because if the scale changes, you need to know what it is at this moment.

I tried to make things easy to change, so for example if you don't like that the graph is in the same space as the normal stats bars, it's easy to move it anywhere else, and make it have other dimensions. The maximums and colors are also easy to change.

The impact on performance should be minimal, since it's one vertex per graph line that's added per frame, and vertices are removed when they scroll off the screen, so you'll never have more than say 1280 * (3 + ncameras) vertices on the screen at one time. No polygons, I used line strips. The scrolling is done with a MatrixTransform?."

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/src/osgViewer/StatsHandler.cpp

    r8970 r8997  
    1717 
    1818#include <osg/io_utils> 
     19 
     20#include <osg/MatrixTransform> 
    1921 
    2022#include <osgViewer/ViewerEventHandlers> 
     
    592594 
    593595 
     596struct StatsGraph : public osg::MatrixTransform 
     597{ 
     598    StatsGraph(osg::Vec3 pos, float width, float height) 
     599        : _pos(pos), _width(width), _height(height), 
     600          _statsGraphGeode(new osg::Geode) 
     601    { 
     602        _pos -= osg::Vec3(0, height, 0.1); 
     603        this->setMatrix(osg::Matrix::translate(_pos)); 
     604        this->addChild(_statsGraphGeode.get()); 
     605    } 
     606 
     607    void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") 
     608    { 
     609        _statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd)); 
     610    } 
     611 
     612    osg::Vec3           _pos; 
     613    float               _width; 
     614    float               _height; 
     615 
     616    osg::ref_ptr<osg::Geode> _statsGraphGeode; 
     617 
     618protected: 
     619    struct Graph : public osg::Geometry 
     620    { 
     621        Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,  
     622              const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") 
     623        { 
     624            this->setUseDisplayList(false); 
     625 
     626            this->setVertexArray(new osg::Vec3Array); 
     627 
     628            osg::Vec4Array* colors = new osg::Vec4Array; 
     629            colors->push_back(color); 
     630            this->setColorArray(colors); 
     631            this->setColorBinding(osg::Geometry::BIND_OVERALL); 
     632 
     633            this->setDrawCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd)); 
     634        } 
     635    }; 
     636 
     637    struct GraphUpdateCallback : public osg::Drawable::DrawCallback 
     638    { 
     639        GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,  
     640                            float max, const std::string& nameBegin, const std::string& nameEnd = "") 
     641            : _width((unsigned int)width), _height((unsigned int)height), _curX(0), 
     642              _viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd) 
     643        { 
     644        } 
     645 
     646        virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const 
     647        { 
     648            osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry()); 
     649            if (!geometry) return; 
     650            osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
     651            if (!vertices) return; 
     652 
     653            int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); 
     654 
     655            // Get stats 
     656            double value; 
     657            if (_nameEnd.empty()) 
     658            { 
     659                if (!_stats->getAveragedAttribute( _nameBegin, value, true )) 
     660                { 
     661                    value = 0.0; 
     662                } 
     663            } 
     664            else 
     665            { 
     666                double beginValue, endValue; 
     667                if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) && 
     668                    _stats->getAttribute( frameNumber, _nameEnd, endValue) ) 
     669                { 
     670                    value = endValue - beginValue; 
     671                } 
     672                else 
     673                { 
     674                    value = 0.0; 
     675                } 
     676            } 
     677 
     678            // Add new vertex for this frame. 
     679            value = osg::clampTo(value, 0.0, double(_max)); 
     680            vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0)); 
     681 
     682            // One vertex per pixel in X. 
     683            if (vertices->size() > _width) 
     684            { 
     685                unsigned int excedent = vertices->size() - _width; 
     686                vertices->erase(vertices->begin(), vertices->begin() + excedent); 
     687 
     688                // Make the graph scroll when there is enough data.  
     689                // Note: We check the frame number so that even if we have  
     690                // many graphs, the transform is translated only once per  
     691                // frame. 
     692                static const float increment = -1.0; 
     693                if (GraphUpdateCallback::_frameNumber != frameNumber) 
     694                { 
     695                    // We know the exact layout of this part of the scene  
     696                    // graph, so this is OK... 
     697                    osg::MatrixTransform* transform =  
     698                        geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform(); 
     699                    if (transform) 
     700                    { 
     701                        transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0))); 
     702                    } 
     703                } 
     704            } 
     705            else 
     706            { 
     707                // Create primitive set if none exists. 
     708                if (geometry->getNumPrimitiveSets() == 0) 
     709                    geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0)); 
     710 
     711                // Update primitive set. 
     712                osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0)); 
     713                if (!drawArrays) return; 
     714                drawArrays->setFirst(0); 
     715                drawArrays->setCount(vertices->size()); 
     716            } 
     717 
     718            _curX++; 
     719            GraphUpdateCallback::_frameNumber = frameNumber; 
     720 
     721            geometry->dirtyBound(); 
     722 
     723            drawable->drawImplementation(renderInfo); 
     724        } 
     725 
     726        const unsigned int      _width; 
     727        const unsigned int      _height; 
     728        mutable unsigned int    _curX; 
     729        osg::Stats*             _viewerStats; 
     730        osg::Stats*             _stats; 
     731        const float             _max; 
     732        const std::string       _nameBegin; 
     733        const std::string       _nameEnd; 
     734        static int              _frameNumber; 
     735    }; 
     736}; 
     737 
     738int StatsGraph::GraphUpdateCallback::_frameNumber = 0; 
     739 
     740 
    594741osg::Geometry* StatsHandler::createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks) 
    595742{ 
     
    8571004 
    8581005    osg::Vec4 colorFR(1.0f,1.0f,1.0f,1.0f); 
     1006    osg::Vec4 colorFRAlpha(1.0f,1.0f,1.0f,0.5f); 
    8591007    osg::Vec4 colorUpdate( 0.0f,1.0f,0.0f,1.0f); 
    8601008    osg::Vec4 colorUpdateAlpha( 0.0f,1.0f,0.0f,0.5f); 
     1009    osg::Vec4 colorEventAlpha(0.0f, 1.0f, 0.5f, 0.5f); 
     1010    osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f); 
     1011    osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f); 
     1012    osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f); 
    8611013 
    8621014    osg::Vec4 colorDP( 1.0f,1.0f,0.5f,1.0f); 
     
    9311083 
    9321084        geode->addDrawable(createBackgroundRectangle(    pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),  
    933                                                         70 * characterSize + 2 * backgroundMargin,  
     1085                                                        _camera->getViewport()->width() - 2 * backgroundMargin,  
    9341086                                                        (3 + 4.5 * cameras.size()) * characterSize + 2 * backgroundMargin, 
    935                                                         backgroundColor)); 
     1087                                                      backgroundColor) ); 
    9361088 
    9371089        { 
     
    10281180            frameMarkers->setDrawCallback(new FrameMarkerDrawCallback(this, startBlocks, viewer->getStats(), 0, _numBlocks + 1)); 
    10291181            geode->addDrawable(frameMarkers); 
     1182 
     1183            pos.x() = leftPos; 
     1184        } 
     1185 
     1186        // Stats line graph 
     1187        { 
     1188            pos.y() -= (backgroundSpacing + 2 * backgroundMargin); 
     1189            float width = _camera->getViewport()->width() - 4 * backgroundMargin; 
     1190            float height = 5 * characterSize; 
     1191 
     1192            // Create a stats graph and add any stats we want to track with it. 
     1193            StatsGraph* statsGraph = new StatsGraph(pos, width, height); 
     1194            group->addChild(statsGraph); 
     1195 
     1196            statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorFRAlpha, 100, "Frame rate"); 
     1197            statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorEventAlpha, 0.016, "Event traversal time taken"); 
     1198            statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorUpdateAlpha, 0.016, "Update traversal time taken"); 
     1199             
     1200            for(ViewerBase::Cameras::iterator citr = cameras.begin(); 
     1201                citr != cameras.end(); 
     1202                ++citr) 
     1203            { 
     1204                statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorCullAlpha, 0.016, "Cull traversal time taken"); 
     1205                statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorDrawAlpha, 0.016, "Draw traversal time taken"); 
     1206                statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorGPUAlpha, 0.016, "GPU draw time taken"); 
     1207            } 
     1208 
     1209            geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0), 
     1210                                                          width + 2 * backgroundMargin, 
     1211                                                          height + 2 * backgroundMargin, 
     1212                                                          backgroundColor) ); 
     1213 
     1214            pos.x() = leftPos; 
     1215            pos.y() -= height + 2 * backgroundMargin; 
    10301216        } 
    10311217 
     
    10411227            if (dp && dp->isRunning()) 
    10421228            { 
    1043                 pos.y() -= (characterSize + backgroundSpacing + 2 * backgroundMargin); 
    1044  
    1045                 pos.x() = leftPos; 
     1229                pos.y() -= (characterSize + backgroundSpacing); 
    10461230 
    10471231                geode->addDrawable(createBackgroundRectangle(    pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),  
    1048                                                                 70 * characterSize + 2 * backgroundMargin,  
     1232                                                                _camera->getViewport()->width() - 2 * backgroundMargin,  
    10491233                                                                characterSize + 2 * backgroundMargin, 
    10501234                                                                backgroundColor));