Accurate update regions for thin QGraphicsItems

Published Tuesday January 8th, 2008
10 Comments on Accurate update regions for thin QGraphicsItems
Posted in Graphics View, KDE, Labs, Painting, Qt

We’ve gotten reports about how Graphics View’s performance drops in one special (yet quite common) case. It’s the case when the item is fairly thin, flat, non-square, or simply sparse, where QGraphicsItem’s bounding rect generates something close to worst-case updates that cause repaints of areas that really haven’t changed. A very helpful customer showed me a simple testcase that illustrates this problem, which is quite hard to work around, which again effectively makes it a bug. Start the portedcanvas example, and clear the canvas (CTRL-E). Add a few meshes (ALT-M). Now click a node in the top left corner and drag it down towards the bottom right corner.

portedcanvas screenshot

Performance degrades steadily as you get closer and closer to the bottom-right corner, until the example almost grinds to a halt. The example is very busy doing something close to nothing, at least it seems so. It’s redrawing the bounding rectangle of the edges to the node you’re dragging.

The yellow thing you get in debug mode by setting/exporting QT_FLUSH_PAINT=1 reveals what’s going on.

portedcanvas screenshot using bounding rect updates

To finally hammer this bug down, we’ve added an opt-in feature, QGraphicsItem::boundingRegion(), and a configurable granularity. You can tune the granularity of the bounding region of your line / edge / connector items, and with the wave of a wand, QGraphicsView will magically generate an optimal update region for that item.

So with 4.4, you’ll instead get something like this:

portedcanvas screenshot using granular region updates

What you’re seeing is that each of the two connector lines updates itself using a region consisting of 20-30 rectangles, a tunable granularity.

Should be in tonight’s 4.4 snapshots.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Graphics View, KDE, Labs, Painting, Qt


JarJarThomas says:

juhu i need that really, because i have nodeview with many interconnected nodes, so that’s a real appreciated information

Ralf says:

Looks great, and we really need this, too.
But how do you implement it for custom items? Does boundingRegion() return a QList of QRects!?


Andreas says:

Ralf: All you do is set the granularity, and Graphics View will find the region for you. You don’t need to reimplement anything; the implementation is based on tracing the outline rendered by QGraphicsItem::paint(). This means you can even get an accurate outline of sparse items (e.g., donuts, L-shaped items, or items with several disjoint shapes). Pretty cool :-).

Ralf says:

Hmm, ok. But what about performance? You save on repaints, but what does the “tracing” cost in terms of time and space? I mean, nobody knows the shape of a custom item better than its developer. So why rely on some calculated approximation and not give the developer a way to give a “hint” to the optimum boundingRegion()?


Andreas says:

Of course, it’s a trade-off. The optimium bounding region isn’t something the developer knows best; in contrary, creating this region is very difficult and highly error-prone. The optimum region also varies with the transformation levels of the item and the view. A line that’s perfectly diagonal in item space may be perfectly horizonal or vertical in device space (if the view is rotated 45 degrees), in which case the optimum region consists of a single rectangle, which is exactly what you get with this feature. Calculating a fine (highly granular) bounding region is somewhat slow, calculating a coarse one is fast. Trial and error is key.

The granularity tuning is 100% accurate and non-magic. A granularity of 0 gives you single-rect region. 1 gives you pixel perfection. 0.5 gives you 2×2 rects, 0.25 gives you 4×4 rects. If you try it out, you’ll quickly get the idea. ๐Ÿ™‚

Ralf says:

I’d like to try it, but I cannot find a snapshot newer than 4.1.2008, neither in my personal download area, nor on the public ftp server. Snapshot generation broken?!


Andreas says:

Sorry about that, we’re working on getting them up again.

Remon says:

I’ve a similar issue with my canvas implementation, hopefully this solves it as well, will try asap!

Although different then the above example, the same happens. A small item, just a vertical line is moved programmatically a tiny bit to the right while at the same time the view is scrolled to the left. The region that is getting updated is from the line to the right of the viewport, in other words, everything when the line is getting close to the left of the viewport!!

Tried to fix this problem by hiding the line item, and instead adding a QWidget with parent the QGV’s viewport(), the same size of the line, hiding the line item, and moving the widget instead of the line item programmatically. But strangely enough, when the widget is moved, the QGV updates the region that was/is covered by the QWidget. Isn’t double buffering supposed to avoid this??

Besides this, QGV and QPainter are impressively fast, no complaints about that!


Karl says:

Question: I am trying to build a high-dimensional parallel coordinate viewer. My guess is that you have heard of these, but in case not, they are linear traces which represent points in N-dimensional space, in my case, 29D space. I used QGraphicsPathItem to emulate any given point trace. However If I have clusters of similar points, I was having problems getting the bounding box to correctly select the correct trace. My next attempt was going to be decomposing the path to lists of line pathes (sets of 29 connected line segments) with highly constrained bounding boxes. The management overhead could be horrible, especially when dealing with a million traces.

Therefore the question Is: Will your modification described here offer a possible alternative?

Thanks in advance for this answer or any thoughts.

Ian Wadham says:

In late 2006, the KDE game called KGoldrunner had a problem in QGraphicsView something like the above. It is animated and if 4 or 5 pixmap frames in different corners of the view had to be re-drawn simultaneously in real time, QGV would re-draw most of the view and could not keep up with real time. A similar problem happened in the the QCanvas sprites demo, ported to QGV, if you started five or more sprites in rapid succession. Will the approach you describe solve those multiple-sprite cases too?

KGoldrunner is currently one of the few KDE Games for KDE 4.0 that do not use QGV. I would like to return it to the QGV path sometime, whenever that is feasible.

Commenting closed.

Get started today with Qt Download now