So I'm doing some DirectX development, using SharpDX under .NET to be exact (but DirectX/C++ API solutions are applicable). I'm looking for the fastest way to render lines in an orthogonal projection (e.g. simulating 2D line drawing for scientific apps) using DirectX.
A screenshot of the sorts of plots I'm trying to render follows:
It's not uncommon for these sorts of plots to have lines with millions of segments, of variable thickness, with or without antialiasing per-line (or full screen AA on/off). I need to update the vertices for the lines very frequently (e.g. 20 times/second) and offload as much to the GPU as possible.
So far I have tried:
- Software rendering, e.g. GDI+ actually not bad performance but obviously is heavy on the CPU
- Direct2D API - slower than GDI, especially with Antialiasing on
- Direct3D10 using this method to emulate AA using vertex colours and tessellation on the CPU side. Also slow (I profiled it and 80% of time is spent computing vertex positions)
For the 3rd method I'm using Vertex Buffers to send a triangle strip to the GPU and updating every 200ms with new vertices. I'm getting a refresh rate of around 5FPS for 100,000 line segments. I need millions ideally!
Now I'm thinking that the fastest way would be to do the tessellation on the GPU, e.g. in a Geometry Shader. I could send the vertices as a line-list or pack in a texture and unpack in a Geometry Shader to create the quads. Or, just send raw points to a pixel shader and implement Bresenham Line drawing entirely in a pixel shader. My HLSL is rusty, shader model 2 from 2006 so I don't know about the crazy stuff modern GPUs can do.
So the question is: - has anyone done this before, and do you have any suggestions to try? - Do you have any suggestions to improve performance with rapidly updating geometry (e.g. new vertex list every 20ms)?
UPDATE 21st Jan
I have since implemented method (3) above using Geometry shaders using LineStrip and Dynamic Vertex Buffers. Now I'm getting 100FPS at 100k points and 10FPS at 1,000,000 points. This is a huge improvement but now I'm fill-rate and compute limited, so I got thinking about other techniques/ideas.
- What about Hardware Instancing of a Line Segment geometry?
- What about Sprite Batch?
- What about other (Pixel shader) oriented methods?
- Can I efficiently cull on the GPU or CPU?
Your comments & suggestions much appreciated!