June 5, 2019
Chromium 为了提升渲染性能,充分利用了 GPU 硬件加速,如 DOM 绘制,Canvas2D、WebGL,视频解码等,并设计了独立的 GPU 进程架构,在需要支持多种系统平台的情况下稳定运行(如Windows/MacOSX/Linux/Android等),设备 GPU 的兼容性显得尤为重要,这里基于 Chromium 源码,简单梳理一下其兼容降级逻辑的实现,主要包括两部分:GPU 特性降级和 GP U驱动 bug 兼容。
GPU 特性降级
Chromium 将使用 GPU 硬件加速的功能模块分为一个个 feature,包括常见的如 Canvas2D、WebGL、视频解码等
- Canvas 2D:GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS
- WebGL 1.0:GPU_FEATURE_TYPE_ACCELERATED_WEBGL
- WebGL 2.0:GPU_FEATURE_TYPE_ACCELERATED_WEBGL2
- 视频硬件解码:GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE
详细的 feature 定义见源码:/gpu/config/gpu_feature_type.h
然后定义了一个针对这些特性的黑名单列表( /gpu/config/software_rendering_list.json ),其实是一个json格式的规则列表文件,如果当前设备上某个feature命中规则,则该feature对应的功能降级为软件渲染(如SwiftShader),规则列表由一个个entry组成,如
{
"id": 106,
"description": "GPU raster broken on ES2-only Adreno 3xx drivers",
"cr_bugs": [480149],
"os": {
"type": "android"
},
"gl_renderer": "Adreno \\(TM\\) 3.*",
"gl_version": {
"op": "<=",
"value": "2.0"
},
"features": [
"accelerated_2d_canvas",
"gpu_rasterization"
]
}
可以看出其支持系统类型、系统版本、GPU型号、驱动版本等多个维度的规则,并且支持版本号的比较、字符串的正则匹配等,详细的格式定义见:/gpu/config/gpu_control_list_format.txt,编译的时候,使用Python脚本将json规则文件转换为C++文件(software_rendering_list_autogen.h等),其中包含 kSoftwareRenderingListEntries 数组常量,即为反序列化后的规则列表,然后在GpuControlList类中进行处理,将当前设备GPU信息进行规则匹配,从而确定各个feature是否需要降级。
目前 GPU 特性黑名单总共有160+项,且在持续维护中
- 14d3f99 Use Intel GPU generation in blacklisting by Lin Sun · 4 weeks ago
- 5c7dcc2 Use DXGI EnumAdapters to collect GPU info instead of SetupAPI. by Rafael Cintron · 5 weeks ago
- bdfacc7 Remove driver_date from gpu fallback list mechanism by Rafael Cintron · 5 weeks ago
- 777d67f Blacklist any Windows graphics drivers older than 2010. by Zhenyao Mo · 3 months ago
- 3876bf6 Remove unnecessary condition for nouveau driver blacklisting by Zhenyao Mo · 4 months ago
- 3a36018 Blacklist Metal on macOS 10.12 by Christopher Cameron · 4 months ago
- 0129383 Plumb up DRI version and change workarounds based on it by Jonathan Backer · 6 months ago
- 00ae8c0 Disable HW Acceleration on GM45 with bad driver by Eric Karl · 7 months ago
GPU 驱动 bug 兼容
前面的特性黑名单是将feature降级为软件渲染,而驱动bug兼容则是针对特定的驱动bug进行兼容处理(workaround),比如在某些设备上调用glClear不生效或闪退,需要通过draw来模拟clear,又或者Android设备上需要限制最大贴图尺寸等,每种workaround都有一个id,如"gl_clear_broken"、"max_texture_size_limit_4096"等,id列表详见/gpu/config/gpu_workaround_list.txt,目前总计有100+项,与前面的特性降级处理逻辑类似,驱动bug列表也是用json规则文件(/gpu/config/gpu_driver_bug_list.json)来记录workaround与设备、系统、GPU等维度的对应关系,如:
{
"id": 95,
"cr_bugs": [421271],
"description": "glClear does not always work on these drivers",
"os": {
"type": "android"
},
"gl_type": "gles",
"gl_version": {
"op": "<",
"value": "3.0"
},
"gl_vendor": "Imagination.*",
"features": [
"gl_clear_broken"
]
},
{
"id": 147,
"description": "Limit max texure size to 4096 on all of Android",
"os": {
"type": "android"
},
"features": [
"max_texture_size_limit_4096"
]
}
目前该规则列表总计有300+项,且在持续更新中
规则文件gpu_driver_bug_list.json也是通过Python脚本生成C++源码文件,将规则列表反序列化到kGpuDriverBugListEntries数组常量中,然后提供给底层渲染逻辑进行兼容处理,比如"gl_clear_broken"这个workaround,最终会影响到skia的绘制逻辑 ( /third_party/skia/src/gpu/gl/GrGLCaps.cpp )
if (fDriverBugWorkarounds.gl_clear_broken) {
fPerformColorClearsAsDraws = true;
fPerformStencilClearsAsDraws = true;
}
以及GPU进程的指令解码 ( /gpu/command_buffer/service/gles2_cmd_decoder.cc )
if (workarounds().gl_clear_broken) {
ClearFramebufferForWorkaround(clear_bits);
} else {
api()->glClearFn(clear_bits);
}
GPU 状态&开关
chrome上可通过访问 chrome://gpu 查看详细的GPU信息,包括Graphics Feature Status、Driver Bug Workarounds、以及各类状态信息等,如:
而访问 chrome://flags/ 则可以手动配置一些GPU相关的开关,如
其中"Override software rendering list"可以强制忽略内置的特性降级列表