Qt 如何在QQuickFramebufferObject中呈现文本?

Qt 如何在QQuickFramebufferObject中呈现文本?,qt,opengl,text,qml,qtquick2,Qt,Opengl,Text,Qml,Qtquick2,动机:目前,我的QML场景中有1000个简单项目,其中一个项目以60fps的速度制作动画,因此整个场景以60fps的速度重新绘制。在我的电脑上,我的4个虚拟内核的Cpu使用率平均为15%。在目标硬件上,情况更糟——4个物理内核的Cpu使用率为60%,导致过热,导致冻结。请注意,我已经实现了一个优化:通过Loaders,卸载(滚动)视口之外的所有项目(因此,在任何给定时间只有~18个项目被加载)。我报告的性能统计是有了这个优化-没有它,情况会更糟 我的解决方案是开始在一个QQuickFramebu

动机:目前,我的QML场景中有1000个简单项目,其中一个项目以60fps的速度制作动画,因此整个场景以60fps的速度重新绘制。在我的电脑上,我的4个虚拟内核的Cpu使用率平均为15%。在目标硬件上,情况更糟——4个物理内核的Cpu使用率为60%,导致过热,导致冻结。请注意,我已经实现了一个优化:通过
Loader
s,卸载(滚动)视口之外的所有项目(因此,在任何给定时间只有~18个项目被加载)。我报告的性能统计是有了这个优化-没有它,情况会更糟

我的解决方案是开始在一个QQuickFramebufferObject中绘制所有1000个项,并停止将它们作为实际的QML项。这样,我就不会因为只有1000件(未卸载!)物品而受到Qt的惩罚

我的困境是:如何在OpenGL中绘制项目的文本部分

方法1:我知道QPainter可以直接将文本呈现到QOpenGLWidget中,但QQFBO中似乎没有这个选项

方法2:在具有
层的QML中使用单个无父
文本
项。启用:true
,设置其
文本
属性,等待1帧(使其渲染),然后获取纹理。有些丑陋和迂回;也可能是缓慢的

方法3:查看QQuickText的源代码,看看它有什么魔力,然后复制它。可能很难,我必须遵守许可证限制

方法4:使用QPaint将软件渲染到QImage,然后将该图像上载到纹理。优雅,但可能太慢


有什么建议可以解决这些方法中的问题吗?

不完全清楚为什么渲染一个项目会使整个场景重新绘制。但如果只有一个项目正在设置动画,则可能需要分割场景。那些不移动的应该放在父项中,移动的可以放在外部

有一种相当简单的方法可以将子树渲染到FBO,只需将子树渲染到不执行任何操作的FBO即可

此示例使用灰度着色器()渲染图像:

ShaderEffect只是一个“渲染到纹理”(render to texture),您可以看到一个矩形中填充了对象的图片。在本例中,错觉仍然存在,但动画对象仅处理单个纹理矩形

我不知道这是否是解决办法,因为问题似乎在别处。请详细说明你的问题,我可能会根据需要更新答案


我知道这似乎是你的第二种方法,但在这种情况下,你渲染纹理你的整个不变的子树。如果我可能猜到,你似乎有一次又一次的滚动文本批处理到GPU,因为一些滚动动画,如果你使用ShaderEffect和一长条项目,你可以只设置滚动窗口的动画,并始终保持文本静态,避免批处理。

不完全清楚为什么渲染一个项目会使整个场景重新绘制。但如果只有一个项目正在设置动画,则可能需要分割场景。那些不移动的应该放在父项中,移动的可以放在外部

有一种相当简单的方法可以将子树渲染到FBO,只需将子树渲染到不执行任何操作的FBO即可

此示例使用灰度着色器()渲染图像:

ShaderEffect只是一个“渲染到纹理”(render to texture),您可以看到一个矩形中填充了对象的图片。在本例中,错觉仍然存在,但动画对象仅处理单个纹理矩形

我不知道这是否是解决办法,因为问题似乎在别处。请详细说明你的问题,我可能会根据需要更新答案


我知道这似乎是你的第二种方法,但在这种情况下,你渲染纹理你的整个不变的子树。如果我可能猜到,你似乎有一次又一次的滚动文本批处理到GPU,因为一些滚动动画,如果你使用ShaderEffect和一长条项目,你可以只设置滚动窗口的动画,并始终保持文本静态,避免批处理。

您是否查看过QML profiler的输出,以了解什么占用了这么多的处理时间?@KubaOber:是的,我查看过;在QML中花费的时间微不足道。因此,我在C++剖析器(CODEXL)中运行了应用程序,发现绝大多数时间都花在了视频卡的驱动程序中,无论是什么奇怪的原因。这在Windows和Linux中都发生过。当我使用我的AMD视频卡时,我使用我的英特尔视频卡(我有可切换的图形)。C++分析器无法计算出在驱动程序中花费的时间。这些时间到底花在了什么特别的功能上?@KubaOber:奇怪,这次它给了我不同的结果。大部分时间花在
QSGRootNode::~QSGRootNode()
,因为它调用
QSGNodeUpdater::isnodeblock(QSGNode*,QSGNode*)const
。我查看了Qt源代码,但还没有弄清楚为什么它会调用前者。我将在另一个问题中发布一个测试用例,并为您提供一个链接。@KubaOber:请查看测试用例。您是否查看了QML profiler的输出,以了解什么占用了这么多的处理时间?@KubaOber:是的;在QML中花费的时间微不足道。因此,我在C++剖析器(CODEXL)中运行了应用程序,发现绝大多数时间都花在了视频卡的驱动程序中,无论是什么奇怪的原因。这在Windows和Linux中都发生过。当我使用我的AMD视频卡时,我使用我的英特尔视频卡(我有可切换的图形)。C++分析器无法计算出在驱动程序中花费的时间。这些时间到底花在了什么特别的功能上?@KubaOber:奇怪,这次它给了我不同的结果。大部分时间都花在
QSGRootNode::~QSGRootNode()
,因为它调用
QSGNodeUpdater::isnodeblock(QSGNode*,
import QtQuick 2.0

Rectangle {
    width: 200; height: 100
    Row {
        Image { id: img;
                sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
        ShaderEffect {
            width: 100; height: 100
            property variant src: img
            vertexShader: "
                uniform highp mat4 qt_Matrix;
                attribute highp vec4 qt_Vertex;
                attribute highp vec2 qt_MultiTexCoord0;
                varying highp vec2 coord;
                void main() {
                    coord = qt_MultiTexCoord0;
                    gl_Position = qt_Matrix * qt_Vertex;
                }"
            fragmentShader: "
                varying highp vec2 coord;
                uniform sampler2D src;
                uniform lowp float qt_Opacity;
                void main() {
                    lowp vec4 tex = texture2D(src, coord);
                    gl_FragColor = vec4(vec3(dot(tex.rgb,
                                        vec3(0.344, 0.5, 0.156))),
                                             tex.a) * qt_Opacity;
                }"
        }
    }
}