How to Efficiently Draw a QImage to a Window.
-
I need to efficiently draw a QImage to a widget several times per second. I had planned to put the draw code in the Widget's paintEvent routine and call update on a timer, as shown here:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { // Set a timer to update the displayed image every 50 ms QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(50); } void MainWindow::paintEvent(QPaintEvent *event) { }
But on my computer (2015 MacBook Pro) this uses 20-25% CPU, which seems rather high. Is there a more efficient way to do draw a QImage to a widget?
-
Hi and welcome to devnet,
You need to provide more details before talking optimization. What kind of image is that ? What size ? How are you loading it ? Why do you need to redraw so quickly ?
-
Size is 800x600. Kind is QImage, "loaded" with
new QImage(800, 600, QImage::Format_ARGB32);
. I'm drawing shapes/applying effects to them to synthesise video. All of these manipulations individually have little discernible impact on CPU utilisation except for drawing to the widget. -
Ok, then since you are drawing anyway, why not draw directly on the widget ?
On a side note, there's rarely need to allocate a QImage on the heap, why to you need to do it ?
-
Let me reformulate: since you are drawing your QImage on the widget, do you really need to pass by a QImage ? Can't you do the same drawing directly on the widget ?
-
If you could that would mean you don't have to allocate a QImage each time you call paint event which in itself is already a gain.
You should also rather work on a QPixmap since you're going to draw it, QPixmap is optimized for showing image on screen while QImage is optimized for IO and direct pixel access.
What operations do you need to do exactly ?
-
I think we're getting a little distracted trying to optimise the system instead of the drawing.
Assuming that I could draw directly to a widget and therefore had no need for QImages or QPixmaps, I might be able to express that like this:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(50); } void MainWindow::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawLine(QPointF(10, 10), QPointF(20, 20)); painter.end(); }
This uses 25% CPU, which seems like a lot just to draw a short line segment. How could this simple example be optimised (if at all)?
-
Is your application painting static content ? If so, then don't trigger update that much, there's no real need.
paintEvent will be called when needed so with your last sample, calling update every 50ms is useless and power consuming.
-
Ok, so that may not have been a great example. In reality it will be dynamic content, so I really do need a frequent screen refresh. This is a slightly more representative example:
int x = 0; void MainWindow::paintEvent(QPaintEvent *event) { if (x > 500) x = 0; QPainter painter(this); painter.drawLine(QPointF(10, 10), QPointF(x++, x++)); painter.end(); }
-
Do you need some kind of graph ?
-
Is there some kind of history for these shapes are do you need to re-draw them all every time ?
-
The first thing I'd do is optimize the data sent e.g. do you really need to build a line of 500 points if you already know the final coordinates ?
Otherwise, maybe consider using OpenGL
-
Yes there is, do the drawing in another thread on a QImage and then trigger the update with that image. You have an example of this in the Mandelbrot example
-