006.RenderEnginge 初始化
1. RenderEngine 在 SurfaceFlinger 中的角色
HWC (硬件合成器) 是 Android 图形系统中负责高效合成图层(Layer)的硬件模块,但它并非万能。其处理能力受限于特定的硬件实现。当遇到超出其硬件能力或设计范围的复杂操作时,HWC 便会将这些图层标记为需要由 GPU(通过 SurfaceFlinger 的 RenderEngine)来处理.
以下是常见的 HWC 无法处理或处理效率较低,从而需要回退到 GPU 进行合成的常见图层操作:
超出叠加层数量限制
每款 SOC 硬件支持的叠加层(Overlay)数量是有限的。虽然 Android 要求至少支持 4 个叠加层(例如状态栏、系统栏、应用界面和壁纸),但当屏幕上的图层数量超过这个限制时,超出的图层就无法通过 HWC 直接合成,需要由 GPU 处理。复杂的 Alpha 混合与透明度处理
- 每像素 Alpha 混合 (Per-Pixel Alpha Blending):当图层需要根据每个像素的 Alpha 值进行精细的透明度混合时(例如不规则形状的遮罩或渐变透明),这对 HWC 来说计算量较大,可能无法高效处理。
- 多层透明度叠加:若多个半透明图层相互叠加(例如一个半透明的 UI 控件叠加在另一个半透明图层上),混合计算会变得复杂,HWC 可能无法胜任。
受保护的内容:出于数字版权保护(如 DRM)的要求,播放受保护视频等内容时,往往需要专用的安全硬件路径。如果 HWC 硬件没有提供这样的路径,这些受保护的图层就无法通过 HWC 合成,必须由支持安全渲染的 GPU 来处理
复杂的几何变换与定位
- 旋转和缩放:某些 HWC 实现可能对图层的旋转角度(非 90° 的倍数)和缩放比例支持有限。
- 不规则定位和重叠:当图层之间存在复杂的重叠关系,尤其是结合了透明度混合时,HWC
高阶视觉特效:许多常见的 UI 特效超出了 HWC 的标准处理能力,例如:
- 模糊 (Blur):实时模糊效果需要读取下方图层的内容并进行像素处理,HWC 通常无法直接支持。
- 圆角 (Round Corners):尤其是当多个带有圆角的图层相互重叠时,GPU 处理起来更加灵活。
- 色彩效果:如色相调整、饱和度调整、灰阶等,这些通常由 GPU 处理。
其他特定操作
- 色彩格式:如果图层使用了 HWC 不支持的色彩格式(某些特殊的 YUV 格式或 RGB 压缩格式),也无法直接通过 HWC 处理。
- 边带流 (Sideband Streams):用于持续更新的视频流等场景,需要 HWC 具备 HWC2_CAPABILITY_SIDEBAND_STREAM能力,否则无法处理()
小结:
- RenderEngine 是 Android 图形合成系统 SurfaceFlinger 中的核心软件渲染引擎,主要负责处理那些无法通过硬件合成器 (HWC) 直接完成的图层操作,确保复杂图形效果能够被正确且高效地渲染到屏幕上。
- RenderEngine 在执行复杂图层的合成时,会使用到图形编程技术来进行图层的合成操作,在分析 RenderEngine 源码之前,我们需要先了解图形编程相关的基础。
2. 什么是图形编程,为什么需要图形编程
早期的计算机,屏幕上只能显示简单的命令行界面,随着计算机系统的发展,屏幕上可以展示出复杂的图形和动画了,这些图形和动画都依赖于图形编程。图形编程可以简单理解为通过编写代码来组织和下达指令,最终由 GPU 执行指令,生成显示 buffer,显示 buffer 发送给屏幕后,屏幕就会根据 buffer 中的数据进行显示。
图形编程历史上经历了几个阶段:
手工作坊式的硬件编程:早期(如 IBM PC 及其兼容机),开发者常需直接操作图形硬件。他们要了解不同图形卡(如 CGA、EGA、Hercules)的内存布局、调色板等细节,编写代码将数据移动到显存特定位置来显示内容。这个过程繁琐且易出错,虽然能榨取硬件极限性能,但开发效率低,代码可移植性差。
专用 API 与图形库的萌芽:为简化开发,一些专用 API 和图形库出现:
- IRIS GL:Silicon Graphics: SGI 公司为其工作站开发的专有图形 API,在 90 年代初是事实上的行业标准 3D 图形库。但它与 SGI 平台紧密耦合,移植性差,且包含非图形功能(如窗口、键盘、鼠标API)。
- Glide(不是图片加载库 glide):3Dfx 公司为其 Voodoo 显卡设计的 API,性能极高,一度是游戏开发首选。但它是厂商锁定的,随着 3Dfx 衰落而消失。
- Borland Graphics Interface (BGI):Borland 公司为其经典的 DOS 时代编程工具(如 Turbo Pascal 和 Turbo C/C++)开发的一套图形编程库。它极大地简化了在 DOS 环境下进行图形编程的复杂度,是许多早期程序员接触图形学的启蒙工具
OpenGL 时代来临:在 OpenGL 诞生之前,图形硬件制造商众多,每家都可能提供自己的编程接口或库。开发者若想应用/游戏支持更多硬件,就需为不同硬件编写不同代码,或依赖硬件商提供的库,工作量巨大。SGI 公司为了推动一个真正开放、跨平台的标准,并应对市场上其他图形硬件供应商(如Sun、HP、IBM 等通过扩展 PHIGS 进入市场)带来的竞争压力,决定在 IRIS GL 的基础上,开发一个全新的、开放的、与硬件无关的图形接口,这就是 OpenGL,在 1992 年 7 月推出了 1.0 版本。OpenGL(Open Graphics Library,开放图形库)的推出是图形计算领域发展的一个重要里程碑。解决了图形编程碎片化问题。它通过定义一个跨平台、开放的标准图形接口,将开发者从为各种硬件编写特定驱动和代码的繁重工作中解放出来。硬件厂商则负责根据 OpenGL 标准实现自己的驱动程序。这种分工大大推动了 3D 图形应用的发展和平民化。
随着对性能要求的提升,更底层的 API 应运而生。它们将更多控制权交给开发者,以减少驱动开销,更好地利用多核 CPU 和现代 GPU 架构。
- Vulkan:由 Khronos Group 制定,是 OpenGL 的继任者。它提供低层次控制 API、支持多线程优化、更高效的资源管理,性能强大,适合高性能应用和多线程,但使用复杂,学习曲线陡峭。是许多 3A 游戏和高级图形应用的选择。
- DirectX 12:微软开发的高性能图形和计算API,支持低层次控制和硬件加速。仅限 Windows 和 Xbox 平台。其集成度较高,控制较少
- Metal:苹果公司为其生态系统打造的图形 API,为 Apple 硬件进行了深度优化,旨在提供低开销和高性能,是开发 macOS 和 iOS 平台高性能应用的首选。
简单理解,图形编程就是利用一个行业通用的接口标准(OpenGL Vulkan 等)编写代码,这些代码向 GPU 下达指令,GPU 收到指令后,根据指令绘制显示 Buffer。OpenGL Vulkan 只是一些接口,具体的实现需要 GPU 硬件厂商去做实现。厂商通常会提供相应的 so 库给到客户。
3. Android 平台图形编程接口
Android 平台上的图形渲染主要由 OpenGL ES 、Vulkan 和 Skia 这三项技术协同支撑。
在应用层,主要使用 OpenGL ES,Vulkan 进行图像编程,应用的类型主要有:
- 游戏类应用,通常使用了游戏引擎(如 Unity、Unreal Engine),游戏引擎会使用 OpenGL ES 或 Vulkan 进行图形渲染。
- 增强现实 (AR) 与虚拟现实 (VR)
- 当你使用 AR 测量工具将虚拟尺子“放在”真实桌面上,或使用宜家 App 预览虚拟家具时,OpenGL ES 在背后做这两件事:1. 渲染虚拟的 3D 模型;2. 通过算法将模型准确地“锚定”在摄像头画面的特定位置和角度上,并处理遮挡关系(如虚拟椅子被真实桌腿挡住)。
- VR 游戏或观影应用需要为每只眼睛渲染一个略有不同的视图,并保证极高的帧率以避免眩晕。OpenGL ES 的高性能渲染能力是提供沉浸式体验的基础。
- 数据与科学可视化
- 医学影像:渲染 MRI、CT 扫描得到的三维体数据,让医生能进行虚拟“剖切”和旋转观察,辅助诊断。
- 地理信息与工程:渲染数字高程模型、复杂的 3D 建筑模型、机械设计图,允许工程师从任意角度审查和交互。
- 科学研究:可视化分子结构、流体动力学模拟结果等。这些场景通常涉及数百万个点、线或三角形,OpenGL ES 的 GPU 加速能力是唯一能实时、流畅渲染它们的途径。例如,有开发者使用 OpenGL ES 来原生渲染雷达点云数据
- 视频与图像处理,许多你觉得“炫酷”的图像效果,背后都是 OpenGL ES 在实时计算。
- 美颜相机:“磨皮”(肤色平滑)、“大眼”、“瘦脸”这些特效,本质上是对图像进行实时滤镜处理和顶点变形,这些都通过编写 OpenGL ES 的着色器 程序在 GPU 上完成,速度极快。
- 专业滤镜 App:各种复杂的色彩滤镜、艺术效果(如素描、油画),也是通过片段着色器对每个像素的颜色进行数学运算来实现。
- 视频编辑软件:在预览和最终输出时,应用转场特效、字幕、调色等,都离不开 GPU 加速渲染。
目前应用层处在 OpenGL ES 到 Vulkan 过渡的重要转型期。主流的 App 都在使用 OpenGL ES 来实现各类炫酷效果,Google 在不遗余力地推广 Vulkan。从 2025 年开始,Vulkan 将正式官宣成为 Android 上的官方图形 API。Vulkan 将正式作为 Android 的唯一 GPU 硬件抽象层 (HAL),Google 会要求所有应用和游戏都必须基于 Vulkan 来实现。虽然 Google 打算强制开发者使用 Vulkan ,但是让大家短期全部迁移明显不现实,毕竟 Vulkan 和 OpenGLES 的差异还是很大的,而这时候 ANGLE 就开始体现它作用。ANGLE 作为兼容层,它支持让 GLES 应用运行到 Vulkan ,ANGLE 通过将 GLES API 调用翻译为 Vulkan API 调用,从而让 GLES 能够兼容运行到 Vulkan。
在 Framework 层,在 HWUI 和 RenderEngine 模块中使用了 Skia:
- HWUI 中使用 SKia 执行 UI 元素的渲染操作:Android 的视图系统(View System)将 UI 组件的绘制命令记录到 显示列表(Display List) 中。在渲染时,HWUI(硬件加速 UI)驱动 Skia 执行这些命令。Skia 通过其 SkCanvas 等 API 将矢量指令或位图数据光栅化(转换为像素),最终输出到屏幕或离屏缓冲区。
- SurfaceFlinger 在执行 GPU 合成时,会通过 RenderEngine 调用 Skia 来执行图层和合成操作。Skia 是一个功能丰富的 2D 图形库,内置了对抗锯齿(Anti-aliasing)、多种混合模式、模糊滤镜(Blur)、阴影(Shadow)、颜色空间转换(Color Management) 等高级特性的优化实现,当待合成的图层需要应用此类效果时,可以在 RenderEngine 中利用 Skia 提供的 API 来实现。
Skia 是一个开源的 2D 图形库,由 Google 开发和维护。它是 Android 系统 UI 渲染的基石,同时也被广泛应用于 Chrome、Flutter 等项目中。Skia 的核心作用是提供高层、易用的绘图 API。开发者常用的 Canvas 和 Paint 等对象就是由 Skia 实现的。Skia 主要负责文字渲染、路径绘制、图像处理(缩放、解码)、矢量图形(如 SVG)显示等任务。其设计理念是将图形绘制过程简化为在画布(Canvas)上通过画笔(Paint)绘制各种图形元素。
早期,Skia 使用 CPU 进行绘制,性能有限,复杂场景易导致卡顿。Android 自 3.0 (Honeycomb) 开始,默认开启硬件加速。此模式下,Skia 将其绘图指令转换为 OpenGL ES 或 Vulkan 命令,由 GPU 执行,大幅提升性能。几乎所有 Android 应用的 UI 绘制,包括视图系统、文本显示、基本形状和图像,都依赖于 Skia 提供的绘图 API。
Skia 设计上解耦为前端与后端,Skia 的前端指的是一套提供给开发者的高级编程接口(API),它隐藏了底层硬件的复杂性,让开发者能够以一种相对统一和直观的方式来描述和创建 2D 图形内容。你可以把它想象成一位画家手中的各种画笔、画板和调色板,提供了创作所需的所有工具。
为了让你快速了解 Skia 前端的主要组成部分,我用一个表格来汇总其核心组件:

Skia 的 Ganesh 和 Graphite 是其两大核心的硬件加速渲染后端:
- Ganesh 基于 OpenGL 体系构建,围绕 GrContext 对象管理 GPU 状态和资源。Ganesh 后端同时支持 OpenGL 和 Vulkan,但 Ganesh 并非为 Vulkan 原生设计:Ganesh 的架构最初是基于 OpenGL 的状态机模型设计的。虽然其后扩展支持了 Vulkan 和 Metal,但在这些现代 API 上的性能和效率表现可能不如其专为这些 API 设计的新一代后端
- Graphite 后端为 Vulkan/Metal/D3D12 等现代 API 从头设计,采用显式控制和多线程优先的架构。它的设计目标是显著降低 CPU 开销,并更好地利用多核处理器和现代 GPU。
目前 Android16 平台, HWUI 与 RenderThread 均采用了 Ganesh + Opengl 进行渲染和合成操作,该组合具有良好的稳定性和广泛兼容性,预计在 Android17 上,HWUI 将采用 Ganesh + Vulkan 的组合, RenderThread 采用了 Graphite + Vulkan 进行合成操作。更后续版本中,HWUI 与 RenderThread 均将切换到 Graphite + Vulkan 组合,预计届时图形渲染性能会有较大幅度的提升,各类奇怪的 bug 会更多(活着就是折腾!)。
4. Android 平台上的 OpenGL ES
Android 平台上,Vulkan 还在起步中,Skia 基于 Opengl ES 实现,所用目前我们的关注点还是在 Opengl ES 上。
OpenGL ES(OpenGL for Embedded Systems)是专为移动设备和嵌入式系统优化的图形渲染 API,通过硬件加速实现高性能的 2D/3D 图形渲染。OpenGL ES 只提供了接口,Android 平台通过对应的 GLES 库实现了这些接口:
* libGLESv1_CM/v2/v3 库:分别对应 OpenGL ES 1.x(固定管线)、2.0+(可编程着色器)及 3.0+(实例渲染等高级特性),OpenGL ES 接口实现
GLES 库不能单独使用,还需要 EGL 库与本地窗口系统之间建立连接,OpenGL ES 的平台无关性正是借助 EGL 实现的,EGL 屏蔽了不同平台的差异,
这些库的 AOSP 实现都在手机上的 /sytem/lib64
路径下:
# oepngl 库
cd /system/lib64
find . -name "libGLES*"
./libGLESv1_CM.so
./libGLESv1_CM_angle.so
./libGLESv2.so
./libGLESv2_angle.so
./libGLESv3.so
# egl 库
find . -name "libEGL*"
./libEGL.so
./libEGL_angle.so
这些库对应的源码在 frameworks/native/opengl
目录下。AOSP 提供这些库用于保证系统有基本的图形编程能力,通常性能都不太理想。这些库其中有两个不一样的面孔 libGLESv2_angle 和 libEGL_angle,他俩为 OpenGL ES 提供基于 Vulkan 的转译实现,旨在解决 Android 生态中长期存在的图形驱动碎片化问题,并提升图形渲染的兼容性与性能。
芯片厂商通常会提供自己的优化版本,通常为闭源实现(综合性能更好,优先使用)。一般在 /vendor/lib64
路径下:
cd /vendor/lib64
find . -name "libGLES*"
./egl/libGLESv2_angle.so
./egl/libGLESv2_adreno.so
./egl/libGLESv1_CM_adreno.so
./egl/libGLESv1_CM_angle.so
./libGLESv2_adreno.so
find . -name "libEGL*"
./egl/libEGL_angle.so
./egl/libEGL_adreno.so
./libEGL_adreno.so
这些库是什么时候加载的?通常在执行 opengl 环境初始化函数 eglGetDisplay 时,通过 dlopen 加载这些库.
5. RenderEngine 初始化过程
有了前面的基础我们就可以开始分析 RenderEngine 的初始化过程了:
初始化过程的调用栈如下:
SurfaceFlinger::init
RenderEngineCreationArgs::Builder # 使用 builder 模式构建
chooseRenderEngineType # 根据系统的配置,选择 RenderEngine 类型
RenderEngine::create # 根据配置创建 RenderEngine 实例
SkiaGLRenderEngine::create
RenderEngineThreaded::create
CompositionEngine::setRenderEngine # 与 CompositionEngine 关联
整个过程如下:
void SurfaceFlinger::init() {
// ... existing code ...
// 创建 RenderEngine 配置
auto builder = renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
.setImageCacheSize(maxFrameBufferAcquiredBuffers)
.setEnableProtectedContext(enable_protected_contents(false))
.setPrecacheToneMapperShaderOnly(false)
.setBlurAlgorithm(chooseBlurAlgorithm(mSupportsBlur))
.setContextPriority(/* ... */);
chooseRenderEngineType(builder);
// 创建 RenderEngine 实例
mRenderEngine = renderengine::RenderEngine::create(builder.build());
// 将 RenderEngine 设置到 CompositionEngine 的 mRenderEngine 成员变量中
mCompositionEngine->setRenderEngine(mRenderEngine.get());
// ... existing code ...
}
本节重点关注到 RenderEngine::create 过程:
// frameworks/native/libs/renderengine/RenderEngine.cpp
std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
threaded::CreateInstanceFactory createInstanceFactory;
// TODO: b/341728634 - Clean up conditional compilation.
#if COMPILE_GRAPHITE_RENDERENGINE // 目前还没有
const RenderEngine::SkiaBackend actualSkiaBackend = args.skiaBackend;
#else
if (args.skiaBackend == RenderEngine::SkiaBackend::GRAPHITE) {
ALOGE("RenderEngine with Graphite Skia backend was requested, but Graphite was not "
"included in the build. Falling back to Ganesh (%s)",
args.graphicsApi == RenderEngine::GraphicsApi::GL ? "GL" : "Vulkan");
}
// 目前,大部分情况是这个
const RenderEngine::SkiaBackend actualSkiaBackend = RenderEngine::SkiaBackend::GANESH;
#endif
ALOGD("%sRenderEngine with %s Backend (%s)", args.threaded == Threaded::YES ? "Threaded " : "",
args.graphicsApi == GraphicsApi::GL ? "SkiaGL" : "SkiaVK",
actualSkiaBackend == SkiaBackend::GANESH ? "Ganesh" : "Graphite");
// TODO: b/341728634 - Clean up conditional compilation.
#if COMPILE_GRAPHITE_RENDERENGINE
if (actualSkiaBackend == SkiaBackend::GRAPHITE) {
createInstanceFactory = [args]() {
return android::renderengine::skia::GraphiteVkRenderEngine::create(args);
};
} else
#endif
{ // GANESH
if (args.graphicsApi == GraphicsApi::VK) {
createInstanceFactory = [args]() {
return android::renderengine::skia::GaneshVkRenderEngine::create(args);
};
} else { // GL
// 关注点
// 绝大部分手机,OpenGL ES + Ganesh 类型,走这个分支
createInstanceFactory = [args]() {
return android::renderengine::skia::SkiaGLRenderEngine::create(args);
};
}
}
// 线程化包装
if (args.threaded == Threaded::YES) {
return renderengine::threaded::RenderEngineThreaded::create(createInstanceFactory);
} else {
return createInstanceFactory();
}
}
create 函数会根据前面 chooseRenderEngineType 函数选择的配置,选择对应的实现类:
- Graphite + Vulkan : GraphiteVkRenderEngine::create()
- Ganesh + Vulkan : GaneshVkRenderEngine::create()
- Ganesh + OpenGL : SkiaGLRenderEngine::create() (大部分是这个)
可以通过 adb shell dumpsys SurfaceFlinger | grep -A 10 "RE "
命令查看 RenderEngine 类型:
- ------------RE GLES (Ganesh)------------: (OpenGL ES + Ganesh)
- ------------RE Vulkan (Ganesh)----------: (Vulkan + Ganesh)
- ------------RE Vulkan (Graphite)----------: (Vulkan + Graphite)
目前主流仍然是 OpenGL ES + Ganesh 类型(稳如老狗),对应的创建 SkiaGLRenderEngine 对象。SkiaGLRenderEngine 初始化的过程如下:
// frameworks/native/libs/renderengine/skia/SkiaGLRenderEngine.cpp
std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(
const RenderEngineCreationArgs& args) {
// initialize EGL for the default display
// 步骤1,获取默认 EGL 显示器
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
// 每个 EGLDisplay 在使用前都需要初始化
if (!eglInitialize(display, nullptr, nullptr)) {
LOG_ALWAYS_FATAL("failed to initialize EGL");
}
// 步骤2,获取 EGL 版本和扩展信息
// 获取 EGL 版本和扩展信息,用于后续功能检测
const auto eglVersion = eglQueryString(display, EGL_VERSION);
if (!eglVersion) {
checkGlError(__FUNCTION__, __LINE__);
LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed");
}
const auto eglExtensions = eglQueryString(display, EGL_EXTENSIONS);
if (!eglExtensions) {
checkGlError(__FUNCTION__, __LINE__);
LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed");
}
// 初始化扩展功能
auto& extensions = GLExtensions::getInstance();
extensions.initWithEGLStrings(eglVersion, eglExtensions);
// 步骤3,获取 EGLConfig 对象
// The code assumes that ES2 or later is available if this extension is
// supported.
// - 配置选择策略 :如果扩展支持无配置上下文,则使用 EGL_NO_CONFIG_KHR ;否则调用 `chooseEglConfig` 选择合适的配置
// - 优先级顺序 :优先尝试 OpenGL ES 3.0,失败后降级到 ES 2.0,最后尝试简化查询
EGLConfig config = EGL_NO_CONFIG_KHR;
if (!extensions.hasNoConfigContext()) {
config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
}
/*
步骤4. EGL 上下文创建
- 受保护上下文 :如果启用受保护内容且硬件支持,创建受保护的 EGL 上下文
- 普通上下文 :创建主要的 EGL 上下文,支持上下文优先级设置(实时、高、中、低)
- 上下文属性配置 :
- EGL_CONTEXT_CLIENT_VERSION :设置 OpenGL ES 版本
- EGL_CONTEXT_PRIORITY_LEVEL_IMG :设置上下文优先级
- EGL_PROTECTED_CONTENT_EXT :启用受保护内容支持
*/
EGLContext protectedContext = EGL_NO_CONTEXT;
const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args);
if (args.enableProtectedContext && extensions.hasProtectedContent()) {
protectedContext =
createEglContext(display, config, nullptr, priority, Protection::PROTECTED);
ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
}
EGLContext ctxt =
createEglContext(display, config, protectedContext, priority, Protection::UNPROTECTED);
// if can't create a GL context, we can only abort.
LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
/*
步骤5,创建 EGLSurface
在缺乏原生窗口的情况下,为你提供一个“画布”(EGLSurface),使得 OpenGL ES 渲染上下文(EGLContext)能够被安全地激活并进行一些必要的 GPU 操作占位表面创建
- 普通占位表面 :如果不支持无表面上下文,创建 1x1 像素的 PBuffer 作为占位表面
- 受保护占位表面 :为受保护上下文创建对应的受保护占位表面
- 表面属性 :设置宽度、高度为 1,并根据需要启用受保护内容
*/
EGLSurface placeholder = EGL_NO_SURFACE;
if (!extensions.hasSurfacelessContext()) {
// createPlaceholderEglPbufferSurface 函数会调用到 eglCreatePbufferSurface 创建一个像素缓冲区表面
placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
Protection::UNPROTECTED);
LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer");
}
/*
步骤6,绑定上下文
- 激活上下文 :调用 eglMakeCurrent() 激活 GL 上下文
- 查询 GL 信息 :获取 GL 供应商、渲染器、版本和扩展信息
- 初始化 GL 扩展 :通过 extensions.initWithGLStrings() 完成 GL 扩展检测
*/
EGLBoolean success = eglMakeCurrent(display, placeholder, placeholder, ctxt);
LOG_ALWAYS_FATAL_IF(!success, "can't make placeholder pbuffer current");
extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
EGLSurface protectedPlaceholder = EGL_NO_SURFACE;
if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
protectedPlaceholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
Protection::PROTECTED);
ALOGE_IF(protectedPlaceholder == EGL_NO_SURFACE,
"can't create protected placeholder pbuffer");
}
// initialize the renderer while GL is current
/*
关注点,引擎实例创建
- 构造 SkiaGLRenderEngine :使用收集的所有 EGL 资源创建引擎实例
- 创建 Skia 上下文 :调用 ensureContextsCreated() 初始化 Skia GPU 上下文
- 信息输出 :记录 OpenGL ES 和 EGL 的详细信息到日志
*/
std::unique_ptr<SkiaGLRenderEngine> engine(new SkiaGLRenderEngine(args, display, ctxt,
placeholder, **protectedContext**,
protectedPlaceholder));
engine->ensureContextsCreated();
ALOGI("OpenGL ES informations:");
ALOGI("vendor : %s", extensions.getVendor());
ALOGI("renderer : %s", extensions.getRenderer());
ALOGI("version : %s", extensions.getVersion());
ALOGI("extensions: %s", extensions.getExtensions());
ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
return engine;
}
SkiaGLRenderEngine 中会使用到 Opengl 的接口来合成图层,使用 opengl 前,需要搭建 EGL 环境。
EGL 作为 OpenGL ES 等渲染 API 与底层原生平台窗口系统之间的接口。EGL 屏蔽了不同系统之间的差异,向 Opengl 提供了三个统一的窗口相关对象:

- Display(EGLDisplay) 是对实际显示设备的抽象;
- Surface(EGLSurface)是对用来存储图像的内存区域 FrameBuffer 的抽象,包括 Color Buffer(颜色缓冲区), Stencil Buffer(模板缓冲区) ,Depth Buffer(深度缓冲区);
- Context (EGLContext) 存储 OpenGL ES 绘图的一些状态信息;
搭建 EGL 环境的一般的步骤如下:
- 获取 EGLDisplay:通过 eglGetDisplay(EGL_DEFAULT_DISPLAY) 获取默认的显示连接。
- 初始化 EGL:调用 eglInitialize() 来初始化与 EGLDisplay 的连接,并可获取 EGL 版本号。源码中使用的是 eglQueryString 完成该过程。
- 选择 EGLConfig:使用 eglChooseConfig() 指定期望的渲染表面参数(如颜色深度、模板/深度缓冲区),系统会返回最匹配的配置。
- 创建 EGLContext:通过 eglCreateContext() 创建渲染上下文。创建时可指定 OpenGL ES 的版本(如3.0)。
- 创建 EGLSurface:
- 对于屏幕上渲染:使用 eglCreateWindowSurface() 并将 Android 的 NativeWindow(通常由 Surface 或 SurfaceTexture获取)传入。
- 对于离屏渲染:使用 eglCreatePbufferSurface() 创建一个像素缓冲区表面。
- 绑定上下文:调用 eglMakeCurrent() 将 EGLDisplay、EGLSurface 和 EGLContext 与当前线程绑定。此后,该线程发出的 OpenGL ES 指令将会在指定的 Context 和 Surface 上生效。
完成 EGL 环境初始化以后就可以使用 OpenGL ES API 进行绘制操作了:
- 渲染与交换缓冲区:
- 使用 OpenGL ES API 进行绘制。
- 对于 Window Surface,绘制完成后需调用 eglSwapBuffers() 将后台缓冲区(Back Buffer)的内容交换到前台(Front Buffer)以显示到屏幕。
- 对于 PBuffer Surface(离屏渲染),通常不需要交换缓冲区,渲染结果可直接读回或绑定为纹理
- 释放资源:在渲染结束后,需要调用 eglMakeCurrent() 解绑上下文,并依次销毁 EGLContext、EGLSurface,最后调用 eglTerminate() 终止与 EGLDisplay 的连接
EGLSurface 有多种创建方式:
- eglCreatePbufferSurface,创建离屏渲染表面 (此处使用该种方式)
// ... existing code ...
EGLSurface placeholder = EGL_NO_SURFACE;
if (!extensions.hasSurfacelessContext()) {
placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
Protection::UNPROTECTED);
LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer");
}
// ... existing code ...
- 创建离屏渲染表面(off-screen surface)
- 不与任何窗口关联
- 主要用作占位符表面,当不支持无表面上下文时使用
- 尺寸固定为1x1像素
- 支持受保护内容(Protected Content)
- eglCreateWindowSurface,这是最常用的窗口表面创建方式:
EGLSurface surface = eglCreateWindowSurface(display, config, nativeWindow, attrib_list);
- 与原生窗口关联
- 用于屏幕显示
- 支持双缓冲
- 可以调用 eglSwapBuffers 进行缓冲区交换
- 尺寸由关联的窗口决定
- eglCreatePixmapSurface,创建像素映射表面
EGLSurface surface = eglCreatePixmapSurface(display, config, pixmap, attrib_list);
- 与像素图关联
- 用于离屏渲染到像素图
- 在Android中已被标记为 @Deprecated
- 实际实现中抛出 UnsupportedOperationException
- eglCreatePlatformWindowSurface (EGL 1.5)
EGLSurface surface = eglCreatePlatformWindowSurface(display, config, native_window, attrib_list);
- EGL 1.5引入的新API
- 提供更好的平台特定支持
- 使用 EGLAttrib 而不是 EGLint 作为属性类型
EGL 环境初始化完成后,开始 SkiaGLRenderEngine 对象的初始化:
// frameworks/native/libs/renderengine/skia/SkiaGLRenderEngine.cpp
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
EGLContext ctxt, EGLSurface placeholder,
EGLContext protectedContext, EGLSurface protectedPlaceholder)
: SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
args.blurAlgorithm),
mEGLDisplay(display),
mEGLContext(ctxt),
mPlaceholderSurface(placeholder),
mProtectedEGLContext(protectedContext),
mProtectedPlaceholderSurface(protectedPlaceholder) {}
调用父类构造函数,然后给一些成员赋值。父类 SkiaRenderEngine 构造函数实现如下:
// frameworks/native/libs/renderengine/skia/SkiaRenderEngine.cpp
enum class Threaded {
NO,
YES,
};
SkiaRenderEngine::SkiaRenderEngine(Threaded threaded, PixelFormat pixelFormat,
BlurAlgorithm blurAlgorithm)
: RenderEngine(threaded), mDefaultPixelFormat(pixelFormat) {
switch (blurAlgorithm) {
case BlurAlgorithm::GAUSSIAN: {
ALOGD("Background Blurs Enabled (Gaussian algorithm)");
mBlurFilter = new GaussianBlurFilter();
break;
}
case BlurAlgorithm::KAWASE: {
ALOGD("Background Blurs Enabled (Kawase algorithm)");
mBlurFilter = new KawaseBlurFilter();
break;
}
case BlurAlgorithm::KAWASE_DUAL_FILTER: {
ALOGD("Background Blurs Enabled (Kawase dual-filtering algorithm)");
mBlurFilter = new KawaseBlurDualFilter();
break;
}
default: {
mBlurFilter = nullptr;
break;
}
}
mCapture = std::make_unique<SkiaCapture>();
}
调用父类构造函数,然后初始化一些成员:
- mBlurFilter:用于指定模糊算法
- mDefaultPixelFormat:默认的像素格式,用于创建 Skia 渲染表面
- mCapture:用于捕获发送到 Skia 的所有绘制命令
父类 RenderEngine 构造函数:
// frameworks/native/libs/renderengine/include/renderengine/RenderEngine.h
RenderEngine(Threaded threaded) : mThreaded(threaded) {}
初始化 mThreaded 成员变量,用于指定渲染引擎是否支持线程化。
SkiaGLRenderEngine 初始化完成后,接着调用 RenderEngineThreaded::create 进行线程化包装:
// frameworks/native/libs/renderengine/threaded/RenderEngineThreaded.cpp
std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
return std::make_unique<RenderEngineThreaded>(std::move(factory));
}
RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory)
: RenderEngine(Threaded::YES) {
ATRACE_CALL();
std::lock_guard lockThread(mThreadMutex);
// 创建线程对象
mThread = std::thread(&RenderEngineThreaded::threadMain, this, factory);
}
关注线程的执行过程:
// frameworks/native/libs/renderengine/threaded/RenderEngineThreaded.h
std::atomic<bool> mRunning = true;
mutable std::queue<Work> mFunctionCalls GUARDED_BY(mThreadMutex);
// frameworks/native/libs/renderengine/threaded/RenderEngineThreaded.cpp
void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
#if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY))
if (foregroundEnabled()) {
if (!SetTaskProfiles(0, {"ProcessCapacityNormal"})) {
ALOGE("%s SetTaskProfiles error happened : ProcessCapacityNormal", __FUNCTION__);
}
} else
#endif
if (!SetTaskProfiles(0, {"SFRenderEnginePolicy"})) {
ALOGW("Failed to set render-engine task profile!");
}
if (setSchedFifo(true) != NO_ERROR) {
ALOGW("Couldn't set SCHED_FIFO");
}
mRenderEngine = factory(); // 返回 SkiaGLRenderEngine 对象
#if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY))
mTid = gettid();
#endif
pthread_setname_np(pthread_self(), mThreadName);
{
std::scoped_lock lock(mInitializedMutex);
mIsInitialized = true;
}
mInitializedCondition.notify_all();
while (mRunning) {
const auto getNextTask = [this]() -> std::optional<Work> {
std::scoped_lock lock(mThreadMutex);
if (!mFunctionCalls.empty()) {
Work task = mFunctionCalls.front();
mFunctionCalls.pop();
return std::make_optional<Work>(task);
}
return std::nullopt;
};
const auto task = getNextTask();
if (task) {
(*task)(*mRenderEngine);
}
std::unique_lock<std::mutex> lock(mThreadMutex);
mCondition.wait(lock, [this]() REQUIRES(mThreadMutex) {
return !mRunning || !mFunctionCalls.empty();
});
}
// we must release the RenderEngine on the thread that created it
mRenderEngine.reset();
}
和大部分事件循环机制类似:获取 Task,执行 Task。
整体的类关系如下图所示:
