[Interest] [QGV] Asynchronous painting of millions QGPathItem

Ch'Gans chgans at gna.org
Tue Dec 6 03:53:45 CET 2016


On 6 December 2016 at 13:27, Philip Schuchardt <vpicaver at gmail.com> wrote:
> I've always wondered if you could put a QGraphicsScene in another process
> and then render to shared memory buffer QSharedMemory
> (https://doc.qt.io/qt-5/qtcore-ipc-sharedmemory-example.html). Then you
> could query the shared memory (as a pixmap) in the main application. This
> would get around the QGraphicsScene blocking the main thread. This approach
> is great for rendering, but terrible if you want to directly interact with
> the QGraphicsView / QGraphicsScene using mouse and keyboard. You could even
> thread the scene by tilting the scene in separate processes. Just an idea.

Not sure to get why you want to render the whole scene in a single
buffer, or even a shared memory for this (IPC). How would that improve
things?

Another solution could be to pre-render each item (or group of items)
using Qt Concurrent, and then each time the zoom level changes, the
scene trigger the painting of the items (they will use the "old"
cache), and at the same time trigger the async pixamp rendering
(QFuture), when they are all done, the scene repaint again...
Basically the goal would be to get the tile-based rendering technique
usedby map applications that gets their tiles from the network...
All of this might fit my use case, because all my items are organised
as layers, these layers are actually QGraphicsItemGroup, and are the
only "root" items. A typical project contains 10 of them, crazy
projects have up to 30/40 layers. Processing one layer per CPU-thread
could greatly improve responsiveness

Something else I had in mind, is to use QPainterPath::simplified()
and/or QPainterPath::toFillPolygons() to paint a "far" item and use
the "real" painter path to paint a "close" item. Basically as you zoom
in, there are less items to draw, so you can use the true (and more
expensive) painter path, when you zoom out, there are more items to
draw, but you don't need the details, hence the used of the simplified
path (a set of polygons where arcs/bezier curves are converted to
poly-lines).
In the same vein, you could as well transform your painter path into a
QRegion. The idea would be to create a pixelated representation of the
path with "big pixels", but i haven't find anything to achieve that in
the Qt graphical API, QRegion seems to be geared toward painting
management of QWidget, if anyone knows a way to convert a QPainterPath
into a QRegion, please share!
Combined with the scene's minimal render size (or something similar
implemented manually), this could give me 4 level of details:
- Not rendered (too small)
- Rendered as a QRegion (small)
- Rendered as QPolygon (small-ish)
- Rendered as QPainterPath (not small)

Thinking about this (sorry but as I read my message again and again
before hitting 'send' I get more and more ideas!), it could be "as
simple" as this pseudo code:
QPainterPath path = buildPath(documentData);
QList<QPolygonF> polygons = path.toFillPolygons();
QList<QRectF> region = [poly.boundingRect() for poly in polygons]

As my scene is static, the shape container need to be calculated only
once, and i could use Qt Concurrent to pre-calculate them, KDE
ThreadWeaver [1] seems to be an even better framework for this
particular use case.


Chris


>
> Phi|ip
>
> On Mon, Dec 5, 2016 at 6:39 PM Ch'Gans <chgans at gna.org> wrote:
>>
>> On 8 September 2016 at 18:29, Tomasz Siekierda <sierdzio at gmail.com> wrote:
>> > On 8 September 2016 at 04:17, Ch'Gans <chgans at gna.org> wrote:
>> >>
>> >> Hi there,
>> >>
>> >> I'm currently working on a Gerber viewer (Gerber is an old file format
>> >> still widely used in the electronics PCB manufacturing industry,
>> >> dating as far back as the old photo-plotter methods), some of these
>> >> files can get pretty big and I end up with a scene that contains up to
>> >> 2 millions QGraphicsPathItem (biggest one so far, but i'm expected
>> >> even bigger, maybe 10 millions would be an absolute limit).
>> >> These huge files are more the exception than the rule, i still want
>> >> nonetheless my GUI app to be usable.
>> >> A typical usage is to render several file in a single QGV by
>> >> super-imposing them as "layers".
>> >> After profiling and optimising all the non-gui part of my app, my
>> >> bottle-neck is now QGS/QGV painting time (QGScene insert time is not
>> >> too bad at that stage). I haven't started to address this (I could try
>> >> to implement aggressive caching to start with), because I'm happy to
>> >> have that as a use case for rendering the view in a asynchronous way.
>> >>
>> >> By asynchronous, I mean that I want my GUI to not be completely frozen
>> >> during the painting time (we're talking 10's of seconds). Of course
>> >> i'm not expecting to be able to give the user full access to the GUI,
>> >> I simply want to give the user feedback about my
>> >> parsing-processing-rendering-painting pipeline.
>> >> So far, I've used Qt Concurent for the parsing, processing and
>> >> pre-rendering parts, but once this part is finished, the QGraphicsView
>> >> very first painting kicks in and freeze the whole app.
>> >>
>> >> It is the first time that I have to deal with multi-threading that
>> >> would run GUI/Widget business. And I'm not sure how to tackle this.
>> >>
>> >> Ideally, I would like something similar to QtCreator progress bars
>> >> (parsing cmake/qmake/qbs, scanning for auto-test, indexing code model,
>> >> ...). But I'll be happy to start with a small modal dialog showing the
>> >> progress for each step/file (parse a file, process the commands,
>> >> post-process/aggregate into QGS, paint it into QGV).
>> >> I have a similar use case for exporting the QGS to images, pdf and svg.
>> >>
>> >> So far i've found only discussion about optimising the item painting,
>> >> but nothing about running it in a separate thread.
>> >>
>> >> So here am I, does anyone had to deal with this kind of situation in
>> >> the past and is willing to share feedback, advice or comment on the
>> >> topic?
>> >
>> >
>> > Not exactly the same use case, and not the same scale, but in one of the
>> > apps I was involved with we did have performance issues with painting
>> > using
>> > QGraphicsView (especially on mobile platforms where there is less CPU
>> > and
>> > RAM available). We've got a significant boost in performance by
>> > rendering
>> > QPainterPath to a QImage first, and then QGV was only painting this
>> > image in
>> > paint(). IIRC.
>>
>> Turns out that i'm working on another project (similar application but
>> different file format and content), and have to deal with the same
>> problem.
>> I haven't tried to render manually into a QImage, but will do shortly.
>> So far i have played with QGraphicsItem::setCacheMode() [1] which does
>> exactly that (pixmap cache), but have been unsuccessful in getting
>> decent results (it's actually slower).
>>
>> One dead-simple technique that help a lot is
>> QGraphicsScene::setMinimumRenderSize(), the drawback is visual
>> "incorectness" as the minimum size get bigger.
>> I have added this feature to the gui in the form of a choice "Level of
>> details: high, medium, low". High mean minimum size = 0 (no
>> optimisation), medium try to find "the right value", and low gives
>> visual artifacts, but allow a very fluid X/Y/Z navigation when all the
>> graphical features are enabled.
>>
>> I still have to spent a decent amount of time to try different way of
>> improving paint performance and find a good way to measure
>> performance, and ultimately both apps will share the same QGraphicsXYZ
>> code.
>> There are lot of areas to explore:
>> - use of OpenGL viewport
>> - QGView optimisation flags
>> - QGView viewport update mode
>> - QGItem cache mode (or manual caching, in my case i can even share
>> cache b/w items)
>> - QGScene minimum render size
>> - QGScene BSP tree depth
>>
>> Have you tried QGItem cache mode ? If so what sort of result did you
>> get? Why did you decide to implement your own caching method?
>>
>> Thanks,
>> Chris
>>
>> [1]http://doc.qt.io/qt-5/qgraphicsitem.html#setCacheMode
>>
>>
>> >
>> >>
>> >> Thanks in advance,
>> >> Chris.
>> >>
>> >> PS: My application is currently able to display such gigantic scenes,
>> >> it just take some time to render (and swallow lot of RAM), and make
>> >> the mouse-wheel based zooming particularly slow, but with a bit of
>> >> patience the result is actually quite amazing. Qt rocks!
>> >> _______________________________________________
>> >> Interest mailing list
>> >> Interest at qt-project.org
>> >> http://lists.qt-project.org/mailman/listinfo/interest
>> >
>> >
>> _______________________________________________
>> Interest mailing list
>> Interest at qt-project.org
>> http://lists.qt-project.org/mailman/listinfo/interest
>
> --
> Phi|ip



More information about the Interest mailing list