Hello all, I'm running into a strange performance drop issue when using dynamic VBOs that change frequently. I am measuring performance using framerate with vsync turned off. I know that framerate isn't always the best performance measurement, but my example is simple enough and the performance drop is significant and repeatable, so I feel comfortable using framerate.
The issue: Suppose I have a Geometry that will hold lots of points (e.g. 100k or more). If I choose to pre-define all points in its vertex array, then a certain framerate is achieved. However, if I choose to add a batch of points during each update traversal, up to the same total number of points, then after all points have been added the framerate is much lower than in the pre-defined model. Note that "much lower" means over 30% lower. Note that in both cases, the same number of points are being drawn, and the Geometry and its vertex array are created once and modified (I'm not creating new Geometry objects at every update). All that changes is whether I added the points all at once before rendering or a few at a time while rendering. I wrote a small standalone osg example (attached). Compile, run, and show stats using: > .\osgdynamicvbotest.exe --numPoints 100000 --batchSize 100000 * If batchSize = 100000 (same as numPoints) then you'll see the case where all points are pre-defined. * As you reduce batchSize (e.g. 100), it will take longer to add the total number of points, but after all points have been added and the framerate stabilizes, you'll see it is much lower than the pre-defined case above. My question is, why is this happening? Is it related to intermediate VBOs being kept in memory and slowing down the GPU? All the other forum posts I see on the topic are either about VBOs not displaying properly (not the case here) or about memory usage (not the case here). Any thoughts on what's going on here would be very much appreciated. Thank you! Ravi
#include <iostream> #include <osg/Geode> #include <osgViewer/Viewer> #include <osgViewer/ViewerEventHandlers> /** Adds points to a geometry in batches, up to a specified number of points. */ class PointUpdateCallback : public osg::Callback { public: PointUpdateCallback(unsigned int numPoints, unsigned int batchSize) : _numPoints(numPoints), _batchSize(batchSize) {} virtual bool run(osg::Object* object, osg::Object* data) { // Get the arrays that hold vertex data osg::Geode* geode = static_cast<osg::Geode*>(object); osg::Geometry* geom = geode->getDrawable(0)->asGeometry(); osg::Vec3Array* vertexArray = static_cast<osg::Vec3Array*>(geom->getVertexArray()); osg::DrawArrays* drawArrays = static_cast<osg::DrawArrays*>(geom->getPrimitiveSet(0)); // Add a batch of points osg::Vec3 pos; unsigned int currBatchPoints; for(currBatchPoints = 0; (vertexArray->size() < _numPoints) && (currBatchPoints < _batchSize); ++currBatchPoints) { // Compute current point on the unit circle double t = ((double)vertexArray->size())*2.0*osg::PI / ((double)_numPoints); pos[0] = std::cos(t); pos[1] = std::sin(t); vertexArray->push_back(pos); } // Mark data as changed if a new batch was added if (currBatchPoints > 0) { std::cout << "Vertex array size = " << vertexArray->size() << ", will stop at " << _numPoints << std::endl; vertexArray->dirty(); drawArrays->setCount(vertexArray->size()); drawArrays->dirty(); geom->dirtyBound(); } // Continue traversing as needed return traverse(object, data); } private: unsigned int _numPoints, _batchSize; }; osg::Node* createScene() { // Initialize geometry that will draw line strips osg::Geometry *geom = new osg::Geometry; geom->setDataVariance(osg::Object::DYNAMIC); geom->setUseDisplayList(false); geom->setUseVertexBufferObjects(true); geom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW); geom->setVertexArray(new osg::Vec3Array()); osg::Vec4Array *lineColors = new osg::Vec4Array(1); (*lineColors)[0] = osg::Vec4(1.0, 1.0, 1.0, 1.0); geom->setColorArray(lineColors, osg::Array::BIND_OVERALL); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 0)); // Geode to hold the geometry osg::Geode* geode = new osg::Geode(); geode->addDrawable(geom); osg::StateSet *stateset = geode->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); return geode; } int main(int argc, char** argv) { // Parse user inputs osg::ArgumentParser arguments(&argc, argv); // Set number of points and batch size unsigned int numPoints = 300000; arguments.read("--numPoints", numPoints); unsigned int batchSize = 100; arguments.read("--batchSize", batchSize); OSG_NOTICE << "Will draw " << numPoints << " points in batches of " << batchSize << " points" << std::endl; osg::ref_ptr<osg::Node> scene = createScene(); scene->setUpdateCallback(new PointUpdateCallback(numPoints, batchSize)); osgViewer::Viewer viewer; viewer.setSceneData(scene); viewer.setUpViewInWindow(100, 100, 1024, 768); viewer.addEventHandler(new osgViewer::StatsHandler); return viewer.run(); }
_______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org