在下面的QML中,唯一的动态部分是闪烁的矩形。虽然它与生成的项目无关,但闪烁的矩形会导致负载过重并降低系统速度(例如,我使用的i.MX6处理器上的CPU负载为100%),即使它与其他设备之间没有重叠/绑定项目。删除Repeater解决了问题,矩形平滑闪烁。
import QtQuick 2.3
Rectangle {
id: root
anchors.fill: parent
Repeater {
model: 10000
delegate: Rectangle {
width: 5
height: 5
x: (index % 200)*6
y: 50 + Math.floor(index / 200)*6
color: "blue"
border.color: "black"
}
}
Rectangle {
property bool blinker: false
width: 20
height: 20
color: blinker ? "green" : "red"
Timer {
running: true
interval: 100
repeat: true
onTriggered: { parent.blinker = !parent.blinker }
}
}
}
如果您具有更好的规格并且没有经历减速,则可能需要将Repeater的model: 10000
参数设置为更高的值。代码在Qt 5.3.2和Qt 5.5.0上进行测试,问题出现在两者中。
我在实际应用程序中的模型数量较少(~100),但代理程序更复杂。因此,CPU(GPU?)的使用取决于代理的复杂性+ Repeater中的模型项的数量。
为什么由Repeater生成的大量项目(或复杂项目)会影响应用程序的性能,因为它们与其他动态对象没有关系/重叠?
我已使用以下javascript代码替换Repeater
以生成具有相同属性的相同数量的对象:
Component.onCompleted: {
var objstr = 'import QtQuick 2.0;Rectangle{id:sample;width:5; height:5;color:"blue";border.color: "black"}';
for(var i=0;i<200;i++) {
for(var j=0;j<50;j++) {
var obj = Qt.createQmlObject(objstr,root);
obj.x = i * 6
obj.y = 50 + j*6
}
}
}
但是性能问题仍然存在。
我已根据this article完成了一些考试。
设置此标志会输出有关渲染和批处理的一些调试信息。测试应用程序的输出
isaac@ubuntu:~$ QSG_RENDERER_DEBUG=render ./qml-test
QML debugging is enabled. Only use this in a safe environment.
Batch thresholds: nodes: 64 vertices: 1024
Using buffer strategy: static
Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: full"
Rendering:
-> Opaque: 14002 nodes in 2 batches...
-> Alpha: 0 nodes in 0 batches...
- 0x8f0a698 [ upload] [ clip] [opaque] [ merged] Nodes: 14000 Vertices: 168000 Indices: 224000 root: 0xb3e2a90 sets: 3
- 0x8f0b310 [ upload] [noclip] [opaque] [ merged] Nodes: 2 Vertices: 8 Indices: 12 root: 0x0
Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: none"
Rendering:
-> Opaque: 14002 nodes in 2 batches...
-> Alpha: 0 nodes in 0 batches...
- 0x8f0a698 [retained] [ clip] [opaque] [ merged] Nodes: 14000 Vertices: 168000 Indices: 224000 root: 0xb3e2a90 sets: 3
- 0x8f0b310 [retained] [noclip] [opaque] [ merged] Nodes: 2 Vertices: 8 Indices: 12 root: 0x0
Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: none"
这表示项目是在2组中进行批处理的;一个有14000个节点,一个有2个节点。这似乎是我们所期望的。
此开关可视化UI上的批次。运行它显示覆盖整个UI的纯色。这意味着闪烁的矩形和小矩形将在一批中呈现:
设置clip: true
无助于强制分离批次。通过设置opacity: 0.5
闪烁矩形,我终于成功强制QML引擎将其放入另一批:
有趣的是,眨眼仍然受到大量小矩形的影响和放缓!
我尝试的最后一个标志是QSG_RENDER_TIMING
,它报告了一些用于渲染的计时信息。根据输出,实际花费的时间是渲染循环中的render
。根据Qt文档,render
时间是
渲染帧所花费的总时间,包括准备和 将所有必要的数据上传到GPU。这是总渲染 时间。不要将它与下面的净渲染渲染时间混淆。
但这对我没有帮助。到目前为止,我无法找到这个问题的根本原因。
isaac@ubuntu:~$ QSG_RENDER_TIMING=1 ./qml-test
QML debugging is enabled. Only use this in a safe environment.
qt.scenegraph.time.compilation: shader compiled in 3ms
qt.scenegraph.time.renderer: time in renderer: total=27ms, preprocess=0, updates=5, binding=0, rendering=21
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 107ms, polish=0, sync=65, render=27, swap=1, frameDelta=0
qt.scenegraph.time.renderer: time in renderer: total=1ms, preprocess=0, updates=0, binding=0, rendering=1
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 1ms, polish=0, sync=0, render=1, swap=0, frameDelta=2
qt.scenegraph.time.renderer: time in renderer: total=8ms, preprocess=0, updates=0, binding=0, rendering=8
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 255ms, polish=0, sync=0, render=8, swap=24, frameDelta=255
qt.scenegraph.time.renderer: time in renderer: total=1ms, preprocess=0, updates=0, binding=0, rendering=1
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 290ms, polish=0, sync=0, render=1, swap=28, frameDelta=297
qt.scenegraph.time.renderer: time in renderer: total=0ms, preprocess=0, updates=0, binding=0, rendering=0
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 296ms, polish=0, sync=0, render=0, swap=29, frameDelta=303
qt.scenegraph.time.renderer: time in renderer: total=298ms, preprocess=0, updates=0, binding=0, rendering=298
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 300ms, polish=0, sync=0, render=298, swap=0, frameDelta=306
qt.scenegraph.time.renderer: time in renderer: total=592ms, preprocess=0, updates=0, binding=0, rendering=592
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 593ms, polish=0, sync=0, render=592, swap=0, frameDelta=600
qt.scenegraph.time.renderer: time in renderer: total=292ms, preprocess=0, updates=0, binding=0, rendering=292
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 298ms, polish=0, sync=0, render=295, swap=0, frameDelta=305
qt.scenegraph.time.renderer: time in renderer: total=286ms, preprocess=0, updates=0, binding=0, rendering=286
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 291ms, polish=0, sync=0, render=286, swap=0, frameDelta=298
qt.scenegraph.time.renderer: time in renderer: total=291ms, preprocess=0, updates=0, binding=0, rendering=291
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 296ms, polish=0, sync=0, render=294, swap=0, frameDelta=305
qt.scenegraph.time.renderer: time in renderer: total=286ms, preprocess=0, updates=0, binding=0, rendering=286
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 292ms, polish=0, sync=0, render=286, swap=0, frameDelta=298
qt.scenegraph.time.renderer: time in renderer: total=290ms, preprocess=0, updates=0, binding=0, rendering=290
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 295ms, polish=0, sync=0, render=291, swap=0, frameDelta=301
qt.scenegraph.time.renderer: time in renderer: total=297ms, preprocess=0, updates=0, binding=0, rendering=297
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 302ms, polish=0, sync=0, render=298, swap=0, frameDelta=310
qt.scenegraph.time.renderer: time in renderer: total=290ms, preprocess=0, updates=0, binding=0, rendering=290
qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 293ms, polish=0, sync=0, render=290, swap=0, frameDelta=316
答案 0 :(得分:1)
这是一个老问题,但看起来这里没有真正的解决方案,所以我会尽力使用一些有用的零碎件。
所以,你肯定会部分地走上正确的轨道,看看批量,开始很好。我想你没有看到设置clip: true
的任何影响的原因是你可能已将它设置在错误的位置 - 你需要将它设置在底部矩形(包含Timer),或者你需要将Repeater包含在您可以剪辑的其他内容中,例如:
Item {
anchors.fill: parent
clip: true
Repeater {
...
}
}
这是因为,虽然Repeater继承了Item类型,但它有点特殊。它创建的子节点是转发器的父的父级,而不是转发器本身,因此转发器将具有剪辑集 - 但是在您的情况下没有视觉子节点应用该剪辑。
这里理想的解决方案是在包含Repeater的内容(如上所述)和底部Rectangle上设置clip: true
,以确保两个子树中的任何一个都不会影响另一个子树的性能。
然而,你注意到这并没有直接解决你的问题,所以让我们从批处理转向其他事情。
快速观察:我注意到您使用的是“basic”renderloop而不是“threaded”。是否有一个原因?用你在这里的例子不会给你带来太多的好处(因为你没有很多绑定评估,也没有其他应用可以说),但在现实世界的情况下,它应该会好一点,所以我会建议尽可能使用它。
一旦你完成了这个,你需要知道QtQuick场景图预计会运行阻塞vsync。动画和其他所有内容都与显示器的vsync相关联。当你在这个级别工作时,你需要知道你的图形设置是如何工作的,并特别注意确保你能够实现这一点。
所以,现在让我们来谈谈图片的硬件方面。我不知道你的设置是什么在imx6上,但我假设你正在使用Linux&amp; fbdev上的Vivante驱动程序和Qt的eglfs QPA插件。首先,您应该使用FB_MULTI_BUFFER
环境变量来确保您与显示的vsync相关联(即您可能需要FB_MULTI_BUFFER=2
或FB_MULTI_BUFFER=3
)。我不知道现在是否自动设置了这个,但是当我上次不得不在这样的系统上工作时,我不知道。
假设您正在使用fbdev,等待显示的机制是ioctl。你想在内核中查看你的显示驱动程序,看看它是否尊重FBIO_WAITFORVSYNC
ioctl,并编译Qt使用它(grep qtbase for FBIO_WAITFORVSYNC
- 它应该在eglfs平台插件中的某个地方)。您还会注意到它隐藏在环境变量QT_QPA_EGLFS_FORCEVSYNC
后面,所以一旦确保它构建为发出ioctl,您就会想要export QT_QPA_EGLFS_FORCEVSYNC=1
。当你在它的时候,你应该检查FBIOGET_VSCREENINFO
ioctl是否正在返回有用和正确的信息,因为eglfs将使用返回的信息来确定显示的刷新率(参见eglfs插件中的q_refreshRateFromFb)
毕竟,事情可能会有所改善。如果他们不这样做,我可以说,在类似的设置上,我遇到了无法强制渲染渲染的情况(FBIO_WAITFORVSYNC实际上无法使用),这意味着你只能这样做了你自己。我不知道这个问题有多普遍,但它可能适用于你,所以:
如果 在这种情况下,您可以调整QT_QPA_UPDATE_IDLE_TIME=x
环境变量,告诉Qt等待至少x
ms的最短持续时间,然后再绘制另一个例如,export QT_QPA_UPDATE_IDLE_TIME=32
帧至少在帧之间等待32ms,大约30 FPS。你应该谨慎对待这一点,因为它远非一个理想的场景,而且它并不是我称之为广泛“支持”的东西。