I'm having performance issues with a program I'm making using Qt. The problem stems from the large number of bitmaps I have updating every 16 ms; it takes about 300 ms to update them all. I'm not happy about this, but the bigger problem is the lag this creates in the rest of the UI. I would like to be able to reduce the priority of the updates so that the massive number of paintEvents don't block the event loop for the rest of the UI, but I'm having difficulty. Since update() and repaint() don't have a priority parameter, I tried using QCoreApplication::postEvent(), but it seems I'm not allowed to call paintEvent in this way because I get this error message:
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setOpacity: Painter not active
QPainter::setFont: Painter not active
QWidget::paintEngine: Should no longer be called
Here is the source of my problems, an array of 240 QLabels that I update all at once every 16 ms:
if (ui->objectSlotTabs->currentIndex() == 1) {
for (int c = 0; c < 240; c++) {
QEvent* event = new QEvent(QEvent::Paint);
QCoreApplication::postEvent((*(ui->mArray))[c], event, -1);} }
EDIT: Here's an example image of what the program does and why the QLabels are so important (My program is the window on the left):
There are two solutions (among many):
While you update the labels, disable the updates on the parent widget of the labels. Re-enable the updates when you're done updating the labels.
Use a QGraphicsView and place QGraphicsPixmapItems within it, instead of labels.
Prioritizing the paint events won't help, since they are all for different widgets. If they were all for the same widget, then you wouldn't need to do anything, since the events are already coalesced and only one repaint for a given widget can ever exist in the event loop.
Related
As the title says, in a program I'm making I have a QGraphicsView that contains a lot of items, about half of which are pixmaps. Obviously this is resource intensive, and I can't expect the display to update at 60 fps like I would prefer. That's fine, but it's important that the rest of the widgets perform crisply. Is there a way to render a QGraphicsView in a separate thread, or otherwise update it synchronously so it doesn't block my other widgets?
EDIT - Screenshot:
http://imgur.com/VzE0jWp
I'm new not only to Xlib but to Linux interface programing as well.
I'm trying to solve common task(which is not so common as it seems to be, as I can't find any reliable example) of drawing content of one window into another.
However I've faced serious perfomance issues and I'm looking for solution which I can use to make program faster and reliable.
Now I'll provide some information about program flow, as I'm not sure if choosen program design was correct, maybe there are some errors with the way I use Xlib.
Program gets ID (Xlib "Window" type) of active window (called SrcWin from now on) in a proper way (not the IDs of widgets of some program, but real visible window where all content is drawn), at first it uses XGetInputFocus to get focused window, then iterates windows using XQueryTree while the child of root window is found, then it uses XmuClientWindow function to get named window(if it is not the already found one).
Then using XGetWindowAttributes it gets width and height of SrcWin which both used in XCreateSimpleWindow function to create new window (called TrgWin) of the same size.
Some events are registered for new window TrgWin such as KeyPress and Expose using XSelectInput function.
Graphics context is created in this way:
GC gc = DefaultGC (Display, ScreenCount (Display) - 1);
Now infinite loop is started, in this loop select function is called to wait for some event on X connection or for timeout (struct timeval).
After that program tries to get image from SrcWin using:
XImage *xi;
xi = XGetImage (Display, SrcWin, 0, 0, SrcWinWidth, SrcWinHeight, AllPlanes, ZPixmap);
and if an image was successfully acquired it is put to TrgWin:
if (xi)
{
XPutImage (Display, TrgWin, gc, xi, 0, 0, 0, 0, SrcWinWidth, SrcWinHeight);
XFree (xi);
}
then pending events are processed if they are:
while (XPending (Display))
{
XNextEvent (Display, &XEvent);
/* some event processing using switch(XEvent.type){} */
}
As mentioned above program works nearly as expected. But I've faced serious perfomance issues when trying to make this program draw content of SrcWin to TrgWin every 40ms(this is timeval value, with events it might be faster), on core i5-3337U it takes 21% of cpu time for this program and nearly 20% for Xorg process to draw one 683*752 window into another of the same size.
From my point of view, it would have been great if only I was able to map memory region with pixels of SrcWin to the corresponding memory region of TrgWin, but I'm not so good in Xlib programming, and I doubt it is possible with standard Xlib functions.
1) However I've started KDE environment to check its window-switcher and all window thumbnails are drawn to window-switcher's window in realtime without any serious CPU load. How it is done?
2) Somewhere XShmGetImage + XShmPutImage mechanism is mentioned - is it better for my program than XGetImage+XPutImage?
3) Also I saw that there is such a thing as "window-damage" events in QT and GTK, is it toolkit-specific events, or does it have Xlib equivalent?
4) I understood "window-damage" events in QT and GTK as signals beign send after any changes in image buffer of window, so everything resulting in changing of at least one pixel in window is also generating such an event? It would be great to have something like this in Xlib as I could get rid of continuously changing TrgWin content every 40ms even if there were no changes in SrcWin.
5) Should I go with GTK+ to make things easier?
Thanks in advance for replies, and sorry for tons of text.
In a display application we do use a large Window painting area. The display application gets so many updates for painting realtime data that all CPU time of the PC is used for painting. We do use InvalidateRect() and then paint the items in WM_PAINT message.
So we decided to use a dirty flag for each item to paint for reducing painting it.
How to know when the application can paint the items so that not all CPU time is consumed. Is there anything telling us that we can do our paint stuff now ?
If the data is updating so fast that painting each update is too much, you can use a timer. Every (say) quarter second, the timer fires, and if any items are dirty, the timer handler calls InvalidateRect(). Updating the data no longer invalidates; only the timer handler does that.
Edit: You could query Windows for the CPU load and if it's low, do the Invalidate immediately; see How to get system cpu/ram usage in c++ on Windows
One method I've used is to make sure that only one paint event is on the event queue at a time. You can use a boolean flag to mark when you begin updating and then reset the flag at the end of the WM_PAINT message (the end of the update process). Of course, if you try to update the window again and the flag is already set, then don't do anything. This will keep extra events from being piled into the queue, which can bog down your system. It looks like you may have thought of this, but do this with the entire update in addition to the individual items. Keep in mind that I'm only thinking of the updating of the windows themselves and not any underlying data.
One other thing I had to do was to "pump" (or process) the message queue during my (application) updates because updating a window (in my case) took several messages, ending with the WM_PAINT.
Another thing to watch out for is to not use idle messages for updating your interface. This is a quick and dirty way of having the update happen automatically, but ends up being a really bad idea because the idling only happens when there are no other events on the message queue. Of course, any time you move the mouse or press keys those events are placed onto the event queue and causes a "stall" of the update process. The idle events can end up coming so fast that it causes your application to use most of the CPU processing power just for displaying data that hasn't even changed. It's better to have your GUI only update when the underlying data it displays actually updates.
I had data coming in at 60Hz and updating lots of lists with columns of data as well as 3D stuff going on. I finally had to prioritize the updates and just not update the lists for each cycle, but DO update the 3D data each cycle. Updaing the lists at about 1-5 Hz was good enough for me and when combined with the techniques above resulted in a much improved and responsive system.
I'm trying to time an application to see how long it takes to load up some information, and paint a graph. My function loads up the data first, then draws the graph.
The timing is fairly simple, it calls an external function that gets msecs since some date.
The problem is even if I set t1 in the beginning and t2 right after I call the draw function, t2 will return before the QGraphicsView is actually updated. (I know, it makes sense why this should be asynchronous)
For instance when I load a large file, it will return with 700 msecs after I subtract the two values, but the actual rendering doesn't finish until a few seconds later.
I've looked all over the web and scoured the Qt documentation. I can find tons of information on updating widgets yourself, but nothing on any kind of signal or event that is fired off after rendering finishes.
Even the QGraphicsScene::changed signal appears to only be fired off when the scene changes underneath, not when rendering is done and the user can SEE the changes.
Any help on how to do this?
Does a signal or event exist for when a QGraphicsView or QWidget is done being painted or rendered?
As far as I know, it does not exist. (looked for something similar)
user can SEE the changes
As far as I know, Qt uses double buffering, so if painting is finished, it doesn't mean that user can see the changes.
Any help on how to do this?
If you want to know when painting has finished, then...
You can subclass QGraphicsScene and implement your own drawItems, drawBackground or drawForeground. This is NOT simple (because item painting algorithm is complicated), but you'll be able to tell when every item has finished painted.
You can fire/emit signals from within paintEvent (QWidget-based classes) or paint() (QGraphicsItem/QGraphicsObject-based classes). You'll need to use your own classes, obviously, and you'll have to subclass either QGraphicsView, or items you're drawing within view, or QGraphicsScene.
You could also create proxy QPainter class, and this way you'll be able to know what exactly is being paitned and when.
Having said that I suspect you're approaching your problem incorrectly.
If you're only trying to draw a graph, then there's no reason for you to know when painting is finished.
If painting is finished, it doesn't mean user can see the result.
Paint events might be called more than once.
Recommended approach:
Receive/read the data (you're drawing in your graph) from external source using threads or timer events (you'll need to read it in small chunks if you're using timer events, obviously), then update the graph from time to time, and let Qt handle repainting.
How exactly does this allow me to detect the amount of time it takes from when I choose to open a file to when all the data is loaded and the graph is drawn and is visible?
You can detect when paintEvent has finished painting by subclassing whatever widget you're using to paint Graph, overriding paintEvent and firing signal from within paintEvent, calling a subroutine or doing whatever you want.
There is no warranty that paintEvent will be called only once.
To measure how slow individual routine is and locate bottlenecks, use profilers. VerySleepy, AQTime, and so on.
Instead of measuring how long it takes to load AND display data, it will make much more sense to measure separately loading time and display time. This is a GUI application, not a game engine, so you do not control precisely when something is being drawn.
I have not testet it, but I think by subclassing QGraphicsScene and reimplementing the render method you can measure the render time.
#include <QGraphicsScene>
#include <QTime>
class MyGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
void render ( QPainter * painter, const QRectF & target = QRectF(), const QRectF & source = QRectF(), Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio ) {
QTime t;
t.start();
QGraphicsScene::render (painter, target, source, aspectRatioMode);
qDebug("render time %d msec", t.elapsed());
}
};
When using a QListWidget in batched layout mode, whenever more items are added than the batch size, the list widget blinks for a short time when switching from the old list to the new list. This means, the list widget shows no items, and the scroll bar handle is set to a seemingly random size.
Have you ever encountered this, can this be resolved somehow? I'm using Qt 4.7.4. I should probably add that I'm not using any hidden items.
I had this issue also and spent hours combing through the sea that is Qt widget rendering. Ultimately, like you, I traced the problem back to the batch processing of the QListView. It appears, that when batch processing is enabled, Qt fires off an internal timer to perform incremental layout adjustments of the underlying scroll view. During these incremental layouts, when the scroll bar is visible, the update region is not computed correctly (it's too big and does not account for the regions occupied by the scroll widget(s) themselves). The result is a bad update region that subsequently finds its way into the viewport update which has the unfortunate side-effect of clearing the entire client area without rendering any of the ListViewItems.
Once the batch processing is complete, the final viewport update correctly computes the layout geometry (with the scroll bar) and produces a valid update region; the visible elements in the list are then redrawn.
The behavior worsens as the number of items in the list grows (relative to the batch size). For example, if your list grows from 500 to 50000 items and a batch size of 50, there is a proportionate increase in the number of "bad repaint" events which are triggered causing the view to visibly flicker even more. :(
These incremental (and failed) viewport updates also appear to be cause the apparent spazmodic behavior in the scrollbar handle position that you describe.
The root of this issue appears related to this "hack" that was added to
QListView::doItemsLayout() as commented here:
// showing the scroll bars will trigger a resize event,
// so we set the state to expanding to avoid
// triggering another layout
QAbstractItemView::State oldState = state();
setState(ExpandingState);
I suppose you could override QListView::doItemsLayout() and provide your own batch processing which handles scroll bars properly, but personally I'm too old and lazy to be cleaning up someone else's poo. Switching to SinglePass eliminated the problem entirely. Seamless flicker-free rendering and the scroll bar behavior you've come to expect and love. Yay.