Pregunta

I created a QML application based on Qt 5.2 that I deploy on Mac OS X and Windows (from XP to 8). My application has one main animation which rotates an image indefinitely while the user is live on air. This animation is a core part of the application and I cannot remove it.

Rotating the image takes too much CPU power and I am looking for a way to fix this. The reason behind it is that lots of users are not supporting OpenGL 2 (on Windows) and I will have to rely on MESA's DLL to do the rendering in software, making the application unusable on these machines while the animation is running.

Here is my current implementation of the Animation in QML:

Image {
  id: imgBroadcastState
  source: "images/broadcast_button.png"
  anchors.horizontalCenter: parent.horizontalCenter

  NumberAnimation on rotation {
    from: 0
    to: 360
    running: rootWindow.isBroadcasting
    loops: Animation.Infinite
    duration: 7000

    onRunningChanged:{
      if(!running) {
        imgBroadcastState.rotation = 0;
      }
    }
  }
}

The first solution I tried was creating a huge sprite containing all the frames for my animation that I then loaded with AnimatedSprite. This decreased CPU but clearly not enough and more than tripled the RAM consumption, up to 300MB which is not a good solution for old Windows XP machine.

I also tried subclassing QQuickPaintedItem and manually call paint() every 30ms (with a QTimer) to rotate the image. This also decreases CPU but not enough either. Here is the code I used:

void MXPaintedItem::paint(QPainter *painter)
{
  QTransform rot;
  rot.rotate(m_angle);
  painter->setRenderHint(QPainter::Antialiasing);
  painter->setRenderHint(QPainter::SmoothPixmapTransform);
  painter->translate(width() / 2, height() / 2);
  painter->rotate(m_angle);
  // Use preloaded QImage
  painter->drawImage(QPoint(-width() / 2, -height() / 2), m_image);


  m_angle += 2.5;
}

Is there any way to improve on this and decrease the CPU usage of rotation animations?

EDIT:

Of course I could change the animation or not use one but this is not a long term solution. In the end this image will have to be drawn/updated dynamically to reflect a VUMeter and represent the sound level. So I need to find a proper solution allowing me to update part of a QML view in real-time without having to redraw the whole UI and take so much CPU.

EDIT2: I've discovered that the main CPU usage is not the rotation itself but the fact that it then has to redraw the whole UI everytime. You can make sure of this by just calling return in the paint() function instead of rotating anything. The CPU usage is the same doing this compared to animating the image itself which shows that the issue comes from updating the whole UI everytime one of the QML components in the scene is updated

¿Fue útil?

Solución 3

After investigating even more I have reached the conclusion that there is no easy way to optimize this. The best performance would be obtained through QML itself because it is optimized for caching elements and improving the scene repainting.

The main solution would be to repaint only part of a scene. This is not yet possible with QML and the new SceneGraph rendering and is not planned in the near future. This answer has been given to me by the people in charge of the development of this feature in Qt.

The CPU usage itself comes is highly dependent on the hardware and the graphic card drivers because everything is now based on OpenGL 2.0 and rely on the fact that your hardware/drivers properly support some OpenGL operations.

Otros consejos

If you have the memory space and the number of rotations is small, use one bitmap for each rotation. This is how "spinners" have been written since the beginning of computers.

The theory is that a bitblit is faster than performing a rotation transformation, then blitting the resulting image.

Next I would try taking your animation and producing an animated GIF. Whatever tool you use to produce the gif should provide you with an ability to configure the compression/optimizations to get a quality/size that you're happy with.

Then try using the QML AnimatedImage Element to display the GIF, perhaps that will provide better results.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top