在QML中旋转图像时降低CPU使用率

4
我创建了一个基于Qt 5.2的QML应用程序,我在Mac OS X和Windows(从XP到8)上部署它。我的应用程序有一个主要动画,它无限旋转一个图像,同时用户正在直播。这个动画是应用程序的核心部分,我不能将其删除。
旋转图像需要太多的CPU功率,我正在寻找解决方法。原因是许多用户不支持OpenGL 2(在Windows上),我将不得不依靠MESA的DLL在软件中进行渲染,使应用程序在这些机器上无法使用,而动画正在运行。
以下是我的当前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;
      }
    }
  }
}

我尝试的第一个解决方案是创建一个包含所有动画帧的大精灵,然后用AnimatedSprite加载它。这减少了CPU使用率,但显然还不够,并且将RAM消耗增加了三倍以上,高达300MB。对于旧的Windows XP机器来说,这不是一个好的解决方案。
我还尝试了子类化QQuickPaintedItem,并手动每30ms调用paint()(使用QTimer)来旋转图像。这也减少了CPU使用率,但仍然不够。以下是我使用的代码:
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;
}

有没有办法改善这个问题并减少旋转动画的 CPU 使用率?
编辑: 当然,我可以更改动画或者不使用动画,但这并不是长期解决方案。最终,这张图片将需要动态绘制/更新以反映音量计并表示声音级别。因此,我需要找到一个适当的解决方案,允许我实时更新 QML 视图的一部分,而无需重新绘制整个 UI 并占用大量 CPU。
编辑2: 我发现主要的 CPU 使用率不是旋转本身,而是每次必须重新绘制整个 UI。您可以通过在 paint() 函数中调用 return 而不是旋转任何内容来确保这一点。这样做与对图像本身进行动画处理时的 CPU 使用率相同,这表明问题来自于每次更新场景中的一个 QML 组件时更新整个 UI。

你为什么要使用Mesa?你有看过ANGLE吗?(参考链接:http://qt-project.org/wiki/Qt-5-on-Windows-ANGLE-and-OpenGL,http://code.google.com/p/angleproject/) - Arpegius
是的,我目前正在使用ANGLE,但它不支持XP,并且只能在我的客户机器的一半上工作,即使使用ANGLE,在其他Windows机器上启动应用程序时,仍然会有一些用户出现空白框架的情况。 - koopajah
1
Arpegius > 在经过6个月的QtQuick 2.0/QtQuick.Controls开发后,我不想回到QtQuick 1.0。 - koopajah
@koopajah,你能发布一下你正在使用的图片或者与之相似的东西吗?这有助于展示动画中的一些优化。 - Matthew
无论您采取什么图像,CPU使用率都是相同的,即使绘制基本矩形并旋转它也几乎需要同样多的CPU。 - koopajah
显示剩余5条评论
3个回答

0
接下来,我建议您尝试将动画制作成动态GIF。无论您使用哪种工具来制作GIF,都应该提供您配置压缩/优化选项的能力,以获得您满意的质量和大小。
然后,尝试使用QML AnimatedImage Element 来显示GIF,也许这会带来更好的效果。

我尝试过的第一个解决方案,但这需要与NumberAnimation一样多的CPU。 - koopajah

0

经过进一步的调查,我得出结论,没有简单的方法来进行优化。最佳性能将通过 QML 本身实现,因为它经过了优化以缓存元素并提高场景重绘。

主要解决方案是只重绘部分场景。这在 QML 和新的 SceneGraph 渲染中还不可能,并且近期也没有计划。这个答案是由 Qt 开发团队负责人给我的。

CPU 使用率本身高度依赖于硬件和显卡驱动程序,因为现在所有操作都基于 OpenGL 2.0,并依赖于您的硬件/驱动程序是否正确支持一些 OpenGL 操作。


0
如果您有足够的内存空间并且旋转次数较少,可以为每个旋转使用一个位图。自计算机问世以来,“旋转菜单”一直是这样编写的。
理论上,使用位块传输操作比执行旋转变换,然后再传输结果图像要快得多。

这不就是创建一个精灵并将其加载到“AnimatedSprite”中吗?我已经尝试过了。问题的一部分是完整旋转需要7秒钟,而我至少需要30 fps(除非你真的看到它滞后),这导致在同一精灵中有210帧,因此使用至少250MB的额外内存,但仍然太多CPU。问题的一部分是每次帧改变时都需要重新绘制整个场景,这成本太高。 - koopajah
@koopajah,你不应该需要那么多帧。让我们来谈谈一个简单的例子,比如“进度轮”(Google一下)。你应该能够用较少的帧数创建类似的动画,可能是12个左右,根据复杂程度可能会稍微多一些。 - Matthew
@koopajah 或者为什么不探索其他选项来简化你的问题呢?比如一个大而明亮的红色按钮,上面写着“正在直播”?这在广播室外展示是相当标准的,为什么不在你的用户界面上显示呢?或者只是一个闪烁的红色动画,类似于录音机的显示方式?这两种方法都会极大地简化你的问题。 - Matthew
1
因为动画是我们应用/品牌的核心部分,仅仅因为它在计算机上占用太多CPU而将其删除似乎有点疯狂。对于帧数,我不认为我可以只用12个帧旋转图像而不会出现延迟,除非它每秒旋转一次,当然这不是我的情况。此外,这并不是我们计划在应用程序中拥有的唯一动画,因此我们正在寻找长期解决方案,而不仅仅是针对这一个的hack方法。 - koopajah
@koopajah,你说得对。对于一个建议(例如动画每秒钟12帧),你可以使用 Timer 并在 onTrigger 事件处理程序中通过增加图像的 rotation 属性30(通过12除以360)来实现。这将大大降低 CPU 使用率。 - S.M.Mousavi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接