firemail

标题: Qt的QWebengine在部分win7设备上黑屏和网页突然消失的问题排查解决 [打印本页]

作者: Qter    时间: 2023-4-7 11:21
标题: Qt的QWebengine在部分win7设备上黑屏和网页突然消失的问题排查解决
https://zhuanlan.zhihu.com/p/550285855

工作中使用到了Qt的qwebengine模块来实现了一个定制化的浏览器,在测试环境下一切正常,但是到了生产上,由于设备软硬件环境五花八门(甚至有10年前设备),出现了例如黑屏,白屏的问题。经过一两个月的痛苦折磨终于找到原因。
黑屏问题
现象:软件将QWebengineView全屏显示,屏幕黑屏。该问题只是部分设备出现,且偶然发生,难以复现。后面发现,部分设备会有“wglCreateContextAttribsARB() Failed”相关报错。
问题分析:报错内容wgl和窗体的渲染相关,所以查了一下QT和QWebengine渲染相关的东西,大致如下:
Qt的渲染机制
参考链接:Qt 渲染机制_lucky-billy的博客-CSDN博客_qt渲染
QT程序有三种不同的窗体类型,包括QWidget,QGraphics,QQuick,他们的渲染机制也不相同。
同时,Qt中有3中不同的渲染方式,可通过设置环境变量来指定,相关机制可参考官网说明:
Qt for Windows - Requirements | Qt 5.15
翻译一下就是,以下三种
通过以下代码指定渲染方式,而且需要在Application创建前(创建前还是消息循环前忘记了...反正要早点设)
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
在QT5.5之后,默认使用了一种智能的动态加载方式,QT会根据部署的设备环境,自动选择合适的OpenGL实现方式。若机器上显卡驱动不支持OpenGL2.0,QT自动使用第二种通过ANGLE调用Derict3D的方式进行渲染。
QWebEngineView的页面渲染
见QWebEngine的说明:
Qt WebEngine Overview | Qt WebEngine 6.3.2
Note:The Qt WebEngine Widgets module uses theQt Quick scene graphto compose the elements of a web page into one view. This means that the UI process requires OpenGL ES 2.0 or OpenGL 2.0 for its rendering.
就是说QWebengine模块使用的是QQucik方式来将一个网页的所有元素压缩到一个网页中,所以QWebengine需要通过OpenGL ES 2.0或者OpenGL 2.0进行渲染。
对于QQuick模块,QT也提供了Quick2DRenderer方案来代替QQuick,使得QQuick应用可以不使用OpenGL,而是使用软件的Qt的栅格化引擎实现替代。相当于给出了软件渲染的形式。通过设置环境变量QMLSCENE_DEVICE=softwarecontext实现。

解决办法
通过问题设备信息收集,并未发现问题设备有什么共性,所以就打算牺牲性能,都用软件渲染,避免对环境依赖。
(通过链接(Blank window when using Qt with ANGLE on Win 7 - Stack Overflow)的第一个回答,设置环境变量QT_LOGGING_RULES=qt.qpa.gl=true,就能在日志中打印出来设备的显卡信息,以及默认动态使用渲染方式最后选择了哪种方式)
使用软件渲染,现在就存在两个要设置的环境变量,一个是使用Qt::AA_UseSoftwareOpenGL,一个是使用QMLSCENE_DEVICE=softwarecontext,经过数周大面积验证,解决了黑屏问题。
其他的点:

白屏问题
本以为黑屏解决了,结束了天天晚上开会攻坚的生活,没想到,又来个白屏。这个还更诡异,只有一个省的设备会有这个问题,也是偶发的,没法在测试环境复现。

现象
QWebEngineView在加载完网页后,突然间就消失了只剩下背景(软件整了个背景图,并且设置了网页背景透明),日志也啥都没有。

分析
这个也是在组长建议下搜索了一些QWebEngine报告的Bug,偶然发现一个bug,大概是说QWebengine模块会有个专门的进程QWebEngineProcess负责网页的渲染等相关内容,如果在运行过程中这个进程崩了,网页内容就没了,一般情况下就白屏了,在我们的软件上就是显示背景图了。
通过对QWebEngineView::renderProcessTerminated信号进行处理,发现问题设备确实是因为这个进程挂了导致的白屏。示例代码在Qt自带的例子中有(D:\Qt\Qt5.14.2\Examples\Qt-5.14.2\webenginewidgets\simplebrowser项目的webView.cpp开头)
connect(this, &QWebEngineView::renderProcessTerminated,            [this](QWebEnginePage::RenderProcessTerminationStatus termStatus, int statusCode) {        QString status;        switch (termStatus) {        case QWebEnginePage::NormalTerminationStatus:            status = tr("Render process normal exit");            break;        case QWebEnginePage::AbnormalTerminationStatus:            status = tr("Render process abnormal exit");            break;        case QWebEnginePage::CrashedTerminationStatus:            status = tr("Render process crashed");            break;        case QWebEnginePage::KilledTerminationStatus:            status = tr("Render process killed");            break;        }        QMessageBox::StandardButton btn = QMessageBox::question(window(), status,                                                   tr("Render process exited with code: %1\n"                                                      "Do you want to reload the page ?").arg(statusCode));        if (btn == QMessageBox::Yes)            QTimer::singleShot(0, [this] { reload(); });    });
例子中通过reload()恢复了页面,但这种方式只是重新加载页面,不能恢复网页原来的状态(比如运行了一些js,用户输入了内容)。目前试了几种方法,都没能在重新加载页面的同时恢复网页原来的状态。如果哪位大佬有办法欢迎补充!感激不尽!
从代码可以看到,结束原因存在4种“官方记录的经典”原因,但是问题设备都没有走到这几种case里面,错误码是536870904,查到是chrome里面的错误码,out of memory,内存问题。
同时发现问题设备在重装系统或者加了内存条之后就不会再出现白屏问题了,就通过这种方式解决了。


作者: Qter    时间: 2023-4-7 11:44
可以看一下qt5 webengine的源码,webview是用opengl进行渲染的。在一些设备上无法避免opengl的问题,建议直接使用cef3进行编程,简单、粗暴、稳定、强大。另外qt的webengine也是基于cef封装。




欢迎光临 firemail (http://firemail.wang:8088/) Powered by Discuz! X3