[osg-users] Dynamic VBO Performance Drop

Ravi Mathur ravidavi at utexas.edu
Thu Dec 6 12:35:30 PST 2018

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

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

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!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20181206/95e6aa2b/attachment.html>
-------------- next part --------------
#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
  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);

    // 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;


    // Continue traversing as needed
    return traverse(object, data);

  unsigned int _numPoints, _batchSize;

osg::Node* createScene()
  // Initialize geometry that will draw line strips
  osg::Geometry *geom = new osg::Geometry;
  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();
  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.setUpViewInWindow(100, 100, 1024, 768);
  viewer.addEventHandler(new osgViewer::StatsHandler);
  return viewer.run();

More information about the osg-users mailing list