Chromium 的 GPU 兼容方案

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+项,且在持续维护中

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"可以强制忽略内置的特性降级列表