Results 1 to 11 of 11

Thread: Performance issue with complex QGraphicsScene

  1. #1
    Join Date
    Jan 2011
    Posts
    9
    Thanks
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Performance issue with complex QGraphicsScene

    Hi all!

    I'm currently working on a game made with Qt and I'm struggling with performance issues in the rendering of the game scene, hence this little question. I've browsed those forums a bit and haven't been able to find a solution to my problem, so here it goes!


    Context
    The map of our game is a cylinder: exiting on the "right" of the map brings you back at the "left" transparently. The map must therefore be scrollable without the user noticing when the "shift" occurs.

    The map features many background elements like regions, rivers, sea... and also foreground features (player tokens).


    Implementation
    To implement the aforementioned features, I used QGraphicsScene and QGraphicsView. All the elements in the game (such as rivers for instance) are represented by three distinct QGraphicsItems, grouped in a subclass of QGraphicsItemGroup (that reimplements "paint" with an empty method to be totally invisible): the world is therefore represented thrice. When users scroll the map (using shortcuts; scrollbars are hidden), the view automatically translates itself to always be centered on the central view. See image below to have an illustration of what I'm talking about.

    map.png
    (over 9000 hours in MSPAINT!)

    We currently have up to a few thousands of QPolygonItem on the map, and a few dozens QPixmapItems on top of them. We use OpenGL rendering (with QGLWidget).


    Issue
    The issue that we have here is that rendering of the scene is slow. By using a naive call to "clock" I've gathered stats about QGraphicsView::paintEvent. It currently takes around 50ms to render a small test scene on my (powerful) dev machine. This is far too much, as we want to let the user scroll the map smoothly (so we aim at keeping that time below 30ms as much as possible). Callgrind shows that 90% percent of that time is spent in QGraphicsPolygonItem::paint.

    The issue here is that as far as I know, with OpenGL rendering the ViewPortUpdateMode option is ignored: scrolling the map means a full rendering at each step. Scaling is even worse (but that might be linked to the fact some items have "cosmetic" (scale-independent size) lines; many things might need to be recomputed).


    Tested solutions
    Before coming here to ask about this issue, I tried or thought about several solutions, none of which proved to boost the performance of the rendering.

    One big item versus many small ones.
    Rivers being totally static (not clickable nor interactive in any way), I've tried to use one big subclassed QGraphicsItem to paint them all. That way, in the paint method, I had only one Painter::save, one Painter::restore and one Painter::setBrush for all the rivers, instead of having hundreds of scattered QGraphicsPolygonItems. Rendering time doubled. Idea scrapped.
    I suppose it's because Qt is able to sort between displayed items and not displayed items and draw only what's useful (if it's indeed the reason, that's a shame that QGLWidget do not support partial updates; that'd solve our problem here, I guess).

    Caching the map in a pixmap.
    This seems like a interesting idea, since we have a lot of static elements in the background. Also, as the map is modified only once in a while but scrolled far more often, caching the result seems like a perfect idea.
    The problem with that solution is that we have lots of cosmetic items, as mentioned before. This would make each zoom change a bit slow. The other problem is that we have huge variations of zoom levels, and that rendering the whole map at the maximum scale is impossible (unless there's a way to easily cache, crop and draw >2Go bitmaps I haven't heard of ^^).
    I've also been unable to paint directly on a QQraphicsView: attempts to create a QPainter in the paintEvent method all failed with a "Widget painting can only begin as a result of a paintEvent" error. And I can't see any other way to circumvent items drawing if I cache the scene with a custom call to QGraphicsView::render.

    Not using transparency.
    Most of my items use alpha blending; it's nicer that way. :)
    I've tried to disable transparency by ensuring all alpha values were set to 1. This didn't change anything, which surprised me. I suppose there is a way to totally deactivate transparency (which prevent Qt from doing the calculations at all), but I haven't been able to find anything relevant yet.

    Not having three items for each element
    That might seem obvious, as it would cut by a solid three the rendering time. But this is not as easy as it might seem. One of the problems is that most elements are interactive. I can click on them and act with them (also they're raised when clicked). As the picture above shows, I might interact without knowing it with items that are not on the "main map" but on one of the duplicates on the sides. As most of the interaction is custom-made (my custom mousePressEvent method uses "itemsAt" to know what item was clicked), I suppose I COULD wrap all interactions to shift user input, but then how would I manage to draw everything thrice?


    Questions
    So I'm left with this issue: I can't find a way to cache the map; I can't seem to find a way to draw each item only once and then "copy / paste" the rendered result; I can't find a way to simulate partial rendering.

    So, a few questions: are there rendering tweaks I might haven't heard of? Is there a way to speed up polygons rendering, maybe by caching calculations as OpenGL call lists would? Is the use of QGraphicsItemGroup for scattered items a problem as far as cropping go? Is there a way to simulate partial rendering with QGLWidget?

    Thank you if you made it that far. ^^
    I'm open to all suggestions or leads; thank you in advance for your time.

  2. #2
    Join Date
    Jan 2011
    Location
    Netherlands
    Posts
    17
    Thanks
    4
    Thanked 5 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Performance issue with complex QGraphicsScene

    At the moment I am dealing with a similar problem. Also using qgraphicsview / scene with rendering done by opengl.

    Some tricks that work for me are:

    Caching the more expensive drawing items in a pixmap. For this to work I had to
    increase the pixmap cachesize in the main routine.
    Qt Code:
    1. // Item is cached into a pixmap
    2. setCacheMode(QGraphicsItem::DeviceCoordinateCache);
    3.  
    4. QPixmapCache::setCacheLimit(102400);
    To copy to clipboard, switch view to plain text mode 

    Caching the background drawing:
    Qt Code:
    1. _ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
    To copy to clipboard, switch view to plain text mode 

    Disable indexing because I have many moving items:
    Qt Code:
    1. //If your scene uses many animations and you are experiencing slowness,
    2. //you can disable indexing by calling setItemIndexMethod(NoIndex).
    3. _scene->setItemIndexMethod(QGraphicsScene::NoIndex);
    To copy to clipboard, switch view to plain text mode 

    Scaling down the number of samples used for anti-aliasing:
    Qt Code:
    1. fmt.setSampleBuffers(true);
    2. fmt.setSamples(2);
    3. _ui->graphicsView->setViewport(new QGLWidget(fmt));
    To copy to clipboard, switch view to plain text mode 

    These tricks give some advantage but I am still looking for better tricks to have a satisfactory result...

  3. The following user says thank you to Stef for this useful post:

    Nicuvëo (20th January 2011)

  4. #3
    Join Date
    Jan 2011
    Posts
    9
    Thanks
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Thumbs up Re: Performance issue with complex QGraphicsScene

    Quote Originally Posted by Stef View Post
    Caching the more expensive drawing items in a pixmap. For this to work I had to increase the pixmap cachesize in the main routine.
    I tried that already; the problem is that I have lots of small items instead of a few expensive ones.

    Quote Originally Posted by Stef View Post
    Caching the background drawing.
    Already tried, also... but my background is currently nothing more than a pixmap, so nothing gained here either. ^^

    Quote Originally Posted by Stef View Post
    Disable indexing because I have many moving items.
    My items aren't moving (yet), but I'll remember that tip when I try to introduce such features.

    Quote Originally Posted by Stef View Post
    Scaling down the number of samples used for anti-aliasing.
    Aaah, this one is useful.
    It does indeed give a bit of a boost to the rendering speed, without looking as ugly as no anti-aliasing at all.

    Quote Originally Posted by Stef View Post
    These tricks give some advantage but I am still looking for better tricks to have a satisfactory result...
    It is a first step in the right direction. Thanks a lot!

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Performance issue with complex QGraphicsScene

    I can suggest a couple of things to try:
    1. enable caching for items (as suggested by my preposter but with ItemCoordinateCache)
    2. set ItemHasNoContents flag on all items that paint nothing
    3. set "interactive" property of the view to false if you don't need your scene to be clickable
    4. make shapes as simple as you can, if you scale use the level of detail information to avoid painting things that can't be noticed by the user
    5. make use of drawBackground() and drawForeground() instead of having items that cover the whole scene
    6. avoid clipping
    7. try using the raster engine instead of OpenGL.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. The following user says thank you to wysota for this useful post:

    Nicuvëo (20th January 2011)

  7. #5
    Join Date
    Jan 2011
    Posts
    9
    Thanks
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Performance issue with complex QGraphicsScene

    Quote Originally Posted by wysota View Post
    1. enable caching for items (as suggested by my preposter but with ItemCoordinateCache)
    As I answered, I don't have any expensive item, but lots of small ones. But I'll try on some of them.

    Quote Originally Posted by wysota View Post
    2. set ItemHasNoContents flag on all items that paint nothing
    Thanks for that! It doesn't seem to do a lot, though, as my empty objects reimplement both paint and boundingRect as empty methods.

    Quote Originally Posted by wysota View Post
    3. set "interactive" property of the view to false if you don't need your scene to be clickable
    Done that! Doesn't seem to have a huge impact on rendering speed, but worth setting anyway.

    Quote Originally Posted by wysota View Post
    4. make shapes as simple as you can, if you scale use the level of detail information to avoid painting things that can't be noticed by the user
    Shapes are already simple, but I can indeed try to simplify things when zoomed out... I'll try to see what I can do!

    Quote Originally Posted by wysota View Post
    5. make use of drawBackground() and drawForeground() instead of having items that cover the whole scene
    Hmmmmm... The thing is that most of my scene is made of distinct "interactive" elements... But for the static elements that might be a very good idea! Ill try that.

    Quote Originally Posted by wysota View Post
    6. avoid clipping
    I'm sorry to ask, but could you be more specific? Do you mean that I should avoid items on top of others?

    Quote Originally Posted by wysota View Post
    7. try using the raster engine instead of OpenGL.
    Three whole seconds to render the scene. ^^"


    Thanks for your answer anyway, I'm going to try to move the static elements in drawBackground and I'll let you know how that improves the rendering speed.


    Added after 17 minutes:


    So... I tried moving some static elements of the map (the aforementioned rivers) in DrawBackground. So instead of having ~1000 QGraphicsPolygonItems, I have ~1000 painter->drawPolygon in WorldView::DrawBackgorund (WorldView being my subclass of QGraphicsView). Strangely enough it is now slower than it was before...
    Another strange thing: caching background does not work. It is WAY slower, and it glitches (a the new part of the screen seems to be redrawn on the previous, or something like that).

    Would it do any difference if I was drawing in QGraphicsScene::DrawBackground instead of QGraphicsView::DrawBackground?
    Last edited by Nicuvëo; 20th January 2011 at 16:22.

  8. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Performance issue with complex QGraphicsScene

    Quote Originally Posted by Nicuvëo View Post
    As I answered, I don't have any expensive item, but lots of small ones. But I'll try on some of them.
    Caching for small items is more important than caching for big items as the cost of preparing painting is relatively bigger for simpler items (compared to painting them).

    Thanks for that! It doesn't seem to do a lot, though, as my empty objects reimplement both paint and boundingRect as empty methods.
    It does a lot. It makes GraphicsView skip preparing transformation matrices for your empty items.

    Done that! Doesn't seem to have a huge impact on rendering speed, but worth setting anyway.
    All those little things added together can have a significant impact.

    Shapes are already simple, but I can indeed try to simplify things when zoomed out... I'll try to see what I can do!
    This also involves things such as antialiasing and polygons.

    I'm sorry to ask, but could you be more specific? Do you mean that I should avoid items on top of others?
    If you're asking about it then you're not doing clipping.


    Three whole seconds to render the scene. ^^"
    How did you enable the raster engine?


    So... I tried moving some static elements of the map (the aforementioned rivers) in DrawBackground. So instead of having ~1000 QGraphicsPolygonItems, I have ~1000 painter->drawPolygon in WorldView:rawBackgorund (WorldView being my subclass of QGraphicsView). Strangely enough it is now slower than it was before...
    It only makes sense to do so if you cache the background and your background doesn't change in every frame. If it does, you get two blits instead of one on every frame (first to the cache and then the cache blitted to the view).

    There are more things you can do but they are really case-specific. If what takes the most time is implementation of paint() for some of your items then enabling caching for items should improve things a lot. Especially for a GL viewport.

    If you show us some of your code, I might be able to suggest some more optimizations.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #7
    Join Date
    Jan 2011
    Posts
    9
    Thanks
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Performance issue with complex QGraphicsScene

    Quote Originally Posted by wysota View Post
    If you're asking about it then you're not doing clipping.
    Thing is, I almost never reimplement paint method, as I mostly have basic primitives. I was thinking that Qt would automatically do the needed clipping... I'll try when drawing rivers in drawBackground, however.

    Quote Originally Posted by wysota View Post
    How did you enable the raster engine?
    By commenting out my line setting a QGLWidget as the viewport of my QGraphicsView. Was I wrong when supposing the raster engine was the default one?

    Quote Originally Posted by wysota View Post
    It only makes sense to do so if you cache the background and your background doesn't change in every frame. If it does, you get two blits instead of one on every frame (first to the cache and then the cache blitted to the view).
    Okay, I understand. As what triggers a redraw is almost always a change in the view (scale or centerOn being called), that's no use to me.

    Quote Originally Posted by wysota View Post
    There are more things you can do but they are really case-specific. If what takes the most time is implementation of paint() for some of your items then enabling caching for items should improve things a lot. Especially for a GL viewport.
    Most of my caching attemps ended up with thousands of X errors such as GLXBadPixmap and X using my whole CPU and my whole RAM, before crashing in a rebooting agony. It seems that enabling the cache for so many items at a time wasn't a very bright idea; I'll have to increase the cache size, methinks.

    Quote Originally Posted by wysota View Post
    If you show us some of your code, I might be able to suggest some more optimizations.
    I'll try to make a small working exemple tomorrow.

    Thanks a lot for your help, anyway!


    Added after 21 minutes:


    EDIT: my mistake, sorry...
    Last edited by Nicuvëo; 20th January 2011 at 17:37.

  10. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Performance issue with complex QGraphicsScene

    Quote Originally Posted by Nicuvëo View Post
    Thing is, I almost never reimplement paint method, as I mostly have basic primitives. I was thinking that Qt would automatically do the needed clipping... I'll try when drawing rivers in drawBackground, however.
    The thing is you don't want to do clipping because it slows things down.

    By commenting out my line setting a QGLWidget as the viewport of my QGraphicsView. Was I wrong when supposing the raster engine was the default one?
    It depends on the platform. It is the default on Windows. On other platforms you need to run your app with "-graphicssystem render" commandline switch.


    Okay, I understand. As what triggers a redraw is almost always a change in the view (scale or centerOn being called), that's no use to me.
    Background is done is scene coordinates so moving the view around the scene doesn't invalidate the background cache (I think). Scaling probably does but I'm not sure.

    Most of my caching attemps ended up with thousands of X errors such as GLXBadPixmap and X using my whole CPU and my whole RAM, before crashing in a rebooting agony. It seems that enabling the cache for so many items at a time wasn't a very bright idea; I'll have to increase the cache size, methinks.
    Use ItemCoordinateCache and not DeviceCoordinateCache. Also calculate how much memory the cache will take and compare it to the amount of memory available for your graphics card. An item size of 64x64 pixels will take about 4kB of memory. Note that for ItemCoordinateCache scaling causes the cache to be invalidated. On the other hand DeviceCoordinateCache provides worse quality in exchange for smaller memory footprint.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. #9
    Join Date
    Jan 2011
    Location
    Netherlands
    Posts
    17
    Thanks
    4
    Thanked 5 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Performance issue with complex QGraphicsScene

    I was wondering do you already have made some progress on this issue and useful tips to share? I am very interested in every aspect to make the QGraphicsView / Scene faster.

  12. #10
    Join Date
    Jan 2011
    Posts
    9
    Thanks
    3
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Performance issue with complex QGraphicsScene

    I haven't found the time to work again on that issue. I'll do (and keep this thread updated) as soon as I can.

  13. #11
    Join Date
    Apr 2009
    Location
    Valencia (Spain)
    Posts
    245
    Thanks
    38
    Thanked 19 Times in 19 Posts
    Qt products
    Qt4
    Platforms
    Symbian S60

    Default Re: Performance issue with complex QGraphicsScene

    I suppose it's because Qt is able to sort between displayed items and not displayed items and draw only what's useful (if it's indeed the reason, that's a shame that QGLWidget do not support partial updates; that'd solve our problem here, I guess).
    If you are using a QGLWidget to render

    Qt Code:
    1. setViewport(new QGLWidget)
    To copy to clipboard, switch view to plain text mode 

    don't forget to set "fullviewportupdate".


    By commenting out my line setting a QGLWidget as the viewport of my QGraphicsView. Was I wrong when supposing the raster engine was the default one?
    It depends on the platform, but in order to be sure, try:

    Qt Code:
    1. int main(int argc, char *argv[])
    2. {
    3. QApplication::setGraphicsSystem("raster");
    4. QApplication a(argc, argv);
    To copy to clipboard, switch view to plain text mode 

    Its a HUGE performance improvement. At least in my case.

    Background is done is scene coordinates so moving the view around the scene doesn't invalidate the background cache (I think).
    I though so... but it does. Caching the background is a good option if the viewport is static. When the viewport moves the big pixmap is loaded again on cache, taking too much time.


    In my opinion this video is a must if you are trying to develop a videogame with the QGraphicsView system. And if you want to have it for a mobile device (and OVI store, where Qt4.7 with QGLWidget for Symbian is still not accepted)
    http://qt.nokia.com/developer/learni...view-in-depth/

    Those are the improvements I'm using, so far.
    Last edited by jano_alex_es; 20th April 2011 at 08:34.

Similar Threads

  1. Performance of scene(QGraphicsScene) with update();
    By mukunda in forum Qt Programming
    Replies: 4
    Last Post: 14th January 2011, 12:21
  2. Performance issue
    By Skorpien126 in forum Qt Programming
    Replies: 4
    Last Post: 2nd July 2010, 16:02
  3. Bad performance of QGraphicsScene
    By miraks in forum Qt Programming
    Replies: 7
    Last Post: 23rd November 2008, 21:41
  4. QGraphicsScene performance
    By Aceman2000 in forum Qt Programming
    Replies: 4
    Last Post: 2nd June 2008, 18:10
  5. QGraphicsScene/QGraphicsView performance problems
    By bnilsson in forum Qt Programming
    Replies: 71
    Last Post: 28th January 2008, 12:08

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.