I need to draw pixel data that is being held by a library as uint8_t *
and that is updated frequently and partially. I get a call-back from the library every time an update is done, that looks like this:
void gotFrameBufferUpdate(int x, int y, int w, int h);
I've tried creating a QImage using the pixel data pointer
QImage bufferImage(frameBuffer, width, height, QImage::Format_RGBX8888);
and let the call-back trigger update()
of my widget
void gotFrameBufferUpdate(int x, int y, int w, int h)
{
update(QRect(QPoint(x, y), QSize(w, h)));
}
which simply draws the updated area of the QImage via paint()
:
void MyWidget::paint(QPainter *painter)
{
QRect rect = painter->clipBoundingRect().toRect();
painter->drawImage(rect, bufferImage, rect);
}
The problem with this approach is that the QImage does not seem to reflect any updates to the pixel buffer. It keeps showing its initial contents.
My current workaround is to re-create a QImage instance each time the buffer is updated:
void gotFrameBufferUpdate(int x, int y, int w, int h)
{
if (bufferImage)
delete bufferImage;
bufferImage = new QImage(frameBuffer, width, height,
QImage::Format_RGBX8888);
update(QRect(QPoint(x, y), QSize(w, h)));
}
This works but seems very inefficient to me. Is there a better way of dealing with externally updated pixel data in Qt? Can I make my QImage aware of updates to its memory buffer?
(Background: I'm writing a custom QML type with C++ backend that shall display the contents of a VNC session. I'm using LibVNC/libvncclient for this.)
I would guess that some sort of caching mechanism is interfering with your expectations. QImage has a cacheKey
, which changes if the QImage
is altered. This can of course only happen if you change the image through QImage
functions. As far as I can see, you're changing the underlying buffer directly, so QImage
's cacheKey
will remain the same. Qt's pixmap cache then has that key in its cache, and uses the cached pixmap for performance reasons.
Unfortunately, there doesn't seem to be a direct way to update this cacheKey
or otherwise "invalidate" a QImage
. You have two options:
QImage
when you need it. No need to new
it, so you can save a heap allocation. Creating a back-buffered QImage
seems like a "cheap" operation, so I doubt this is a bottleneck.QImage
(i.e. setPixel
on a single pixel to black and then to the old value). This is somewhat "hackish" but probably the most efficient way to work around this API deficiency (it will trigger an update to cacheKey
as far as I can tell).