QGraphicsView rendering thousands of items
-
I am implementing a viewer application where the user must be able to add / edit / move objects over a large scene, where there may be many thousands of items in the scene. At a basic level this is very similar to the 40,000 chips example.
The QGraphicsScene/View model is generally fantastic, and I have a scene with ~50K items that works seamlessly when zoomed in.
However, when zoomed out to a level where there are thousands of visible items at once, the render speed of the scene becomes unworkable. This is even the case when I define each item in the scene as a simple rect with default pen and no brush (thus reducing the number of state changes required for the painter).
A bare-bones scene that is rendering 10,000 squares takes about 300ms to paint. Profiling the 40,000 chips example shows that it too takes hundreds of milliseconds to render the entire scene when fully zoomed out.
It seems that using the OpenGL renderer for the GraphicsScene is even slower...
I have been reading about the Qt Quick Scene Graph, and the hardware acceleration that provides does look promising. However it would appear, from what I have read, that the Scene Graph does not provide "scene management" capabilities comparable with QGraphicsScene, such as selecting objects with a marquee, culling painted items outside the viewer rect, etc.
Is there any way of utilising the QGraphicsScene power with the hardware accelerated graphics that come with the QML SceneGraph?
-
I am implementing a viewer application where the user must be able to add / edit / move objects over a large scene, where there may be many thousands of items in the scene. At a basic level this is very similar to the 40,000 chips example.
The QGraphicsScene/View model is generally fantastic, and I have a scene with ~50K items that works seamlessly when zoomed in.
However, when zoomed out to a level where there are thousands of visible items at once, the render speed of the scene becomes unworkable. This is even the case when I define each item in the scene as a simple rect with default pen and no brush (thus reducing the number of state changes required for the painter).
A bare-bones scene that is rendering 10,000 squares takes about 300ms to paint. Profiling the 40,000 chips example shows that it too takes hundreds of milliseconds to render the entire scene when fully zoomed out.
It seems that using the OpenGL renderer for the GraphicsScene is even slower...
I have been reading about the Qt Quick Scene Graph, and the hardware acceleration that provides does look promising. However it would appear, from what I have read, that the Scene Graph does not provide "scene management" capabilities comparable with QGraphicsScene, such as selecting objects with a marquee, culling painted items outside the viewer rect, etc.
Is there any way of utilising the QGraphicsScene power with the hardware accelerated graphics that come with the QML SceneGraph?
@SchrodingersGat said in QGraphicsView rendering thousands of items:
Is there any way of utilising the QGraphicsScene power with the hardware accelerated graphics that come with the QML SceneGraph?
Not really, these are 2 completely separate systems within Qt.
One hint for speeding things up when zoomed out. In one of the projects I was involved in we managed to squeeze much more performance out of QGraphicsView when we replaced items with a pixmap/ picture. How? Initially when items were painted (it was a painting software where users draw with mouse/ touch) we used QPainterPaths and rendered all "normally". Then when the item was finished, we painted it (offscreen) to a QPixmap and displayed the pixmap instead of the painter path. This proved much faster. Another, further step to make it more performant was to combine items into a single, large pixmap - so instead of painting 20, 100, 1000 separate pixmaps with transparency, we painted everything into a single "cache" pixmap. QGraphicsView was only painting this single pixmap.
It was much faster, although we run into another issue there - when zoomed out, the amount of pixels shown was so large that we were running into issues with RAM. It could be avoided with some further tricks, through.
I'm not sure if this is applicable in your use case, but maybe it helps :)
-
@SchrodingersGat said in QGraphicsView rendering thousands of items:
Is there any way of utilising the QGraphicsScene power with the hardware accelerated graphics that come with the QML SceneGraph?
Not really, these are 2 completely separate systems within Qt.
One hint for speeding things up when zoomed out. In one of the projects I was involved in we managed to squeeze much more performance out of QGraphicsView when we replaced items with a pixmap/ picture. How? Initially when items were painted (it was a painting software where users draw with mouse/ touch) we used QPainterPaths and rendered all "normally". Then when the item was finished, we painted it (offscreen) to a QPixmap and displayed the pixmap instead of the painter path. This proved much faster. Another, further step to make it more performant was to combine items into a single, large pixmap - so instead of painting 20, 100, 1000 separate pixmaps with transparency, we painted everything into a single "cache" pixmap. QGraphicsView was only painting this single pixmap.
It was much faster, although we run into another issue there - when zoomed out, the amount of pixels shown was so large that we were running into issues with RAM. It could be avoided with some further tricks, through.
I'm not sure if this is applicable in your use case, but maybe it helps :)
@sierdzio ok thanks for clearing that up. And some good hints there, too. Do you know if switching the QGraphicsView to use an OpenGL context should speed up rendering by itself? Or would I need to update the paint method of each GraphicsItem object to use OpenGL rather than QPainter commands?
-
I don't have experience with OpenGL and GraphicsView. I suspect that turning it on won't help much as items will still be rendered by software rasterizer and then sent to GPU. THat's only a guess though
-
I have a similar feature where I draw 10s of thousands of lines, polylines, text, and triangles. Culling is a great and necessary start but I found that by using QPainterPath for all objects and by greeking text when it gets unreadable helps a lot. I can move fairly real-time (20Hz min) drawing 70000+ triangles, and 18000+ other objects. The only filled objects I use are the three SVG graphics I provide. Anti-aliasing and transparencies are used throughout.
I do NOT use QML as I need high performance.
The only hint I turn off is calculating the anti-aliasing into the bounding box.
I use smart updates.
I do not use OpenGL as it is not necessary.
I use QPainterPath.I assume that under windows, GDI+ and 2D acceleration is at play when QPainterPath is used.
-
I have a similar feature where I draw 10s of thousands of lines, polylines, text, and triangles. Culling is a great and necessary start but I found that by using QPainterPath for all objects and by greeking text when it gets unreadable helps a lot. I can move fairly real-time (20Hz min) drawing 70000+ triangles, and 18000+ other objects. The only filled objects I use are the three SVG graphics I provide. Anti-aliasing and transparencies are used throughout.
I do NOT use QML as I need high performance.
The only hint I turn off is calculating the anti-aliasing into the bounding box.
I use smart updates.
I do not use OpenGL as it is not necessary.
I use QPainterPath.I assume that under windows, GDI+ and 2D acceleration is at play when QPainterPath is used.
@Buckwheat that's interesting, do you convert the text objects to paths and cache the path? Also, what culling operations do you mean (aside from the viewport culling that QGraphicsView provides)?
-
@SchrodingersGat ... I do cache the QPainterPath objects. I also look at objects that are complex (more than a simple entity like a mesh), throw away the pieces that are not in view and then cache the visible items in the painter path.
You can also "greek" the more complex objecfs to a bounding polygon and not draw all the detail. These require some computation but it is amazing how much time is saved by not rendering. Hundreds of objects when they are zoomed out to fit in a small area where you cannot make out the detail anyway.
Since I need to keep objects in their geometric form (more precision than the QGraphicsItems) I cache what is drawn and then when the scene changes.