[Interest] [QGV] Asynchronous painting of millions QGPathItem

Philip Schuchardt vpicaver at gmail.com
Tue Dec 6 01:27:34 CET 2016


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.

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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20161206/1187de78/attachment.html>


More information about the Interest mailing list