添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
面冷心慈的牛腩  ·  iOS 15 越狱情报·  昨天    · 
近视的卡布奇诺  ·  Visual Studio Code ...·  昨天    · 
慷慨大方的香烟  ·  netstandard2.0 ...·  1小时前    · 
另类的火柴  ·  Java SE 11 Binaries ...·  1 年前    · 
气宇轩昂的春卷  ·  使用visual studio ...·  1 年前    · 
慷慨的包子  ·  Workbook 对象 (Excel) | ...·  1 年前    · 

Qt的QWebengine在部分win7设备上黑屏和网页突然消失的问题排查解决

工作中使用到了Qt的qwebengine模块来实现了一个定制化的浏览器,在测试环境下一切正常,但是到了生产上,由于设备软硬件环境五花八门(甚至有10年前设备),出现了例如黑屏,白屏的问题。经过一两个月的痛苦折磨终于找到原因。

黑屏问题

现象:软件将QWebengineView全屏显示,屏幕黑屏。该问题只是部分设备出现,且偶然发生,难以复现。后面发现,部分设备会有“wglCreateContextAttribsARB() Failed”相关报错。

问题分析:报错内容wgl和窗体的渲染相关,所以查了一下QT和QWebengine渲染相关的东西,大致如下:

Qt的渲染机制

参考链接: Qt 渲染机制_lucky-billy的博客-CSDN博客_qt渲染

QT程序有三种不同的窗体类型,包括QWidget,QGraphics,QQuick,他们的渲染机制也不相同。

  • QWidget是最常用的UI界面类,其实现方式是对各平台对应控件的封装,通过平台自身的绘制工具绘制界面,可以直接使用OpenGL。
  • QGraphics是QT为了提升大量简单组件的渲染性能而创造的模块,不一定需要使用OpenGL。
  • QQuick是QML(一种声明式的界面编程语言)应用程序使用的QT库,从Qt Quick 2.x 起统一使用OpenGL ES 2.0 或者 OpenGL 2.0来渲染界面。渲染方式更倾向于优先使用显卡,通过硬件来加速,所以现在使用QML需要良好的显卡支持。

同时,Qt中有3中不同的渲染方式,可通过设置环境变量来指定,相关机制可参考官网说明:

Qt for Windows - Requirements | Qt 5.15

翻译一下就是,以下三种

  • Qt::AA_UseDesktopOpenGL:使用显卡的openGL库,且要求支持openGL 2.1及以上的版本。因此很多老旧设备是不满足版本要求的(windows默认的驱动版本只支持openGL1.1)。(依赖硬件,即硬件加速渲染)
  • Qt::AA_UseOpenGLES:使用Angle库来将 DirectX 11或者DirectX 9的接口转成OpenGL ES2.0的API,从而使得windows上显卡驱动不满足要求的设备也能够正常运行。(通过API封装,使得显卡驱动版本低的设备也可以正常运行)
  • Qt::AA_UseSoftwareOpenGL:纯软件实现渲染,不依赖于显卡驱动,当然也没硬件加速。

通过以下代码指定渲染方式,而且需要在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 the Qt Quick scene graph to 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,经过数周大面积验证,解决了黑屏问题。

其他的点:

  • 指定使用Qt::AA_UseOpenGLES,部分设备会出现弹窗。
  • 也尝试仅设置两个变量中的一个,都不行,会出现一些奇怪的显示问题,或者弹窗。
  • 性能问题,没做定量比较,肉眼是无法看出区别的。
  • 额外收获,之前偶发的程序崩溃问题也随着设置软件渲染消失了。


白屏问题

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


现象

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;