文章目录
-
- 资料快车
- preface
- 1、Android的UI绘图
- 2、Android显示系统框架
- 3、Android窗口系统概述
- 4、Android图形库体系
-
- 1)Android图形库EGL/OpenGL-ES-wrapper/OpenGL-ES
- 2)EGL介绍
- [3)OpenGL ES Wrapper库](#3)OpenGL ES Wrapper库)
- 4)OpenGL-ES协议及其实现介绍
- [5)Skia与OpenGL-ES/Vulkan 简述](#5)Skia与OpenGL-ES/Vulkan 简述)
- 6)Android如何使用OpenGL-ES
- [7)简化OpenGL ES开发-GLSurfaceView](#7)简化OpenGL ES开发-GLSurfaceView)
- 5、UI的构造过程剖析
- 6、音视频库-FFMPEG
- 7、PQ及其他视频处理模块
- 8、图形处理的专业化-音视频领域
资料快车
1)看完不懂我吃:Android 渲染(显示)原理 - 传统架构
https://juejin.cn/post/7484470326080929827#heading-8
2)Android Graphics 图像显示系统 - 全面解读 - 旧架构
https://www.cnblogs.com/roger-yu/p/15641545.html
3)Android图形图像显示-Display-Surfaceflinger-Fence-DRM-SKIA/OpenGL/Vulkan
https://www.cnblogs.com/bluestorm/p/17662946.html
4)DRM架构
Android画面显示流程一 : https://blog.csdn.net/qq_42282862/article/details/131595316
Android画面显示流程二:https://blog.csdn.net/qq_42282862/article/details/131596401
Android画面显示流程三:https://blog.csdn.net/qq_42282862/article/details/131600816
surfaceflinger : https://blog.csdn.net/qq_42282862/article/details/131606904
preface
Android显示系统从上到下涉及的模块极其多,可以说是系统里最复杂的模块,任一个模块都可以使用一个篇章来描述,任重而道远
1、Android的UI绘图
1、Android的UI底层是用CPU绘图还是GPU绘图
都支持,高端平台(TV/手机/平板/车载等)基本都使用GPU硬件加速,重点学习硬件加速
2、应用层如何绘制UI,什么时候需要绘制UI?
绘图时机:
- `ViewRootImpl.performTraversals()` - 主绘制入口
- 响应 VSync 信号
- 窗口切换、窗口大小、属性有改变;
- 视图失效(invalidate)
3、Activity与绘图?
在应用层的角度,Activity是一个活动界面,在这个界面我们可以放置各种元素,这些元素就需要绘图,注意界面本身也是绘图的结果,总体而言,一个完整绘图上叠放各种小绘图;
1)站在应用的角度,UI界面的设计分为两步
绘图 - 静态效果,再添加 特效 - 动态效果,在Android中,UI绘图使用View,特效使用View动画
好比PPT,我们先画好每一页精美的内容(静态效果),再给每一页添加出场效果、退场效果(动态效果)

动态效果实现:代码实现让一个View先平移,后旋转,最后淡出
1.使用属性动画来实现
/android/frameworks/base/core/java/android/view/animation/AnimationSet.java
2.
ObjectAnimator moveIn = ObjectAnimator.ofFloat(myView, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(myView, "alpha", 1f, 0f);
AnimatorSet animSet = new AnimatorSet();
// 按顺序执行
animSet.playSequentially(moveIn, rotate, fadeOut);
// 或者同时执行
// animSet.playTogether(moveIn, rotate, fadeOut);
// 或者更复杂的组合
// animSet.play(rotate).with(fadeOut).after(moveIn);
animSet.setDuration(1000);
animSet.start();
2)UI绘图依赖的硬件资源?
1、简单绘图底层可以使用软件CPU实现、也可以使用硬件实现(2D图形模块、GPU),虽然他们都拥有这样的能力,但效率和效果不同,不同的平台,根据自身资源情况来选择实现方式;
2、渲染、特效这些较为复杂,工作量大的任务,一般都使用GPU来承担;
2、Android显示系统框架
在Android的快速发展下,新技术不断涌现,架构也在不断进化,新旧架构我们都应该了解,以便能在项目中区分出来,不至于迷乱在繁杂的架构
1)Android经典图形架构图(低版本架构)

以上来自Android4.0源码版本的架构
1)libagl - android graphic library - Android自有软件实现的图形引擎库
2)libhgl - hardware graphic library - 硬件实现的图形引擎库,厂商提供
3)应用程序可以直接调用EGL和OpenGL-ES的接口,不一定要经过SurfaceFlinger,也是理所当然的,毕竟SF只是集中管理的功能;
4)简单概述就是围绕三个主线进行
1、APP向SF申请buffer用以存放自己的显示内容;
2、APP使用Skia/GL等图形库画图、GPU渲染,最后结果存放在buffer,最后提交给SF进一步处理;
3、SF组织合成送显;
2)框架图-面向对象视角

notes
1、VSync是project butter工程中加入的一种同步机制,可以是硬件产生,也可以使用软件来模拟-VsyncThread;
2、surface的含义,"表面",好比一张空白纸(内存),应用可以在这张纸上素描、着色、渲染,产出一帧完整的图片;
3)基于DRM框架图
1、Linux类操作系统

其中图形库部分与Android系统比较相近 (skia + mesa3D + DRM)
2)基于DRM架构的Android的显示系统

1、在 Android 12 中,GKI 2.0 将 ION 分配器替换为了 DMA-BUF 堆(从名字可以看出,DMA是趋势,主要使用DMA内存加速);

2、Android开源图形库实现同样也是 :skia + mesa3D + DRM
4)小结
Android显示系统 可以划分为 窗口系统和 图形库体系
3、Android窗口系统概述
1、最简单的窗口系统?
一个APP+FB显示,这只能做一些简单的显示,比如单片机。
2、Android上的窗口系统实现
不同平台,不同系统,窗口系统的实现多种多样,应当专注于当前的项目平台,不要迷失方向;
Android Framework 实现的SurfaceFlinger、WMS、View、Activity等等都属于窗口系统内容,是Android平台的特有实现,涉及内容生成-产生窗口、多个内容如何呈现 - 窗口组织管理,以便呈现出各种各样的窗口效果
3、WMS、View体系与SurfaceFlinger的关系

这里的框图重点体现WMS、View和SF这几个主体,不会糅杂太多细节和分支,框架应该如此!
1)WMS是管理者;
2)View是生成者;
3)SF是消费者,也是硬件资源管理者;
WMS、View都属于上层使用者,在Android显示子系统 原理探索中 可以简单了解框架(逻辑的堆砌过于庞大)
4、Android图形库体系
图形库(OpenGL-ES/Vulkan)是一个极其复杂的模块,算是另一个领域的知识(音视频领域),学习显示框架时,不求深入,我们把握框架即可!
1)Android图形库EGL/OpenGL-ES-wrapper/OpenGL-ES
1)Android系统图形栈 OpenGL-ES和EGL介绍: https://blog.csdn.net/u010029439/article/details/90413006
2)OpenGL ES库和EGL库的加载过程: https://blog.csdn.net/ninver2007/article/details/97152412
3)Android系统EGL源码分析:https://segmentfault.com/a/1190000045166147
2)EGL介绍
1、基本认识
EGL : khronos(机构) Native Platform graphics interface
1、主要负责图形环境管理、surface/buffer绑定、渲染同步等,介于本地窗口系统和Rendering API之间的一层接口;
2、由于openGL ES是开源软件,如何保证上层应用调用的是稳定API?通过设计中间层EGL并由google统一管理实现。
3、调用链路:应用程序 -> EGL -> Rendering API(openGL ES)-> GPU
1)OpenGL ES接口成千上百,应用都需要通过EGL来访问?不是,只有管理相关API才需要,其它API可以直接调用
4、EGL适用于X11、Wayland、Android等系统
5、谁来实现?
在Android源码中Android framework有自己的实现,有很多开源软件都实现了-比如Mesa3D;
2、源码介绍
1、Framework java层
/android/frameworks/base/opengl/java
核心实现 - 封装GL,让应用程序更方便使用
/android/frameworks/base/opengl/java/android/opengl/GLSurfaceView.java
2、JNI
frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp:EGL本地代码的JNI调用接口
frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
frameworks/base/core/jni/android_opengl_GLESXXX.cpp:OpenGL功能函数的JNI调用接口
3、native cpp层
/android/frameworks/native/opengl/libs/EGL
libEGL (共享库)
├── libEGL_getProcAddress (静态库)
│ └── getProcAddress.cpp
├── libEGL_blobCache (静态库)
│ ├── BlobCache.cpp
│ └── FileBlobCache.cpp
└── 核心源文件
├── egl_tls.cpp # 线程本地存储
├── egl_cache.cpp # 着色器缓存
├── egl_display.cpp # 显示管理
├── egl_object.cpp # 对象生命周期
├── egl_layers.cpp # 层支持
├── egl.cpp # EGL 入口点
├── eglApi.cpp # EGL API 实现
├── egl_platform_entries.cpp # 平台入口
├── Loader.cpp # 驱动加载
└── egl_angle_platform.cpp # ANGLE 平台支持
4、EGL加载openGL ES库
源码:/android/frameworks/native/opengl/libs/EGL/Loader.cpp
官方说明:https://source.android.google.cn/docs/core/graphics/implement-opengl-es?hl=zh-cn
1)4.4版本之前EGL (libegl.so) 根据egl.cfg来加载软件实现还是硬件实现的图形库;
2)4.4版本之后使用属性确定加载哪个库
路径:/vendor/lib/egl 、/vendor/lib64/egl
属性名:ro.hardware.egl、ro.board.platform
libEGL_${ro.hardware.egl}.so
libGLESv1_CM_${ro.hardware.egl}.so
libGLESv2_${ro.hardware.egl}.so
libEGL_${ro.board.platform}.so
libGLESv1_CM_${ro.board.platform}.so
libGLESv2_${ro.board.platform}.so
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
SurfaceFlinger::init()
/android/frameworks/native/opengl/libs/EGL/eglApi.cpp
--eglGetDisplay(EGLNativeDisplayType display)
/android/frameworks/native/opengl/libs/EGL/egl.cpp
---egl_init_drivers()
----egl_init_drivers_locked()
/android/frameworks/native/opengl/libs/EGL/Loader.cpp
------loader.open()
------load_driver() //加载对应的GL-ES库
4、使用EGL的绘图的一般步骤:
获取 EGL Display 对象:eglGetDisplay()
初始化与 EGLDisplay 之间的连接:eglInitialize()
获取 EGLConfig 对象:eglChooseConfig()
创建 EGLContext 实例:eglCreateContext()
创建 EGLSurface 实例:eglCreateWindowSurface()
连接 EGLContext 和 EGLSurface:eglMakeCurrent()
使用 OpenGL ES API 绘制图形:gl_*()
切换 front buffer 和 back buffer 送显:eglSwapBuffer()
断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()
删除 EGLSurface 对象
删除 EGLContext 对象
终止与 EGLDisplay 之间的连接
3)OpenGL ES Wrapper库
1、OpenGL ES Wrapper库:OpenGL ES Wrapper 库是一个对 OpenGL ES API 进行封装的一个包裹库,它向上为应用程序提供了标准的 OpenGL ES API,向下可以和不同厂商实现的 OpenGL ES 库进行绑定,将 OpenGL ES API 和对应的实现函数一一绑定在一起。
2、
OpenGL ES 1.x API 的 Wrapper 库
/android/frameworks/native/opengl/libs/GLES_CM >> libGLESv1_CM.so
OpenGL ES 2.0 的 Wrapper 库
/android/frameworks/native/opengl/libs/GLES2 >> libGLESv2.so
4)OpenGL-ES协议及其实现介绍
1、背景
1)由于openGL需要较高的内存配置、耗电高等特点不适合移动设备,openGL-ES则解决这些问题,广泛应用在汽车电子、手机等;
2)不仅适合3D图形的实现,也广泛应用于2D的视频和图像处理,拥有强大的渲染和特效处理功能;
3)底层需要依赖GPU渲染,当然也可以CPU渲染;
2、实现介绍
1、OpenGl-ES是一套规范协议,定义一套供上层进行调用的API(相当于interface),抽象GPU的功能,使得开发者不必关系底层GPU类型和具体实现;
2、实现OpenGL-ES协议的库我们有时也叫openGL-ES,注意区分!比如Mesa3D
3、OpenGL ES库:OpenGL ES 库就是上面 OpenGL ES 中定义的 API 的具体实现。
1)基于GPU的闭源实现
由于每个显卡制造厂商的 GPU 硬件结构不同,从而导致各个厂商的OpenGL ES 库也各不相同,所以 Android 系统中的 OpenGL ES 库通常是由硬件厂商提供的,通常存放在 Android 系统中的 /system/lib64/egl 下面或者 /vendor/lib64/egl 目录下。
硬件库-厂家提供
/vendor/lib/egl/libEGL.so
/vendor/lib/egl/libGLESv1_CM.so
/vendor/lib/egl/libGLESv2.
2)基于GPU的开源实现-Mesa3D,有时也会用协议名称表示openGL-ES
3)基于CPU的纯软件实现(AOSP)
OpenGL ES软件实现(Android 7.1路径,注意高版本Android已被移除)
/frameworks/native/opengl/libagl/
库名:libGLES_android.so
4、编译工具
/android/frameworks/native/opengl/tools/glgen/
5、编译
1)**LL-NDK**:Low-Level NDK,供系统库使用的稳定接口。
2)编译优化
#if defined(__arm__)
#define API_ENTRY(_api) __attribute__((naked,noinline)) _api
#define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile(
"mrc p15, 0, r12, c13, c0, 3 \n" // 获取 TLS
"ldr r12, [r12, %[tls]] \n"
"cmp r12, #0 \n"
"ldrne pc, [r12, %[api]] \n" // 跳转到实际函数
: : [tls] "J"(TLS_SLOT_OPENGL_API*4),
[api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))
: "r0", "r1", "r2", "r3", "r12"
);
#endif
5)Skia与OpenGL-ES/Vulkan 简述
1、Skia: 提供统一的绘制 API,可以直接使用 CPU 栅格化(软件绘制);也可以通过 OpenGL ES/Vulkan 与 GPU 交互进行加速渲染(硬件加速)。
2、OpenGL-ES/Vulkan: 图形/计算 API,用来让程序与 GPU 交互、把场景画成屏幕上的像素。
因此,Skia 位于应用与 GPU API 之间:应用调用 Skia 的 API;Skia 在 CPU 或 GPU 上进行栅格化;GPU 路径下 Skia 再通过 OpenGL ES/Vulkan 与 GPU 交互。应用也可以绕过 Skia 直接用 OpenGL/Vulkan,但 Android UI 体系默认用 Skia。后文会结合代码详细介绍。
3、OpenGL-ES/Vulkan对比
1)Android 7以上都支持OpenGL-ES/Vulkan,如何选用?
2)Vulkan Android官方介绍:
https://android-docs.cn/games/develop/vulkan/overview
3)Vulkan 与 OpenGL ES 核心对比

4)如果用编程语言来类比,OpenGL-ES相当于Java语言,Vulkan相当于C语言,Vulkan 更贴近驱动编程;
6)Android如何使用OpenGL-ES
1.OpenGL-ES就是一个图形库,可以画各种图、渲染各种特效(转场、翻页效果)等等;
2.Android应用程序使用OpenGL-ES,间接调用EGL接口 或 直接调用OpenGL-ES接口都可以,但一般都会搭配EGL;
3、为了方便上层使用,Google肯定也会有自己的封装 简化应用程序使用GL库
4)OpenGL-ES也会通过JNI暴露给java程序直接使用
5)由于图形库是显示的重要底层组件,但凡需要增强显示效果的场合都需要直接或间接使用它,比如以下场景
1、SurfaceFlinger使用GL库,哪些场景?当HWC处理不了的复杂合成,SF会调用GL分担部分合成工作
2、游戏应用程序使用GL库
3、开机动画使用GL库
4、Skia使用GL库
因此你会看到源码许多地方都有EGL/GL的身影,让人感到极其混乱,本质上都是为了各方使用OpenGL-ES
1.native层使用opengl
/android/frameworks/native/opengl
2.framework-java层使用opengl
/android/frameworks/base/opengl
3.skia库使用opengl
/android/external/skia/src/gpu/gl/egl
4.mesa3d实现的EGL
/android/external/mesa3d/src/egl
6)小结

1、Native可以是SurfaceFlinger、CPP程序等;
7)简化OpenGL ES开发-GLSurfaceView
1、Android系统已经在SDK为开发人员封装了一整套OpenGL-ES的使用和管理机制,
2、java层代码可以通过以下两种方式来搭建OpenGL-ES环境;
1)直接使用SDK提供的EGL,GLES类
/android/frameworks/base/opengl/java/android/opengl/EGL15.java
/android/frameworks/base/opengl/java/android/opengl/GLES32.java
2)使用GLSurfaceView
1、产生的背景:使用EGL,GLES编程也比较复杂,因此Android继续封装出一个更易用的类GLSurfaceView,应用程序可以直接使用,当前很多Android游戏都是直接或间接通过GLSurfaceView完成;
2、GLSurfaceView主要特性
1)管理EGLDisplay - 表示一个显示屏;
2)管理Surface
3)GLSurfaceView会创建新的线程,已使得整个渲染过程不会阻塞UI主线程
4)用户可以通过SetRenderer()自定义渲染方式
1、类图

2、Surface申请流程

3、源码分析
1.init初始化
/android/frameworks/base/opengl/java/android/opengl/GLSurfaceView.java
private void init() {
/android/frameworks/base/core/java/android/view/SurfaceHolder.java
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
2. 设置Renderer实现用户自定义渲染方式
private void setRenderer(Renderer renderer) {
new SimpleEGLConfigChooser();
new DefaultContextFactory();
new DefaultWindowSurfaceFactory();
mRenderer = renderer;
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
3.GLThread的运行
static class GLThread extends Thread {
run() --不断等待和处理渲染事件
--guardedRun();
----mEglHelper = new EglHelper()
----readyToDraw()
------mEglHelper.start(); //创建GL-ES使用环境
--------mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
--------mEgl.eglInitialize(mEglDisplay, version)
--------view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
--------view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
----gl = (GL10) mEglHelper.createGL();
----GLSurfaceView view = mGLSurfaceViewWeakRef.get();
----view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
----view.mRenderer.onDrawFrame(gl); //开始渲染
----mEglHelper.swap(); //把渲染结果显示到屏幕
}
5、UI的构造过程剖析
认识构造UI的各个对象和流程十分重要,源码实现的过程 就是将这些实体(对象)、策略(函数方法) 转化为代码表示;了解框架和这些构造过程看代码将会事半功倍;
1)一个APP构造UI画面过程

1、使用图形库画基础图形,多个图形构造一幅画面;
2、构造完成后数据送到显示控制器,最终在显示器中显示出来;
2)多个APP共同构造出界面

1、一般一个界面由多个APP共同构造而成;
2、相对单个APP构造界面,这将复杂很多,涉及合成,层级优先级等;
3、layerstack

3)转化为代码表示

1、Surface是APP中负责管理 界面构造的管理单元(操作方法的集合);
2、GraphicBuffer是图形数据的载体,使用BufferQueue队列数据结构组织;
4)UI界面构造流水线图

1、一个页面包含多种元素,每个元素都单独使用GL生成,最后放在一个layer里面;
2、一个APP可以画出多个页面(即layer),每个页面都可以保存起来,需要的时候再调用;
3、如果一个页面需要更新,则标记为dirty,SF会进行合成更新到layer里面;
6、音视频库-FFMPEG
1、简介
FFmpeg : fast forward moving picture Experts Group //快速处理音视频的工具集
FFmpeg 是一个开源、免费、跨平台的音视频处理解决方案
源码:
/android/vendor/amlogic/common/external/ffmpeg/
2、核心组成:
ffmpeg: 命令行工具本身,用于对音视频文件进行转换、抓取、编辑等操作。
ffplay: 一个简单、跨平台的媒体播放器,基于 FFmpeg 库和 SDL 库开发,常用于快速测试和调试。
ffprobe: 一个多媒体流分析工具,用于查看媒体文件的格式、码流、编码信息等元数据。
一系列编解码库(libavcodec): 这是 FFmpeg 最核心的部分,是一个包含了众多音视频编解码器的库。它支持几乎所有你能想到的音视频格式(如 H.264, H.265, VP9, AV1, AAC, MP3 等)。
格式处理库(libavformat): 一个包含多种多媒体容器格式的解封装器和封装器的库,用于处理各种文件格式(如 MP4, MKV, FLV, MOV 等)。
3、主要功能:
格式转换(转码): 将一个视频文件(如 MKV)转换为另一种格式(如 MP4),或者改变其编码(如将 H.264 转为 H.265 以减小文件体积)。
编解码: 对音频和视频流进行编码(压缩)和解码(播放)。
视频抓取和录制: 从视频设备或屏幕上抓取内容。
流媒体处理: 支持推流、拉流以及流媒体的转换。
基本编辑: 如裁剪、拼接、调整音量、添加水印、调整速度等。
信息提取与分析: 使用 ffprobe 获取媒体的详细信息。
4、是否依赖硬件?可选
7、PQ及其他视频处理模块
1、这些是什么,处于什么层级?
1)在传输给显示屏真正显示之前,对图像数据的校准,以获得满足需求的显示效果;
2)可以使用GPU+软件算法实现?当然可以,使用硬件模块处理是为了高效,分担CPU/GPU的负担!
3)可以集成在CPU或独立的硬件模块(主板端或屏端都可以);
2、如何工作?
配置好寄存器,硬件自动工作?
Android平台下 drm,kms中有设置色温的属性吗?
/android/frameworks/base/services/core/java/com/android/server/display/color/ColorDisplayService.java
ColorDisplayService.java中的colormatirx,这个可以调色温,
何小龙 - drm 有对 PQ 的支持,主要通过 property 来设置,大部分 code 都在 drm_color_mgmt.c 中。
PQ 一般不经过 gpu 驱动,主要通过窗口系统来直接设置,目前没有标准的做法,都是各 vendor 厂商自己添加的,gamma_lut 对色温能起到一定的效果,大部分硬件还是通过 color matrix 来实现色温效果的。
8、图形处理的专业化-音视频领域
1)图形、图像处理专业知识复杂庞大,属于音视频专业领域,有专门的工种
1、渲染引擎工程师(skia、nanovg、agg);
2、Android图示工程师(Android图形系统性能,帧率优化);
3、OS视窗高级工程师(skia、软硬件合层、x11/wayland);
2)涉及的模块?
中间件 - Opengl、ffmpeg、skia等等
硬件音视频处理模块 - GPU、视频编解码、音频编解码等等