Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QPainter::paintText very slow in QGraphicsView



  • It appears as through QPainter::drawText in a custom QGraphicsObject can be a major bottleneck in QGraphicsView, at least on iOS. Is there a better way to do this? I am just trying to draw text in a rectangle in an efficient and predictable way.

    Here is a video demonstrating that it doesn't take that many text objects to really slow down the drawing performance. The first part has no text and runs at full device framerate, then the second part has text and has lots of stuttering. This is on a 2018 iPad Pro w/ the very fast A12x chip.

    https://youtu.be/O2LaCFFvF-M

    And here is another video showing how the problem scales to a much larger number of items.

    https://youtu.be/fUMs_FVVRzI

    I am doing the drawing in my custom QGraphicsObject subclass like this:

    void ItemDetailsDelegate::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        if(pathItem()->dev_showPathItemShapes()) {
            PathItemDelegate::paint(painter, option, widget);
        } else if(!m_text.isEmpty()) {
            painter->save();
            painter->setFont(m_font);
            painter->drawText(QRectF(0, 0, 100000, 100000), Qt::AlignLeft, m_text);
            painter->restore();
        }
    }
    

    Here is an example heaviest stack trace from Xcode Instruments Time Profiler, where all of the time is taken up by QPainter::drawText calls like that one above.

    Screen Shot 2020-03-31 at 8.41.51 PM 2.jpg

    It also looks like QGraphicsTextItem is not much faster, as shown in the following profile trace. Any ideas on how to speed this up? Do I have to cache all text to an image and paint that instead??

    Screen Shot 2020-03-31 at 9.14.30 PM 2.jpg


  • Lifetime Qt Champion

    Hi,

    Did you check with a QGraphicsTextItem ?



  • @SGaist said in QPainter::paintText very slow in QGraphicsView:

    Hi,

    Did you check with a QGraphicsTextItem ?

    This is covered in the second profile screenshot.


  • Lifetime Qt Champion

    My bad, scrolling got me wrong.

    In that case, I would indeed go with making an image to minimize the drawing needs.

    What version of Qt is it ?

    By the way, the widget module is not at all optimized for mobile devices. Depending on what you want to do, Qt Quick might be a better choice.



  • @SGaist Yes, I certainly would have gone with a Quick model if I weren’t already three years into a QGV model. However, I have to say that QGV is quite fast on iOS. The text rendering performance appears to be much, much slower than path rendering which is interesting.

    This is with Qt-5.14.2.

    Another thing, all I am doing is scaling and planning the view. It seems as though QGV would not have to repaint anything to simply scale and pan if things were more or less cached internally. Or I wonder if there is way to take advantage of any internal coaching, if any exists? All other aspects of rendering is pretty fast, like selection boxes, dragging large number of items at once. That means that there must be something that I can do to improve this....


  • Lifetime Qt Champion

    The cache mode property comes to mind as well as the viewport update mode.



  • @SGaist said in QPainter::paintText very slow in QGraphicsView:

    The cache mode property comes to mind as well as the viewport update mode.

    As far as I understand it, the cache mode property only controls whether the background itself is cached, not the items. And the ViewportUpdateMode just controls the update regions. Neither affects a full-scene scale.

    There must be some way to improve this because dragging large numbers of items is extremely fast. That should be slower than scaling the entire scene with no actual item updates.



  • This looks like a very useful stackoverflow answer on optimizing QGV in general, though I have already implemented most of the ideas in it and haven't had success solving the problem I have here.

    https://stackoverflow.com/questions/43826317/how-to-optimize-qgraphicsviews-performance

    The thread did direct me to the item-level pixmap cache set through QGraphicsItem::setCacheMode. This will no doubt performance improvements in some instances, for example avoiding redundant QGraphicsItem::paint calls when dragging items that don't change during the drag.

    I am still seeing paint calls for each frame when zooming the entire view/scene, however.


  • Lifetime Qt Champion

    Did you already saw this wiki entry: https://wiki.qt.io/Smooth_Zoom_In_QGraphicsView ?



  • @SGaist said in QPainter::paintText very slow in QGraphicsView:

    Did you already saw this wiki entry: https://wiki.qt.io/Smooth_Zoom_In_QGraphicsView ?

    Yes. So far as I can tell QGraphicsView::scale(x, y) just does the same thing that I do except it sets the matrix on the transform first:

    What I do:

        def zoomAbsolute(self, x):
            """ Set the zoom immediately. Used for anim ticks. """
            x = min(max(.07, x), 50.0)
            self.setTransform(QTransform.fromScale(x, x))
    

    What they do:

    void QGraphicsView::scale(qreal sx, qreal sy)
    {
        Q_D(QGraphicsView);
        QTransform matrix = d->matrix;
        matrix.scale(sx, sy);
        setTransform(matrix);
    }
    

    There is actually a better example here that calls QGraphicsView::setTransformationAnchor to zoom into the mouse cursor.

    Either way, this still calls QGraphicsItem::paint on all items once every animation frame.


Log in to reply