如何优化基于 QGraphicsView 的应用程序的性能?
我有一个基于 Qt 图形视图框架的应用程序。
这是一款拼图游戏,基本上将像素图切割成更小的像素图(拼图块),并将它们显示为 QGraphicsView
中的 QGraphicsItem
。我希望这个应用程序能够在智能手机和平板电脑上运行。 (它已经在诺基亚 N900 和一些 Symbian 手机上运行。尚未针对 Symbian^3 进行优化。)
来源是Gitorious。
这些项目继承了QGraphicsItem
和QObject
,并具有用于pos()
和rotation(的
的 Q_PROPERTY
宏。 )QGraphicsItem
来启用使用 Qt 动画框架对它们进行动画处理。
我对项目执行转换,例如缩放和旋转(后者仅在开发中的多点触控分支中),并且我还在它们上使用 QGraphicsDropShadowEffect。
我使用 QGLWidget
作为 QGraphicsView
的视口,以便为应用程序启用 OpenGL 加速。
问题是,尽管应用程序经过 OpenGL 加速,但它一点也不流畅。 (特别是动画,特别是自从我将旋转变换添加到多点触控分支后。)显示的图形项并不多,并且没有 3D 操作或任何严重的内容,只有 2D 绘图。
我根本不是图形专家,所以我不知道为什么这个应用程序运行缓慢。我见过其他具有更复杂效果的游戏运行起来比这个流畅得多。
秘密是什么?我该如何优化这个应用程序?
I have an app which is based on the Qt Graphics View framework.
It's a jigsaw puzzle game which basically cuts a pixmap into smaller pixmaps (puzzle pieces) and displays them as QGraphicsItem
s in a QGraphicsView
. I want this app to run on smartphones and tablets. (It already runs on the Nokia N900 and some Symbian phones. Not optimized for Symbian^3 yet.)
The source is on Gitorious.
The items inherit QGraphicsItem
and QObject
, and have Q_PROPERTY
macros for the pos()
and rotation()
of the QGraphicsItem
to enable animating them with the Qt Animation framework.
I perform transformations on the items, such as scaling and rotating (the latter only in the in-development multitouch branch), and I also use QGraphicsDropShadowEffect
on them.
I use a QGLWidget
as viewport of the QGraphicsView
in order to enable OpenGL acceleration for the app.
The problem is that despite being OpenGL-accelerated, the app is not smooth at all. (Especially the animations and especially since I added the rotation transform to the multitouch branch.) There are not many graphics items displayed, and there are no 3D operations or anything serious, just 2D drawing.
I'm not a graphics expert at all, so I have no idea why this app runs slowly. I've seen other games with lot more complicated effects run a lot smoother than this.
What's the secret? How could I optimize this app?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
好吧,我等了这么久,终于找到解决方案了。
与此同时,我用 QML 重写了应用程序的 UI,令我惊讶的是,性能好多了,而且应用程序现在非常流畅。
一些结论:
源代码在这里。
Okay, I've waited for this long for a solution.
In the meantime, I've rewritten the app's UI in QML, and to my surprise, the performance is a LOT better and the app is very smooth now.
Some conclusions:
Source code is here.
我的答案是针对那些像我一样在他们的
GraphicsItem::paint()
方法中实现渲染模式逻辑的人。例如:
以下是我如何实现良好的 QGraphicsView 性能,即使是涉及多个图层的大型场景。它甚至可以支持层之间形状的动态剪切。
所以你有 setPen() 和 setBrush() 支持。
仅在需要时触发更新。
.h
.cpp
然后你的
GraphicsItem
(它继承了AbstractGraphicsItem
)变成:旧的
GraphicsItem::paint()
方法的内容是现在在GraphicsItem::updatePenAndBrush()
中,并且时不时地调用,但不是在每次绘制调用时调用。另一方面,绘画方法涉及基础知识。显然,您必须自己调用
updatePenAndBrush()
,但对我来说这并不难。这并不是我为提高绩效所做的唯一事情。我搜索了很多,并且图形视图系统有很多可能的调整,但是有了这个,我的应用程序从几乎不可用变成了实时(终于!)
My answer is for people who, like I did for a while, implement render mode logic in their
GraphicsItem::paint()
method.For example :
Here is how I achieved good QGraphicsView performance, even with large scenes involving multiple layers. It could even support dynamic clipping of shapes between layers.
so you have setPen() and setBrush() support.
trigger an update only when needed.
.h
.cpp
And then your
GraphicsItem
(which inherits ofAbstractGraphicsItem
) becomes :The contents of the old
GraphicsItem::paint()
method is now inGraphicsItem::updatePenAndBrush()
and is called every now and then, but not at every paint call. On the other side, the paint method gets to the basics.Obviously you'll have to call
updatePenAndBrush()
yourself, but it was not hard in my case.It's not the only thing I did to improve performance. I searched a lot, and there is a lot of tweaking possible for a Graphics View system, but with this one my app went from barely usable to real-time (finally!)
特别是当您在场景中移动项目时,QGraphicsScene 的索引可能需要一些更新索引的时间,从而降低性能。您可以使用 setItemIndexMethod() 调整索引。如果您不依赖 items() 或 itemAt(),这可能有助于提高性能。
然而,这是一个漫长的过程。如果场景中只有很少的项目,则性能改进可能很小。
Especially when you have moving items in a scene, QGraphicsScene's indexing may need some time to update its index, decreasing performance. You can tune the indexing by using setItemIndexMethod(). If you do not rely on items() or itemAt(), this may help increase performance.
However, this is a long shot. If you have only few items in your scene, the performance improvements may be minimal.
通常最好将 Graphicssystem 设置为“raster”(最终输出仍为 OpenGL,因为 GL Widget 作为视口)。您没有提及它,但您可以轻松尝试将“-graphicssystem raster”添加到命令行是否会产生任何改进。
Usually it is best to set the Graphicssystem to "raster" (final output will still be OpenGL because of the GL Widget as viewport). You don't mention it, but you can easily try if adding "-graphicssystem raster" to the command line yields any improvements.
根据我自己的经验,QGraphicsItem 中的图形效果确实占用大量内存和计算量。如果您在动画过渡期间使用它们,则可能会出现问题。您应该将它们取下来,看看它有多平滑,然后尝试实现您自己的效果。
From my own experience, graphics effects in QGraphicsItem is really memory and computation heavy. If you use them during the animated transitions, it could be the problem. You should take them off and see how much smoother it is then try to implement your own effects.