Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-110595

[REG 5.15 -> 6.x] QSvgRenderer::render(QPainter*) is now ~100x slower

    XMLWordPrintable

Details

    • ce7b4c734 (dev), d1a32dfce (tqtc/lts-6.2), 15e007175 (6.4), b11608fa8 (6.5), 8f5075067 (dev)

    Description

      Code

      // data.h
      #ifndef DATA_H
      #define DATA_H
      
      #include <QByteArray>
      
      // Need to split this into separate file because moc trips over the raw string literal
      inline QByteArray getSvgData()
      {
          return
                  R"svg(<?xml version="1.0" encoding="UTF-8" standalone="no"?>
                  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
                  <svg width="400" height="400" version="1.1" xmlns="http://www.w3.org/2000/svg">
                      <circle style="fill:none;stroke:#c0c0c0;stroke-width:1" cx="200" cy="200" r="150" />
                  </svg>)svg";
      }
      
      #endif
      
      // main.cpp
      #include "data.h"
      
      #include <QtTest>
      #include <QObject>
      #include <QSvgRenderer>
      #include <QImage>
      #include <QPainter>
      
      class tst_MyClass : public QObject
      {
          Q_OBJECT
      
      private slots:
          void QSvgRenderer_render()
          {
              QImage img(QSize(5120, 5120), QImage::Format_ARGB32_Premultiplied);
              QPainter p(&img);
              p.fillRect(QRect(0, 0, img.width(), img.height()), Qt::transparent);
      
              QSvgRenderer renderer(getSvgData());
              renderer.setViewBox(QRectF(45., 185., 30., 30.));
              QBENCHMARK
              {
                  renderer.render(&p);
              }
              img.save("output.png");
          }
      };
      
      QTEST_MAIN(tst_MyClass)
      #include "main.moc"
      

       

      Benchmark results

      ********* Start testing of tst_MyClass *********
      Config: Using QtTest library 5.15.12, Qt 5.15.12 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2019), windows 10
      PASS   : tst_MyClass::initTestCase()
      PASS   : tst_MyClass::QSvgRenderer_render()
      RESULT : tst_MyClass::QSvgRenderer_render():
           2.2 msecs per iteration (total: 71, iterations: 32)
      PASS   : tst_MyClass::cleanupTestCase()
      Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 12342ms
      ********* Finished testing of tst_MyClass *********
      
      ********* Start testing of tst_MyClass *********
      Config: Using QtTest library 6.2.7, Qt 6.2.7 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2019), windows 10
      PASS   : tst_MyClass::initTestCase()
      PASS   : tst_MyClass::QSvgRenderer_render()
      RESULT : tst_MyClass::QSvgRenderer_render():
           180 msecs per iteration (total: 180, iterations: 1)
      PASS   : tst_MyClass::cleanupTestCase()
      Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 2623ms
      ********* Finished testing of tst_MyClass *********
      
      ********* Start testing of tst_MyClass *********
      Config: Using QtTest library 6.4.2, Qt 6.4.2 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2019), windows 10
      PASS   : tst_MyClass::initTestCase()
      PASS   : tst_MyClass::QSvgRenderer_render()
      RESULT : tst_MyClass::QSvgRenderer_render():
           180 msecs per iteration (total: 180, iterations: 1)
      PASS   : tst_MyClass::cleanupTestCase()
      Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 2926ms
      ********* Finished testing of tst_MyClass *********
      
      ********* Start testing of tst_MyClass *********
      Config: Using QtTest library 6.5.0, Qt 6.5.0 (x86_64-little_endian-llp64 shared (dynamic) release build; by MSVC 2019), windows 10
      PASS   : tst_MyClass::initTestCase()
      PASS   : tst_MyClass::QSvgRenderer_render()
      RESULT : tst_MyClass::QSvgRenderer_render():
           176 msecs per iteration (total: 176, iterations: 1)
      PASS   : tst_MyClass::cleanupTestCase()
      Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 3023ms
      ********* Finished testing of tst_MyClass *********
      

       

      Possible workaround

      If you don't need to regularly change the SVG viewport position and size, then you can get much better results by pre-rasterizing the SVG image into a QImage/QPixmap with a transparent background and then repeatedly calling QPainter::drawImage()/QPainter::drawPixmap() instead of repeatedly calling QSvgRenderer::render().

       

      Use-case

      The customer is porting an application that needs to to regularily adjust the viewport position or even change the SVG contents to generate an overlay on top of a live (large) image feed. Unfortunately, this means the workaround above cannot be used.

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              vgt Eirik Aavitsland
              skoh-qt Sze Howe Koh
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: