Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast line drawing in OpenGL

I am working on a project that requires drawing a lot of data as it is acquired by an ADC...something like 50,000 lines per frame on a monitor 1600 pixels wide. It runs great on a system with a 2007-ish Quadro FX 570, but basically can't keep up with the data on machines with Intel HD 4000 class chips. The data load is 32 channels of 200 Hz data received in batches of 5 samples per channel 40 times per second. So, in other words, the card only needs to achieve 40 frames per second or better.

I am using a single VBO for all 32 channels with space for 10,000 vertices each. The VBO is essentially treated like a series of ring buffers for each channel. When the data comes in, I decimate it based on the time scale being used. So, basically, it tracks the min/max for each channel. When enough data has been received for a single pixel column, it sets the next two vertices in the VBO for each channel and renders a new frame.

I use glMapBuffer() to access the data once, update all of the channels, use glUnmapBuffer, and then render as necessary.

I manually calculate the transform matrix ahead of time (using an orthographic transform calculated in a non-generic way to reduce multiplications), and the vertex shader looks like:

#version 120

varying vec4 _outColor;

uniform vec4 _lBound=vec4(-1.0);
uniform vec4 _uBound=vec4(1.0);
uniform mat4 _xform=mat4(1.0);

attribute vec2 _inPos;
attribute vec4 _inColor;

void main()
{
    gl_Position=clamp(_xform*vec4(_inPos, 0.0, 1.0), _lBound, _uBound);
    _outColor=_inColor;
}

The _lBound, _uBound, and _xform uniforms are updated once per channel. So, 32 times per frame. The clamp is used to limit certain channels to a range of y-coordinates on the screen.

The fragment shader is simply:

#version 120

varying vec4 _outColor;

void main()
{
    gl_FragColor=_outColor;
}

There is other stuff being render to the screen; channel labels, for example, using quads and a texture atlas; but profiling in gDEBugger seems to indicate that the line rendering takes the overwhelming majority of time per frame.

Still, 50,000 lines does not seem like a horrendously large number to me.

So, after all of that, the question is: are there any tricks to speeding up line drawing? I tried rendering them to the stencil buffer and then clipping a single quad, but that was slower. I thought about drawing the lines to a texture, the drawing a quad with the texture. But, that does not seem scalable or even faster due to uploading large textures constantly. I saw a technique that stores the y values in a single row texture, but that seems more like memory optimization rather than speed optimization.

like image 869
slakr007 Avatar asked Mar 28 '14 20:03

slakr007


People also ask

How do I draw a thick line in OpenGL?

Set the line width before: glLineWidth(3); glBegin(GL_LINES); glVertex2f(-0.7f, -1.0f); glVertex2f(-0.7f, 1.0f); glEnd();

How do you draw a line in OpenGL 4?

Create an array with the corners points of the line strip. The first and the last point define the start and end tangents of the line strip. So you need to add 1 point before the line and one point after the line.

What is GL line strip?

Draws lines between each vertex passed, from the beginning to the end. If you pass three vertices, A, B and C, two lines are drawn: one between A and B, and one between B and C. To set up the screen for drawing in 2D, use GL.


1 Answers

Mapping a VBO might slow you down due to the driver might require to sync the GPU with the CPU. A more performant way is to just throw your data onto the GPU, so the CPU and GPU can run more independently.

  • Recreate the VBO every time, do create it with STATIC_DRAW
  • If you need to map your data, do NOT map as readable (GL_WRITE_ONLY)
like image 183
Abubadabu Avatar answered Oct 17 '22 21:10

Abubadabu