Speed up graphics, reduce CPU load
I'm working on an app that receives network data from a radio.
The radio produces UDP packets at varying rates and upon receipt I gather the data and put it in a queue. This is done in a background UDP thread that works very well.
I have two other threads that process the queued data. Each of these must pop a data packet off the queue and do some drawing. Each of these creates a QImage and draws the data and queues the image in an image queue.
My foreground window has a 0 time, timer that looks to see if there is an image waiting in the image queue and if so calls update. Update triggers repaint which grabs an image and simply using QPainter to drawImage the image to the window.
This all works very nicely except that everything eats up quite a bit of CPU time. I'm working on optimizing that.
The other issue is that when the window gets big the processing cannot keep up and it seems that QPainter drawImage cannot move the pre-drawn image to screen very efficiently. Making the window smaller puts things back in reasonable shape.
The radio can also send out data to be plotted as fast as 30 frames per second. I can handle this rate but only if the display window is quite small. The moment I start to make it larger the queue starts filling with images and it seems QPainter draw image cannot move them fast enough.
So I'm looking for some suggestions.
First I have tried to stay generic in how I do the graphics because I want this program to run on both PC and Mac and maybe even Linux. But I also would like to improve the performance.
So beyond QPainter drawImage what are my options for getting the pre-drawn image to screen as quickly as possible? IE what is the next step down that might improve this performance?
I've proven that my background draw threads can handle very high rates although they are kind of CPU intensive. I'm working to reduce that load. But I'm just not sure how to move these images to screen fast enough.
I can provide some movies and sample code but right now I'm looking for high level suggestions.
Thanks in advance!
Hi, just a quick suggestion: if your frames do not have completely new content 30 times a second (for example, if you're doing some sideways scrolling) you could perhaps reuse some existing content in the frame instead of telling QPainter to redraw all of it.
Hi! You can get hardware acceleration for QPainter, see the 2D Painting Example. But I'm not sure if this has a great effect here as I assume the most costly part is copying the pixel data from main RAM into the GPU. A much faster solution, assuming your GPU supports at least OpenGL 4.3, would be to move your raw data to the GPU, compute the FFT and "waterfall" with compute shaders and render the results into a pixel buffer. If you can't use compute shaders (because your hardware doesn't support them) then you could still use OpenCL for the computations and then render the results with your older OpenGL. Or, compute the FFT and waterfall data like you do now on the CPU and only do the rendering with OpenGL.
Regarding the first idea (using the technique described in 2D Painting Example)... Instead of rendering to QImage on the CPU you could let your worker thread compute the FFT and waterfall but only put the data needed to render the image into the queue. Then, using this data, do the actual painting operations inside the paintEvent of the Widget (which would use hardware acceleration). That should be faster.