文章目录
-
- [Android 图形库体系回顾](#Android 图形库体系回顾)
- 1、应用程序调用什么接口进行绘图?
- 2、canvas
- 3、2D图形引擎库-skia
-
- 1)资料快车
- 2)概况
- [3)Android4.0 - skia框架](#3)Android4.0 - skia框架)
- 4)Skia外部组件依赖
- [5)Skia 软件层次分析](#5)Skia 软件层次分析)
- 6)SKia图形库架构分析
- 7)使用skia
- 8)调用流程示例
- 4、Android上使用canvas和skia
- 5、HWUI介绍
- [6、HWUI (Hardware UI) 架构分析](#6、HWUI (Hardware UI) 架构分析)
-
- [1)HWUI 概述](#1)HWUI 概述)
- 2)核心功能
- [3)在 Android GUI 架构中的位置](#3)在 Android GUI 架构中的位置)
- [7、HWUI 核心组件分析](#7、HWUI 核心组件分析)
- 8、典型的硬件渲染过程
Android 图形库体系回顾

canvas和skia是Android图形库体系中的一部分,硬件渲染才会通过HWUI使用skia,对于图形库,我们把握框架即可
1、应用程序调用什么接口进行绘图?
在Android应用程序中是通过Canvas API来绘制UI元素的。在硬件加速渲染环境中,这些Canvas API调用最终会转化为OpenGL API调用(转化过程对应用程序来说是透明的)。由于OpenGL API调用要求发生在Open GL环境中,因此在每当有新的Activity窗口启动时,系统都会为其初始化好OpenGL环境。
2、canvas
1)canva是java层的一个绘图工具(提供java应用层的绘图接口 - 矩形、三角形),native层实现是skia;
2)Android官方定义canva:The Canvas class holds the draw calls,是一个将"图像数据"写入Bitmap中的一个工具集;
3)canva和Skia支撑着整个Android的上层视觉呈现;
3、2D图形引擎库-skia
1)资料快车
注意skia的资料相对匮乏!
skia的学习与研究
https://zhuanlan.zhihu.com/p/27494299049
深入理解Flutter的图形图像绘制原理------图形库skia剖析
https://mp.weixin.qq.com/s/NwW4SKe1uFYkPh94pAsprA
Skia 2D引擎开发知识分享:
https://blog.csdn.net/liulun/article/details/145071567
Skia编译及实践:
https://segmentfault.com/a/1190000044507663#item-2-1
Google官网: https://code.google.com/p/skia
2)概况
Skia 是一个跨平台的 2D 图形渲染库(百万代码行级别),由 Google 开发并维护,在 Android 系统中,Skia 是底层图形渲染的核心引擎,
SKia - 需要用到GPU? 可选用硬件GPU 或 软件CPU方式处理
Skia 提供以下核心功能:
Skia 提供统一的图形 API,屏蔽底层硬件差异
动画实现(animator目录)、图片界面、文件绘制、支持多种特效(effects目录)
1. 2D 图形绘制
- 几何图形:矩形、圆形、路径、文本等
- 图像处理:解码、编码、缩放、旋转等
- 效果处理:模糊、阴影、渐变、滤镜等
2. 渲染后端支持 - Skia 通过 EGL/Vulkan 等标准接口与底层驱动交互
- **软件渲染**:使用 CPU 进行像素级绘制(`SkBitmapDevice`)
- **硬件加速**:使用 GPU 进行加速渲染(`GrDirectContext`)
- OpenGL ES 后端(`GrGLGpu`)
- Vulkan 后端(`GrVkGpu`)
3. 图像编解码
- 支持多种图像格式:JPEG、PNG、WebP、BMP、ICO 等
- 提供 `SkCodec` 接口进行图像解码
4. 文本渲染
- 字体管理(`SkFontMgr`)
- 文本布局和渲染
- 支持复杂文本效果
3)Android4.0 - skia框架

4)Skia外部组件依赖

1、最新架构中SKGPUDevice被替换为GrDirectContext方式;
5)Skia 软件层次分析

1、Skia在结构上大致分为三层:画步层,渲染设备层和封装适配层
6)SKia图形库架构分析
1.缩略词
GrGpu -Graphics GPU
GrGL - Graphics OpenGL
GrContext - Graphics Context
2.Skia的基础组件:
- `SkCanvas` - 绘制画布
- `SkPaint` - 画笔
- `SkPath` - 路径
- `SkImage` - 图像
- `SkShader` - 着色器
3.示例程序
1)一个简单的使用skia例子
/android/external/skia/example/HelloWorld.cpp
2)CPU/GPU方式skia编程例子
Skia编译及实践:
https://segmentfault.com/a/1190000044507663#item-2-1
4.源码目录结构
external/skia/
├── include/ # 公共头文件
│ ├── core/ # 核心 API (SkCanvas, SkSurface, SkPaint 等)
│ ├── gpu/ # GPU 相关 API (GrDirectContext, GrGpu 等)
│ ├── effects/ # 效果 API (模糊、渐变等)
│ └── android/ # Android 特定接口
├── src/ # 源代码
│ ├── core/ # 核心实现
│ │ ├── SkCanvas.cpp //定义了SKCanvas类,它是所有图形渲染操作的基础
│ │ ├── SkSurface.cpp
│ │ ├── SkBitmapDevice.cpp # 软件渲染设备
│ │ └── SkDraw.cpp # 底层绘制引擎
│ ├── gpu/ # GPU 后端实现
│ │ ├── GrDirectContext.cpp //定义了GrDirectContext类,它是Skia的GPU渲染上下文
│ │ ├── gl/ # OpenGL ES 后端
│ │ │ ├── GrGLGpu.cpp
│ │ │ └── GrGLInterface.cpp
│ │ └── vk/ # Vulkan 后端
│ │ └── GrVkGpu.cpp
│ ├── codec/ # 图像编解码
│ └── effects/ # 效果实现
│ └── fronts/ # 文字渲染
│ └── image/ # 图像处理
│ └── pdf/ # 支持图形渲染为PDF文档,渲染结果不是输出到显示器的画面,而是输出为pdf文件。
│ └── svg/ # Scalable Vector Graphics,可缩放矢量图形渲染
| └── tools/skiatest.cpp //包含了一系列Skia测试用例,可以用于验证Skia的功能。
└── Android.bp # Android 构建文件
5. 核心类关系
SkCanvas (绘制接口)
↓
SkBaseDevice (设备基类)
├── SkBitmapDevice (软件渲染设备)
└── GrBaseDevice (GPU 设备基类)
└── GrSurfaceDrawContext (GPU 渲染设备)
SkSurface (渲染表面)
├── SkSurface_Raster (软件渲染表面)
└── SkSurface_Gpu (GPU 渲染表面)
GrDirectContext (GPU 上下文)
↓
GrGpu (GPU 抽象基类)
├── GrGLGpu (OpenGL ES 后端)
├── GrVkGpu (Vulkan 后端)
└── GrMtlGpu (Metal 后端)
6.skia在Android GUI 架构层次
┌─────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ - View.onDraw(Canvas) │
│ - Canvas.drawRect(), drawText() 等 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Android Framework 层 │
│ - Canvas.java (Java API) │
│ - ThreadedRenderer.java │
│ - HardwareRenderer.java │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ HWUI 层 (Hardware UI) │
│ - SkiaCanvas (Skia 的薄包装层) │
│ - RecordingCanvas (硬件加速记录) │
│ - RenderProxy, CanvasContext │
│ - DisplayList, RenderNode │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Skia 层 (本文档分析) │
│ - SkCanvas (绘制接口) │
│ - SkSurface (渲染表面) │
│ - SkBitmapDevice (软件渲染) │
│ - GrDirectContext (GPU 上下文) │
│ - GrGLGpu / GrVkGpu (GPU 后端) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 图形驱动层 │
│ - EGL (OpenGL ES 接口层) │
│ - Vulkan (Vulkan API) │
│ - Mesa / Panfrost (GPU 驱动) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 内核层 (Kernel) │
│ - DRM/KMS (Direct Rendering Manager) │
│ - GPU 硬件 │
└─────────────────────────────────────────────────────────┘
7.对外提供的核心API接口
1)SkCanvas - 绘制接口
1、头文件include/core/SkCanvas.h`
- 提供所有绘制操作:`drawRect()`, `drawText()`, `drawPath()`, `drawImage()` 等
- 管理绘制状态:变换矩阵、裁剪区域、Paint 属性
- 支持图层操作:`save()`, `restore()`, `saveLayer()`
2、SkCanvas类
class SkCanvas {
public:
// 绘制操作
void drawRect(const SkRect& r, const SkPaint& paint);
void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint);
void drawPath(const SkPath& path, const SkPaint& paint);
void drawImage(sk_sp<const SkImage> image, SkScalar x, SkScalar y, const SkSamplingOptions&, const SkPaint* paint);
// 状态管理
int save();
void restore();
void restoreToCount(int count);
// 变换和裁剪
void translate(SkScalar dx, SkScalar dy);
void scale(SkScalar sx, SkScalar sy);
void rotate(SkScalar degrees);
void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias);
};
2)SkSurface - 渲染表面
1、头文件include/core/SkSurface.h
- 创建和管理渲染表面(CPU 内存或 GPU 纹理)
- 提供 `getCanvas()` 获取绘制接口
- 支持离屏渲染和屏幕渲染
2、SkSurface类
class SkSurface {
public:
// 创建软件渲染表面
static sk_sp<SkSurface> MakeRaster(const SkImageInfo& imageInfo, size_t rowBytes, const SkSurfaceProps* props);
static sk_sp<SkSurface> MakeRasterDirect(const SkImageInfo& imageInfo, void* pixels, size_t rowBytes, const SkSurfaceProps* props);
// 创建 GPU 渲染表面
static sk_sp<SkSurface> MakeRenderTarget(GrRecordingContext* context, SkBudgeted budgeted, const SkImageInfo& imageInfo, int sampleCount, GrSurfaceOrigin origin, const SkSurfaceProps* props, bool shouldCreateWithMips);
// 获取绘制接口
SkCanvas* getCanvas();
// 图像操作
sk_sp<SkImage> makeImageSnapshot();
bool readPixels(const SkPixmap& pm, int srcX, int srcY);
};
3) GrDirectContext - GPU 上下文
1、头文件:include/gpu/GrDirectContext.h`
功能
- 管理 GPU 资源和上下文
- 提供 GPU 加速的渲染能力
- 支持 OpenGL ES、Vulkan、Metal 等后端
2、GrDirectContext类
class GrDirectContext : public GrRecordingContext {
public:
// 创建 OpenGL ES 上下文
static sk_sp<GrDirectContext> MakeGL(sk_sp<const GrGLInterface> glInterface, const GrContextOptions& options);
// 创建 Vulkan 上下文
static sk_sp<GrDirectContext> MakeVulkan(const GrVkBackendContext& backendContext, const GrContextOptions& options);
// 资源管理
void flush();
void submit(bool syncCpu);
void resetGLTextureBindings();
// 查询能力
const GrCaps* caps() const;
};
4)SkImage - 图像接口
1、头文件include/core/SkImage.h`
2、功能
- 表示图像数据(位图、纹理、编码图像等)
- 支持图像变换、缩放、裁剪
- 支持从文件、内存、GPU 纹理创建图像
5)SkPaint - 绘制属性
1、头文件:include/core/SkPaint.h
2、功能
- 定义绘制属性:颜色、样式、字体、效果等
- 支持各种绘制效果:模糊、阴影、渐变、滤镜等
7)使用skia
当使用软件渲染时应用程序可以直接调用skia的API,使用硬件GPU渲染时一般借助hwui方便地使用skia
- 软件绘制:`SkiaCanvas` 包装 `SkCanvas(bitmap)` → `SkBitmapDevice`
- 硬件加速:`SkiaPipeline` 使用 `GrDirectContext` → `GrGLGpu` / `GrVkGpu`
这里介绍硬件渲染
1)HWUI (Hardware UI)
frameworks/base/libs/hwui/
1、View System使用HWUI
1)Android Framework Canvas API
frameworks/base/core/java/android/graphics/Canvas.java`
- Java 层通过JNI调用HWUI的SkiaCanvas
- 最终调用Skia的SkCanvas API
流程图
Canvas.java.drawRect()
↓ [JNI]
android_graphics_Canvas.cpp::drawRect()
↓
SkiaCanvas::drawRect()
↓
SkCanvas::drawRect()
2、HWUI创建SKCanvas
- SkiaCanvas:直接使用 `SkCanvas` 进行绘制
frameworks/base/libs/hwui/SkiaCanvas.cpp
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
}
3、使用GrDirectContext进行 GPU 加速渲染
// frameworks/base/libs/hwui/pipeline/skia/SkiaPipeline.cpp
// 创建 GPU 上下文和表面
sk_sp<GrDirectContext> context = GrDirectContext::MakeGL(...);
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context.get(), ...);
4.图形绘制接口
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
mCanvas->drawRect({left, top, right, bottom}, p);
}
8)调用流程示例
1、EGL 接口层
位置 :系统库 libEGL.so
功能:
- 提供 OpenGL ES 与窗口系统的接口
- 管理渲染上下文(Context)
- 管理渲染表面(Surface)
Skia 使用方式:
// Skia 通过 EGL 创建 OpenGL ES 上下文
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLContext context = eglCreateContext(display, config, ...);
// 然后通过 GrGLInterface 封装 OpenGL ES 调用
2、软件绘制流程
View.onDraw(Canvas)
→ Canvas.java.drawRect()
→ SkiaCanvas::drawRect()
→ SkCanvas::drawRect()
→ SkBitmapDevice::drawRect()
→ SkDraw::drawRect()
→ CPU 内存操作
3、硬件加速流程
View.onDraw(Canvas)
→ RecordingCanvas (记录命令)
→ DisplayList
→ RenderThread
→ SkiaPipeline::draw()
→ SkCanvas::drawRect() (GPU Surface)
→ GrDirectContext
→ GrGLGpu::drawRect()
→ OpenGL ES API
→ EGL
→ Mesa/Panfrost
→ GPU 硬件
4、Android上使用canvas和skia
1.Canvas
/android/frameworks/base/graphics/java/android/graphics/Canvas.java
public class Canvas extends BaseCanvas {
Bitmap mBitmap;
DrawFilter mDrawFilter;
scale(float sx, float sy);
rotate(float degrees, float px, float py);
clipRect(float left, float top, float right, float bottom);
// ---------------- Draw Methods -------------------
drawArc();
drawCircle();
drawLine();
}
2.Canvas的创建
/android/frameworks/base/core/java/android/view/Surface.java
lockCanvas(Rect inOutDirty)
--nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); //mCanvas = new CompatibleCanvas();
/android/frameworks/base/core/jni/android_view_Surface.cpp
----sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); //C++层的Surface对象
----surface->lock(&buffer, dirtyRectPtr); //获得一个可用的buffer
----graphics::Canvas canvas(env, canvasObj);
----canvas.setBuffer(&buffer); //设置canvas的buffer
3.ANativeWindow_Buffer
/android/frameworks/native/libs/nativewindow/include/android/native_window.h
typedef struct ANativeWindow_Buffer {
int32_t width;
int32_t height;
int32_t stride;
int32_t format;
void* bits;
}ANativeWindow_Buffer;
4.drawCircle() -软件绘制
/android/frameworks/base/graphics/java/android/graphics/Canvas.java
drawCircle()
/android/frameworks/base/graphics/java/android/graphics/BaseCanvas.java
--super.drawCircle()
/android/external/skia/src/core/SkBitmapDevice.cpp
void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
BDDraw(this).drawRect(r, paint);
}
5.drawCircle() - 硬件绘制
/android/frameworks/base/graphics/java/android/graphics/Canvas.java
drawCircle()
/android/frameworks/base/graphics/java/android/graphics/BaseCanvas.java
--super.drawCircle()
/android/frameworks/base/libs/hwui/jni/android_graphics_Canvas.cpp
----nDrawCircle()
------CanvasJNI::drawCircle()
--------get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
/android/frameworks/base/libs/hwui/SkiaCanvas.cpp
----------mCanvas->drawCircle(x, y, radius, p) //最终陷入到skia中去
5、HWUI介绍
1.Android HWUI 介绍:
https://zhuanlan.zhihu.com/p/1914686827882853373
6、HWUI (Hardware UI) 架构分析
1)HWUI 概述
1、HWUI (Hardware UI)是 Android的硬件加速渲染库,即使用GPU渲染,负责对接 Android Java层视图系统(View System)到 native的图形库,在android低版本上通过libhwui调用OpenGL api来渲染, Android P上libhwui 会调用skia,再调用GLES相关的API进行渲染。
2)核心功能
1)显示列表记录:将 View 的绘制命令记录为 DisplayList,再次渲染只更新DisplayList中的部分区域
2)渲染线程管理:在独立线程中执行 GPU 渲染,避免阻塞 UI 线程
3)Skia 集成:基于 Skia 图形库实现底层绘制
4)OpenGL/Vulkan 支持:支持 OpenGL ES 和 Vulkan 两种渲染后端
3)在 Android GUI 架构中的位置
1、View体系到GPU的调用路径
┌─────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ - Activity, Fragment, View │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ View 系统层 (View System) │
│ - ViewRootImpl │
│ - ThreadedRenderer (Java) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ HWUI 层 (Hardware UI Library) ← 当前层级 │
│ - RenderNode, RecordingCanvas │
│ - RenderProxy, CanvasContext │
│ - SkiaPipeline │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Skia 图形库层 │
│ - SkCanvas, SkPaint, SkPath │
│ - Skia GPU Backend │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ OpenGL ES / Vulkan 驱动层 │
│ - EGL / Vk │
│ - Mesa/Panfrost (开源驱动) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ GPU 硬件层 │
│ - Mali, Adreno, PowerVR 等 GPU │
└─────────────────────────────────────────────────────────┘
```
3.2 调用路径示例
应用代码
↓
View.onDraw(Canvas canvas)
↓
RecordingCanvas (记录绘制命令)
↓
RenderNode (存储 DisplayList)
↓
ViewRootImpl.performTraversals() - JAVA
↓
ThreadedRenderer.draw() - JAVA
↓ [JNI]
RenderProxy.syncAndDrawFrame() ← HWUI 入口
↓
CanvasContext.draw()
↓
SkiaPipeline.draw()
↓
SkCanvas (Skia)
↓
OpenGL-ES/Vulkan -mesa3D
↓
Panfrost (开源用户态驱动) - libdrm
↓
GPU driver - DRM/KMS (开源内核态驱动)
↓
GPU 硬件
7、HWUI 核心组件分析
1)主要目录结构
hwui/
├── jni/ # JNI 接口层 - 同时也是对外接口层
│ ├── android_graphics_HardwareRenderer.cpp
│ ├── android_graphics_RenderNode.cpp
│ └── android_graphics_Canvas.cpp
│
├── renderthread/ # 渲染线程管理
│ ├── RenderProxy.cpp # UI 线程和渲染线程的代理
│ ├── RenderThread.cpp # 渲染线程主循环
│ ├── CanvasContext.cpp # 渲染上下文管理
│ └── DrawFrameTask.cpp # 绘制帧任务
│
├── pipeline/ # 渲染管线
│ └── skia/
│ ├── SkiaPipeline.cpp # Skia 渲染管线
│ ├── SkiaOpenGLPipeline.cpp # OpenGL 后端
│ └── SkiaVulkanPipeline.cpp # Vulkan 后端
│
├── RenderNode.cpp # 渲染节点(存储 DisplayList)
├── RecordingCanvas.cpp # 记录画布(记录绘制命令)
└── ...
```
2)核心类说明
2.1 RenderNode
- **功能**:存储视图的绘制命令和属性
- **位置**:`RenderNode.h/cpp`
- **作用**:
- 存储 DisplayList(显示列表)
- 存储 RenderProperties(渲染属性:变换、裁剪等)
- 支持硬件层(Hardware Layer)
2.2 RecordingCanvas
- **功能**:记录绘制命令到 DisplayList
- **位置**:`RecordingCanvas.h/cpp`
- **作用**:
- 将 View.onDraw() 中的绘制命令记录为 DisplayList
- 不立即执行绘制,而是记录命令序列
2.3 RenderProxy
- **功能**:UI 线程和渲染线程之间的代理
- **位置**:`renderthread/RenderProxy.h/cpp`
- **作用**:
- 管理线程间通信
- 同步 UI 线程和渲染线程
- 提交绘制任务到渲染线程
2.4 CanvasContext
- **功能**:管理渲染上下文和 EGL/Vulkan
- **位置**:`renderthread/CanvasContext.h/cpp`
- **作用**:
- 管理 EGL 上下文或 Vulkan 设备
- 管理渲染表面(Surface)
- 执行实际的绘制操作
2.5 SkiaPipeline
- **功能**:基于 Skia 的渲染管线实现
- **位置**:`pipeline/skia/SkiaPipeline.h/cpp`
- **作用**:
- 将 DisplayList 转换为 Skia 绘制命令
- 调用 Skia API 进行绘制
- 支持 OpenGL 和 Vulkan 两种后端
3)HWUI 工作流程
完整渲染流程
1. UI 线程:View.onDraw(Canvas)
└─> RecordingCanvas 记录绘制命令
└─> 存储到 RenderNode 的 DisplayList
2. UI 线程:ViewRootImpl.performTraversals()
└─> ThreadedRenderer.draw()
└─> updateRootDisplayList() 更新所有 View 的 DisplayList
└─> syncAndDrawFrame() [JNI 调用]
3. JNI 层:android_graphics_HardwareRenderer.cpp
└─> RenderProxy.syncAndDrawFrame()
└─> 提交 DrawFrameTask 到渲染线程
4. 渲染线程:RenderThread
└─> DrawFrameTask.run()
└─> CanvasContext.draw()
└─> SkiaPipeline.draw()
└─> 遍历 RenderNode 树
└─> 执行 DisplayList 中的绘制命令
└─> 调用 Skia API
5. Skia 层
└─> SkCanvas 绘制操作
└─> Skia GPU Backend
└─> 生成 OpenGL/Vulkan 命令
6. 驱动层
└─> OpenGL ES / Vulkan API
└─> EGL / Vulkan 驱动
└─> Mesa/Panfrost
└─> GPU 硬件执行
8、典型的硬件渲染过程
