Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. How to improve performance on a board without a GPU
Forum Updated to NodeBB v4.3 + New Features

How to improve performance on a board without a GPU

Scheduled Pinned Locked Moved Solved Mobile and Embedded
10 Posts 3 Posters 1.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Boofish
    wrote on last edited by Boofish
    #1

    Hello,

    I'm trying to decrease the frame rate of the rendering in a QGraphicsScene (qt version 4.8.6). but I can't seem to find which bit of code to patch (if I have to) to achieve what I want. I have found the define for the animation frame rate but I can't find how to control the frame rate for the actual rendering.

    I know that I can control the frame rate by setting viewport mode to NoViewportUpdate and using a timer to render the scene at a fixed rate but I'd like to avoid this because there is no graphics card on the board and the CPU usage goes quite high at 60% and sometimes up to 100% when I redraw repeatedly big sections of the screen (for example when I move a fader that controls a graph).

    I think I have already optimised the rendering code (so its points and paths etc are cached and the paint methods are pretty much just setBrush, setPen, drawRect/Arc/Path etc). And I already managed to improve performance a bit by using scene->setItemIndexMethod(QGraphicsScene::NoIndex) as any other option seems too slow (makes sense as the items in the scene are often moved, set to visible/hidden etc cause of animations). So it seems to me one of the few things left is to try reducing the frame rate.

    I have also tried to use directfb where I render changed items into pixmaps first, so I can use the accelerated directfb version of drawRect and drawPixmap (all other functions seem to be falling back to software rendering) but this seems even slower.

    So is it possible to reduce/control the rendering frame rate? I suspect that Qt targets 60fps?

    1 Reply Last reply
    0
    • B Offline
      B Offline
      Boofish
      wrote on last edited by Boofish
      #7

      Hello,

      Yes I would prefer to update the graph when the mouse moves rather than just when it stops. I have actually figured out a solution.

      I noticed that everything behind the graph is also rendered when I update the graph, as expected I guess since there's no depth test. So I basically just implemented a custom depth test.

      I added a "isTransparent" variable in my base class which inherits from QGraphicsItem. Then everytime QGraphicsView::paintEvent runs I create a path from the exposed region, iterate from front to back through the items that are about to be redrawn and test if the item still intersects the exposed region. If the item is not transparent I subtract it from the region (at which point it becomes a polygon) and continue to test and subtract (if its opaque) the next item.

      This hacked depth test seems to be getting rid of a lot of the items that are about to be redrawn. Something like half of them because there are quite a few opaque backgrounds and whatnot in the app. Its pretty fast too for a depth test.

      Now I wonder, is there actually anything in qt that already does this that I could use instead? I noticed some members called "exposed" and "opaque" before, but when I tried to use them they seemed really expensive. In any case my solution seems to be working pretty well.

      Here is the code btw:

      void GraphicsView::paintEvent(QPaintEvent* event)
      {
          const QRectF exposedRegion = mapToScene(event->region().boundingRect()).boundingRect();
      
          QPainterPath path;
          path.moveTo(QPointF(exposedRegion.x(), exposedRegion.y()));
          path.lineTo(QPointF(exposedRegion.x() + exposedRegion.width(), exposedRegion.y()));
          path.lineTo(QPointF(exposedRegion.x() + exposedRegion.width(), exposedRegion.y() + exposedRegion.height()));
          path.lineTo(QPointF(exposedRegion.x(), exposedRegion.y() + exposedRegion.height()));
      
          bool allItems = false;
          QList<QGraphicsItem *> itemList = itemsInRegion(exposedRegion, &allItems, viewportTransform());
          auto item = itemList.constEnd();
      
          while (item != itemList.constBegin())
          {
              --item;
              auto view = dynamic_cast<View*>(*item);
              if (view)
              {
                  auto x = std::max(exposedRegion.x(), view->scenePos().x());
                  auto y = std::max(exposedRegion.y(), view->scenePos().y());
                  auto z = std::min(exposedRegion.x() + exposedRegion.width(), view->scenePos().x() + view->size().width());
                  auto w = std::min(exposedRegion.y() + exposedRegion.height(), view->scenePos().y() + view->size().height());
      
                  QPainterPath subviewPath;
                  subviewPath.moveTo(QPointF(x, y));
                  subviewPath.lineTo(QPointF(z, y));
                  subviewPath.lineTo(QPointF(z, w));
                  subviewPath.lineTo(QPointF(x, w));
      
                  auto intersection = path.toFillPolygon().intersected(subviewPath.toFillPolygon());
                  if (intersection.isEmpty())
                  {
                      view->setBlockRender(true);
                  }
                  else
                  {
                      view->setBlockRender(false);
                  }
      
                  // extract the subpath of opaque items from the path
                  if (!view->isTransparent())
                  {
                      path = path.subtracted(subviewPath);
                  }
              }
          }
      
          QGraphicsView::paintEvent(event);
      }
      

      setBlockRender sets a boolean that I check in the paint method. If it is set I unset it and exit the function without rendering. Do you reckon this code can be made even faster? I wonder if I can actually get away without creating a Path (or without converting them to fillPolygons) from the bounding rect of the item and do the intersection test by just using the rect. Or is it going to be the same thing under the hood?

      Thank you for the replies!

      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi and welcome to devnet,

        Qt doesn't have any frame rate target. It already tries to minimise the number of update it does.

        Can you explain what happens in your application ?

        Did you already tried 4.8.7 ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        2
        • B Offline
          B Offline
          Boofish
          wrote on last edited by Boofish
          #3

          Hello and thank you for the quick reply,

          I basically have a scene of items, mostly items that draw rectangles, pixmaps and text. And a couple of custom items that draw things like audio filter graphs that use drawPath for the fill and drawPolyline for the stroke. So when I move a fader that affects the graph the CPU usage goes up to 98% (Its a singlecore 500MHz Arm CPU driving a 800x480 16bit RGB screen using linuxfb driver). I've made sure that updating the path and the points for drawPath and drawPolyline is as cheap as possible and I'm just using one loop to update both of them. Commenting out the paint methods (for the fader and the graph) drops the usage pretty much down to 0-10% or so.

          Using a newer version of qt is a bit tricky as we are using buildroot and from what I see I cannot just change the qt version anywhere there. But I can try to build qt 4.8.7 manually and install it on the board. I think I'll do this next. Are there any major changes in the render engine in 4.8.7?

          1 Reply Last reply
          0
          • dheerendraD Offline
            dheerendraD Offline
            dheerendra
            Qt Champions 2022
            wrote on last edited by dheerendra
            #4

            Without seeing code we cannot comment much. But few questions.

            1. How are you doing painting ?
            2. How refresh is forced ?
            3. Is there something partof view can drawn and kept in memory only once ?

            I felt this is typical fast update issue.

            Dheerendra
            @Community Service
            Certified Qt Specialist
            http://www.pthinks.com

            1 Reply Last reply
            0
            • B Offline
              B Offline
              Boofish
              wrote on last edited by Boofish
              #5

              Hello dheerendra,

              Here is some code:

              void EQFilter::updateResponse(vector<float> inputData)
              {
                  m_points = calculatePointsForStroke();
                  m_path = calculatePathForFill();
                  update();
              }
              
              void EQFilter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
              {
                  Q_UNUSED(option);
                  Q_UNUSED(widget);
              
                  painter->setRenderHints(QPainter::Antialiasing
                      | QPainter::SmoothPixmapTransform
                      | QPainter::HighQualityAntialiasing, true);
              
                  painter->setBrush(QBrush(bandColorsAlpha[m_band]));
                  painter->drawPath(m_path);
              
                  painter->setPen(QPen(QBrush(bandColors[m_band]), 1));
                  painter->drawPolyline(m_points.data(), m_points.size());
              }
              

              So refreshing is done by calling update() function. The function updateResponse is called on a mouse move when I move a fader. There are about 4 instances of EQFilter and when a fader moves I only call updateResponse on one of them, although I noticed that the paint function runs for all the filters (I suspect cause their bounding rects are the same). I have also tried rendering each filter to a pixmap so that when I call update() I only need to call drawPixmap on all 4 of them (plus recreate the pixmap for the dirty filter) and not drawPath and drawPolyline but this is even slower. I suspect when you say save something into memory you mean a qpixmap?

              Also I have tried using removing all those hints on the painter (antialiasing etc) and that makes almost no difference either. Also as I've mentioned the code inside calculatePointsForStroke() and calculatePathForFill() is negligible as the performance goes down to around 10% when I just comment out the paint functions and I just leave the rest of the code.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #6

                Are you doing updates for each values when moving ? Otherwise you could compress that e.g. only animate on stop.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • B Offline
                  B Offline
                  Boofish
                  wrote on last edited by Boofish
                  #7

                  Hello,

                  Yes I would prefer to update the graph when the mouse moves rather than just when it stops. I have actually figured out a solution.

                  I noticed that everything behind the graph is also rendered when I update the graph, as expected I guess since there's no depth test. So I basically just implemented a custom depth test.

                  I added a "isTransparent" variable in my base class which inherits from QGraphicsItem. Then everytime QGraphicsView::paintEvent runs I create a path from the exposed region, iterate from front to back through the items that are about to be redrawn and test if the item still intersects the exposed region. If the item is not transparent I subtract it from the region (at which point it becomes a polygon) and continue to test and subtract (if its opaque) the next item.

                  This hacked depth test seems to be getting rid of a lot of the items that are about to be redrawn. Something like half of them because there are quite a few opaque backgrounds and whatnot in the app. Its pretty fast too for a depth test.

                  Now I wonder, is there actually anything in qt that already does this that I could use instead? I noticed some members called "exposed" and "opaque" before, but when I tried to use them they seemed really expensive. In any case my solution seems to be working pretty well.

                  Here is the code btw:

                  void GraphicsView::paintEvent(QPaintEvent* event)
                  {
                      const QRectF exposedRegion = mapToScene(event->region().boundingRect()).boundingRect();
                  
                      QPainterPath path;
                      path.moveTo(QPointF(exposedRegion.x(), exposedRegion.y()));
                      path.lineTo(QPointF(exposedRegion.x() + exposedRegion.width(), exposedRegion.y()));
                      path.lineTo(QPointF(exposedRegion.x() + exposedRegion.width(), exposedRegion.y() + exposedRegion.height()));
                      path.lineTo(QPointF(exposedRegion.x(), exposedRegion.y() + exposedRegion.height()));
                  
                      bool allItems = false;
                      QList<QGraphicsItem *> itemList = itemsInRegion(exposedRegion, &allItems, viewportTransform());
                      auto item = itemList.constEnd();
                  
                      while (item != itemList.constBegin())
                      {
                          --item;
                          auto view = dynamic_cast<View*>(*item);
                          if (view)
                          {
                              auto x = std::max(exposedRegion.x(), view->scenePos().x());
                              auto y = std::max(exposedRegion.y(), view->scenePos().y());
                              auto z = std::min(exposedRegion.x() + exposedRegion.width(), view->scenePos().x() + view->size().width());
                              auto w = std::min(exposedRegion.y() + exposedRegion.height(), view->scenePos().y() + view->size().height());
                  
                              QPainterPath subviewPath;
                              subviewPath.moveTo(QPointF(x, y));
                              subviewPath.lineTo(QPointF(z, y));
                              subviewPath.lineTo(QPointF(z, w));
                              subviewPath.lineTo(QPointF(x, w));
                  
                              auto intersection = path.toFillPolygon().intersected(subviewPath.toFillPolygon());
                              if (intersection.isEmpty())
                              {
                                  view->setBlockRender(true);
                              }
                              else
                              {
                                  view->setBlockRender(false);
                              }
                  
                              // extract the subpath of opaque items from the path
                              if (!view->isTransparent())
                              {
                                  path = path.subtracted(subviewPath);
                              }
                          }
                      }
                  
                      QGraphicsView::paintEvent(event);
                  }
                  

                  setBlockRender sets a boolean that I check in the paint method. If it is set I unset it and exit the function without rendering. Do you reckon this code can be made even faster? I wonder if I can actually get away without creating a Path (or without converting them to fillPolygons) from the bounding rect of the item and do the intersection test by just using the rect. Or is it going to be the same thing under the hood?

                  Thank you for the replies!

                  1 Reply Last reply
                  2
                  • B Offline
                    B Offline
                    Boofish
                    wrote on last edited by
                    #8

                    By the way it seems the title is not very related to the thread anymore. Should I change it to something like "how to improve performance on a board without a GPU" or something like that?

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #9

                      That's a good idea, it gives a better clue about what the question was about in the end.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      B 1 Reply Last reply
                      1
                      • SGaistS SGaist

                        That's a good idea, it gives a better clue about what the question was about in the end.

                        B Offline
                        B Offline
                        Boofish
                        wrote on last edited by
                        #10

                        Done. Thanks for all the help.

                        1 Reply Last reply
                        1

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved