QML窗口大小调整/移动闪烁

19

我正在开发一个简单的 QML 应用程序,注意到与例如 QtWidgets 窗口相比,调整和移动 QML 窗口会产生难看的闪烁。

因此,我创建了两个测试应用程序来展示差异:

Qt Widgets:

enter image description here

QML:

enter image description here

如您所见,QML 版本的应用程序闪烁得非常难看,而 QtWidgets 版本则没有。当您的 UI 变得复杂时,这种情况会变得更加糟糕。

您对此有何了解?这是一个 bug 吗?是否有任何修复或解决此问题的方法?


你使用哪款显卡? - synacker
@Milovidov 我正在使用集成在Intel Core i5-3360M中的Intel HD Graphics 4000。 - Jacob Krieg
3
英特尔的OpenGL实现存在问题。尝试获取或编译不带OpenGL的Qt。在这种情况下,Qt Quick将绘制为本地小部件,例如Qt小部件解决方案。 - synacker
另外,您可以尝试更新您的图形驱动程序。 - synacker
我希望我有你的问题。你的应用程序的用户有多频繁地调整窗口大小? - Andrej Repiský
无论你如何精确计算窗口大小,人们总有不同的偏好。这是一个问题,因为用户经常会调整窗口大小以适应他们的喜好。这会给人留下不好的第一印象... - jpnurmi
4个回答

10

你可以尝试这个:

int main(int argc, char* argv[]) {
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
or
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);

第一个选项使用OpenGl2DirecX角度库(像Google Chrome一样)

第二个选项通过软件仿真使用OpenGL ...对于小程序非常好用,并且与旧操作系统如Windows XP完全兼容。

注意:您可以尝试使用Qt 5.7和新的Qtquick.Controls 2.0...性能更好... https://blog.qt.io/blog/2016/06/10/qt-quick-controls-2-0-a-new-beginning/


在我的Windows 7 PC上尝试了Qt 5.6.2和Intel Graphics 4000。使用Qt :: AA_UseOpenGLES表现更好!谢谢! - mrAlmond

3
问题在于QML应用程序的调整大小涉及到更新具有过时几何信息的窗口。解决方法是同步更新和调整大小。
由于可能会出现从更新计时器到渲染场景图的突然更新,这会在任何时候更新窗口,从而导致使用过时几何信息绘制内容。 https://bugreports.qt.io/browse/QTBUG-46074 应该使用基本或扩展同步来同步调整大小和窗口更新。目前Qt中使用并实现了基本同步,但仍需要将来自Windows Manager的窗口更新(来自计时器)与调整大小事件同步。
但是,像往常一样,还存在一些问题:
当窗口调整大小过快时,会观察到问题。由于同步事件(来自WM)应该连续发送,因此应该在上一个事件之后立即发送下一个事件:
  1. 从WM发送了_NET_WM_SYNC_REQUEST,现在大小正在改变。

  2. _NET_WM_SYNC_REQUEST被应用程序接收并处理。

  3. 接收到其他事件,例如新几何形状。

  4. ..更新内容,交换缓冲区。

  5. 将_NET_WM_SYNC_REQUEST_COUNTER发送回WM。

  6. 从WM再次发送_NET_WM_SYNC_REQUEST,大小正在改变。

  7. ..swapBuffers//问题出现在这里,当窗口正在更改其几何形状时执行更新。

  8. 再次接收和处理_NET_WM_SYNC_REQUEST。

因此,问题发生在(7)swapBuffers出现在_NET_WM_SYNC_REQUEST被发送但尚未接收/处理的情况下。

最后的结论:

  • 窗口的实际调整大小是在窗口管理器发送_NET_WM_SYNC_REQUEST之后立即开始的,而不是在应用程序接收到它时。此时,窗口甚至可能已经更新,但同步请求尚未被应用程序处理。这将使用过时的几何图形绘制内容。
  • _NET_WM_FRAME_DRAWN可以帮助在调整大小和更新之间进行同步,但是窗口管理器可能不支持(我猜测不支持)。

换句话说,基本的或扩展的同步都没有帮助(至少没有_NET_WM_FRAME_DRAWN),因为没有办法知道实际调整大小何时完成。

扩展同步协议是试图解决这个问题的一种方法,但是由于实际的几何图形更改是在不与客户端同步的情况下完成的,因此我认为如果没有_NET_WM_FRAME_DRAWN,则始终存在使用过时的几何图形更新窗口的机会。

https://lists.freedesktop.org/archives/xcb/2019-February/011280.html


1
在我的情况下,我通过添加下一个标志来解决这个问题:
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);

但这会增加其他渲染问题。或者不会。

1
在golang的therecipe/qt中,这帮助了我:
func main() {
    var format = gui.NewQSurfaceFormat()
    format.SetVersion(4, 5)
    format.SetProfile(gui.QSurfaceFormat__CoreProfile)
    format.SetRenderableType(gui.QSurfaceFormat__OpenGL)
    format.SetSwapInterval(0)
    format.SetDefaultFormat(format)
    os.Setenv("QT_SCALE_FACTOR", "1")
    ap := widgets.NewQApplication(len(os.Args), os.Args)
    ap.SetApplicationName("APP 1.1")

系统: Linux debian 10 GPU: Radeon 570
但动画速度更快是因为没有渲染所有帧...

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