[Qt-interest] QGraphicsView performance issue

Alexis Ménard alexis.menard at trolltech.com
Tue May 12 10:50:57 CEST 2009


On Tuesday 12 May 2009 10:05:49 Santhosh Y wrote:
> Alexis Ménard wrote:
> > On Tuesday 12 May 2009 05:32:56 Santhosh Y wrote:
> >> Hi,
> >>
> >> As a part of optimization I did the following:
> >>
> >> - From the scene of 30,000 items,  I figured out the areas(QRectF area1,
> >> QRectF area2) which needs
> >> repainting for a "particular_functionality"
> >> ------------------------------------------------------------------------
> >>--- --------------------------- class GraphicsView :: public
> >> QGraphicsView{};
> >>
> >> void
> >> GraphicsView::paintEvent (QPaintEvent* e)
> >> {
> >>        if (particular_functionality) { // customizing the paintevent
> >>
> >>                     // painting only area1
> >>                    QPaintEvent  ar1 (area1);  // QRectF area1
> >>                    QGraphicsView::paintEvent(&ar1);
> >>
> >>                     // painting only area2
> >>                    QPaintEvent ar2 (area2);   // QRectF area2
> >>                    QGraphicsView::paintEvent(&ar2);
> >>
> >>                    particular_functionality  = false;
> >>        } else { //  normal paint events on Graphicsview
> >>              QGraphicsView::paintEvent (e); // not being disturbed
> >>        }
> >> }
> >> ------------------------------------------------------------------------
> >>--- ---------------------------
> >>
> >> The issue with the above code is that, the area1& area2 are only being
> >> repainted and the rest of the area is being erased.
> >> I am not understanding why the rest of the area is being erased.
> >>
> >> I am not using any optimization flags such as
> >> setOptimizationFlags( QGraphicsView::DontSavePainterState);
> >>
> >> Please tell me how to avoid the rest of the area from being erased.
> >> Good part of this customizing paintevent  is that, it is very fast when
> >> I am selectively painting the area.
> >
> > I would say it is because the exposed rect that you receive from the
> > paintEvent has mark all the scene as dirty (because of a previous
> > update()) and because you hi-jack the paintEvent those area that are not
> > in area1 or in area 2 won't be redrawn. This approach is not the correct
> > one. But what is slow exactly items discovery (estimateItemsInRect in
> > qgraphicsscene.cpp?) or the painting itself?
>
> In
> void QGraphicsView::paintEvent(QPaintEvent *event)
> {
> ............................................
>           // Items
>     drawItems(&painter, numItems, itemArray, styleOptionArray);
> ............................................
> }
>
> In the above drawItems () call, for dispatching itemArray it is taking
> around 2.5 seconds.
> It is slow in items discovery.

So it is not item discovery because if you have already the list of items to 
draw it means that you have already discovered them. I would say that 
drawItems has changed a lot since 4.3 so i can not really help you unless you 
upgrade to 4.5.0. Can you investigate what is slow in drawItems, and 
drawItemHelper? 

>
> >> Regards,
> >> Santhosh.
> >>
> >> Alexis Ménard wrote:
> >>> On Monday 11 May 2009 17:09:44 Santhosh Y wrote:
> >>>> Alexis Ménard wrote:
> >>>>> On Monday 11 May 2009 16:10:04 Santhosh Y wrote:
> >>>>>> Please read my comments below
> >>>>>>
> >>>>>> Alexis Ménard wrote:
> >>>>>>> On Monday 11 May 2009 15:01:52 Santhosh Y wrote:
> >>>>>>>> Santhosh Y wrote:
> >>>>>>>>> Hi,
> >>>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>>>> I added  30,000 items to the scene.
> >>>>>>>>> While updating the scene, the response from the view is very
> >>>>>>>>> slow.
> >>>>>>>>>
> >>>>>>>>> Among these 30,000 items only 3,000 items have the distinctive
> >>>>>>>>> locations and the rest of 27,000 items have the same location of
> >>>>>>>>> those 3,000 items.
> >>>>>>>>>
> >>>>>>>>> In such a scenario to improve the performance, what flags
> >>>>>>>>> I should use on the scene to improve the performance.
> >>>>>>>
> >>>>>>> If the painting (paint method) is slow on items, you can use the
> >>>>>>> cache mode, itemCoordinateCache if you have no transformations
> >>>>>>> otherwise DeviceCoordinateCache.
> >>>>>>
> >>>>>> I am not able to find the above flag for setting cache mode.
> >>>>>> I am using 4.3.3 version of Qt.
> >>>>>> I can use only cacheNone or cacheBackGround.
> >>>>>
> >>>>> OoOooOOooooOOo. Then i fully encourage you to upgrade to 4.5. Lot of
> >>>>> performance improvements has been made since 4.3.3 and those repaint
> >>>>> bugs has been
> >>>>> probably fixed. And you have more features.
> >>>>
> >>>> Is 4.5 released for windows version.
> >>>
> >>> Yes and more 4.5.1. As always Qt is cross platform all version are
> >>> released at the same time and it is the same source code anyway.
> >>>
> >>>>>>> If you trigger full updates on the scene, then you need to set the
> >>>>>>> viewportUpdate to fullviewport update because sometimes it is
> >>>>>>> slower to caculate the exact dirty area than repainting the all
> >>>>>>> scene (aka OpenGL).
> >>>>>>>
> >>>>>>>> To add to the above issue, what I have observed is that,
> >>>>>>>> paintEvent() on QGraphicsview is being called multiple times
> >>>>>>>> which is taking around 3 sec for each call to pick the items from
> >>>>>>>> the visible region for sending to
> >>>>>>>
> >>>>>>> That why we are working on an API to allow you to create your
> >>>>>>> custom indexing where you can skip some parts of the scene or
> >>>>>>> skipping items that you don't need.
> >>>>>>>
> >>>>>>>> QGraphicsScene::drawItems(QPainter* p, int numItems,
> >>>>>>>> QGraphicsItem** items, const QStyleOptionGraphicsItem* options )
> >>>>>>>>  function dispatch.
> >>>>>>>>
> >>>>>>>> Can anybody tell me how to track from where this paintEvent call
> >>>>>>>> is dispatched so many times.
> >>>>>>>
> >>>>>>> recalculateContentSize can be the source of those calls because you
> >>>>>>> query a full update (see below).
> >>>>>>>
> >>>>>>>> I have no QGraphicsView::update() calls in my code, but I have the
> >>>>>>>> QGraphicsScene::update() calls.
> >>>>>>>
> >>>>>>> Calling update on the scene is not a good idea unless you give a
> >>>>>>> rectangle to update(). Without parameter it will redraw
> >>>>>>> everything... Why do you need to update the whole scene? Updating
> >>>>>>> the content should triggers updates on items for you...
> >>>>>>
> >>>>>> I removed all the QGraphicsScene::update () calls. Still the
> >>>>>> performance have not improved.
> >>>>>>
> >>>>>>>> But none of the QGraphicsScene::update () call is immediately
> >>>>>>>> resulting a QGraphicsView::paintEvent(QPaintEvent*)
> >>>>>>>>
> >>>>>>>> My observation is that all the mutliple calls on
> >>>>>>>> QGraphicsView::paintEvent(QPaintEvent*) are resulting from the
> >>>>>>>> following stack.
> >>>>>>>> ------------------------------------------------------------------
> >>>>>>>>-- -- -- --- ---------------------------
> >>>>>>>> QGraphicsView::paintEvent(QPaintEvent * e=0x0012b550)  Line 1282
> >>>>>>>> C++ QtGuid4.dll!QWidget::event(QEvent * event=0x0012b550)  Line
> >>>>>>>> 6256 C++ QtGuid4.dll!QFrame::event(QEvent * e=0x0012b550)  Line
> >>>>>>>> 641 C++ QtGuid4.dll!QAbstractScrollArea::viewportEvent(QEvent *
> >>>>>>>> e=0x0012b550)  Line 909 + 0xc bytes    C++
> >>>>>>>>      QtGuid4.dll!QGraphicsView::viewportEvent(QEvent *
> >>>>>>>> event=0x0012b550)  Line 2324    C++
> >>>>>>>>      QtGuid4.dll!QAbstractScrollAreaPrivate::viewportEvent(QEvent
> >>>>>>>> * event=0x0012b550)  Line 78 + 0x28 bytes    C++
> >>>>>>>>      QtGuid4.dll!QAbstractScrollAreaFilter::eventFilter(QObject *
> >>>>>>>> o=0x08705aa0, QEvent * e=0x0012b550)  Line 89 + 0x29 bytes    C++
> >>>>>>>>      QtGuid4.dll!QApplicationPrivate::notify_helper(QObject *
> >>>>>>>> receiver=0x08705aa0, QEvent * e=0x0012b550)  Line 3533 + 0x1b
> >>>>>>>> bytes C++ QtGuid4.dll!QApplication::notify(QObject *
> >>>>>>>> receiver=0x08705aa0, QEvent * e=0x0012b550)  Line 3482 + 0x10
> >>>>>>>> bytes    C++
> >>>>>>>>      QtCored4.dll!QCoreApplication::notifyInternal(QObject *
> >>>>>>>> receiver=0x08705aa0, QEvent * event=0x0012b550)  Line 516    C++
> >>>>>>>>      QtCored4.dll!QCoreApplication::sendSpontaneousEvent(QObject *
> >>>>>>>> receiver=0x08705aa0, QEvent * event=0x0012b550)  Line 188 + 0x38
> >>>>>>>> bytes    C++
> >>>>>>>>      QtGuid4.dll!qt_sendSpontaneousEvent(QObject *
> >>>>>>>> receiver=0x08705aa0, QEvent * event=0x0012b550)  Line 1182 + 0xe
> >>>>>>>> bytes C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=4)  Line 1195 + 0xd bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=0, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1099    C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=4)  Line 1231 + 0x2e bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=2, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1099    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=3, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1089 + 0x20 bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=4, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1089 + 0x20 bytes    C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=4)  Line 1231 + 0x2e bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=13, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1099    C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=4)  Line 1231 + 0x2e bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=5, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1099    C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=4)  Line 1231 + 0x2e bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=40, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1099    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=41, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1089 + 0x20 bytes    C++
> >>>>>>>>
> >>>>>>>> QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecursive(QPaintDevi
> >>>>>>>>ce * pdev=0x02a0a878, const QList<QObject *> & siblings={...}, int
> >>>>>>>> index=42, const QRegion & rgn={...}, const QPoint & offset={...},
> >>>>>>>> int flags=4) Line 1089 + 0x20 bytes    C++
> >>>>>>>>      QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevice *
> >>>>>>>> pdev=0x02a0a878, const QRegion & rgn={...}, const QPoint &
> >>>>>>>> offset={...}, int flags=5)  Line 1231 + 0x2e bytes    C++
> >>>>>>>>      QtGuid4.dll!QWidgetBackingStore::cleanRegion(const QRegion &
> >>>>>>>> rgn={...}, QWidget * widget=0x0012fd58, bool
> >>>>>>>> recursiveCopyToScreen=false)  Line 1000    C++
> >>>>>>>>      QtGuid4.dll!qt_syncBackingStore(QRegion rgn={...}, QWidget *
> >>>>>>>> widget=0x0012fd58, bool recursive=false)  Line 230    C++
> >>>>>>>>      QtGuid4.dll!QETWidget::translatePaintEvent(const tagMSG &
> >>>>>>>> msg={...})  Line 3094 + 0x2b bytes    C++
> >>>>>>>>      QtGuid4.dll!QtWndProc(HWND__ * hwnd=0x000a1118, unsigned int
> >>>>>>>> message=15, unsigned int wParam=0, long lParam=0)  Line 1680 + 0xc
> >>>>>>>> bytes    C++
> >>>>>>>> ------------------------------------------------------------------
> >>>>>>>>-- -- -- --- ---------------------------
> >>>>>>>>
> >>>>>>>> Please tell me how to track the event call of paint over
> >>>>>>>> QGraphicsView.

-- 

Alexis Ménard
Software Engineer, Widgets Team 1
Qt Software, Nokia Norge AS, Sandakerveien 116, 0484 Oslo, Norway
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20090512/baef3436/attachment.html 


More information about the Qt-interest-old mailing list