iOS 原生渲染与 Flutter 有什么区别 (上)
theme: smartblue
「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。
前言
今天,我们在这篇文章中来聊聊渲染原理以及iOS原生是如何渲染的。
iOS 原生渲染与 Flutter 有什么区别
渲染原理
首先我们说说渲染原理,对于我们看到的手机界面,都是使用CPU + GPU
运算绘制出来的,CPU
和GPU
在设计的的初始时职责就有所不同,CPU
拥有强大的运算能力,是整个系统的控制核心,通常会帮助计算显示内容,GPU
是专门进行绘图运算工作的处理器,并行计算能力更强,能够通过计算将图形结果显示在屏幕上。我们通常说的渲染也就是内存中的图形数据再经过计算和转换,最终呈现到屏幕上的过程。
在渲染过程中,CPU
则处理渲染内容的计算,如视图创建、计算布局、图片解码等,内容计算完成后,再传输给 GPU
进行渲染。
而GPU
主要是将 3D
坐标转化成 2D
坐标 继而再转成实际像素,具体实现可以分为顶点着色器(确定形状的点)、形状装配(确定形状的线)、几何着色器(确定三角形个数)、光栅化(确定屏幕像素点)、片段着色器(对像素点着色)、测试与混合(检查深度和透明度进行混合)六个阶段。
原生渲染
原生渲染的层级可以分为以下几个层级:
UIKit
、Core Animation
、OpenGL ES
、Graphics Hardware
UIKit
:UI基础库,用来满足我们上层开发;Core Animation
:负责图形渲染与动画的基础设施,Core Animation
将大部分实际的绘图任务交给了图形硬件来处理。OpenGL ES
:OpenGL 的子集,一套专门处理GPU绘制的API。Core Graphics
: 基于 Quartz 高级绘图引擎。它提供了具有无与伦比的输出保真度的低级别轻量级 2D 渲染。您可以使用此框架来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像创建和图像遮罩以及 PDF 文档创建,显示和分析。Graphics Hardware
: 图形硬件,
原生界面更新渲染的流程,可以分为以下流程。
第一步,更新视图树,同步更新图层树。当在操作 UI 时 如果改变了视图Frame或者更新了 UIView / CALayer
的层级时,或者手动调用了 UIView / CALayer
的 setNeedsLayout / setNeedsDisplay
方法后,在此过程中 app 可能需要更新 视图树
,相应地,图层树
也会被更新;
第二步,CPU 计算要显示的内容,包括视图创建(设置 Layer 的属性)、布局计算、视图绘制(创建 Layer 的 Backing Image)、图像解码转换。当 runloop
在 BeforeWaiting 和 Exit
状态时,会通知注册的监听,然后对图层打包,打完包后,将打包数据发送给一个独立负责渲染的进程 Render Server
。
第三步,数据到达 Render Server
后会被反序列化,得到图层树,按照图层树中图层顺序、RGBA 值、图层 frame 过滤图层中被遮挡的部分,过滤后将图层树转成渲染树,渲染树的信息会转给 OpenGL ES/Metal
。前面 CPU
所处理的这些事情统称为 Commit Transaction
。
第四步,Render Server
会调用 GPU
,GPU
开始进行前面提到的顶点着色器、形状装配、几何着色器、光栅化、片段着色器、测试与混合六个阶段。完成这六个阶段的工作后,再将 CPU
和 GPU
计算后的数据显示在屏幕的每个像素点上。整个渲染过程,如下图所示:
如上图所示,CPU
处理完渲染内容会输入到 Render Server
中,经图层树和渲染树的转换,通过 OpenGL
接口提供给 GPU
,GPU
处理完后在屏幕上显示。渲染过程中 Commit Trasaction
的布局计算会重载视图 layoutSubviews
方法,以及执行 addSubview
方法来添加视图。视图绘制会重载视图的 drawRect
方法。这几个方法都是 iOS
开发中常用的。移动视图位置、删除视图、隐藏或显示视图、调用 setNeedsDisplay
或 setNeedsDisplayInRect
方法,都会触发界面更新,执行渲染流程。
Render Server
Render Server
六个阶段如下:
1. 顶点着色器(Vertex Shader
)。该阶段的输入是 顶点数据(Vertex Data
),比如以数组的形式传递 3 个 3D 坐标用来表示一个三角形。顶点数据是一系列顶点的集合。顶点着色器主要的目的是把 3D 坐标转为另一种 3D 坐标,同时顶点着色器可以对顶点属性进行一些基本处理。
-
形状(图元)装配(
Shape Assembly
)。该阶段将顶点着色器输出的所有顶点作为输入,并将所有的点装配成指定图元的形状。图中则是一个三角形。图元(Primitive) 用于表示如何渲染顶点数据,如:点、线、三角形。 -
几何着色器(
Geometry Shader
)。该阶段把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。例子中,它生成了另一个三角形。 -
光栅化(
Rasterization
)。该阶段会把图元映射为最终屏幕上相应的像素,生成片段。片段(Fragment) 是渲染一个像素所需要的所有数据。 -
片段着色器(
Fragment Shader
)。该阶段首先会对输入的片段进行 裁切(Clipping)。裁切会丢弃超出视图以外的所有像素,用来提升执行效率。 -
测试与混合(
Tests and Blending
)。该阶段会检测片段的对应的深度值
(z 坐标),判断这个像素位于其它物体的前面还是后面,决定是否应该丢弃。此外,该阶段还会检查alpha
值( alpha 值定义了一个物体的透明度),从而对物体进行混合。因此,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。
写在最后
本章着重聊了聊渲染的原理以及iOS原生渲染的过程,那么在下一篇文章中,我们在聊聊目前火热的Flutter
它的渲染流程是如何的,以及它跟原生渲染还有一些其他的前端渲染有何区别。敬请期待!
- LeetCode 初级算法之数组(上),看看你都学会了吗?
- LeetCode 初级算法之链表,看看你都学会了吗?
- LeetCode 初级算法之字符串(上),看看你都学会了吗?
- 纯代码布局,也可以一样的简洁
- UIStackView之一问一答
- 使用UIStackView来简化iOS的界面布局
- 夏天来了,iOS开发者们该如何减少App耗电?(上)
- 夏天来了,App开发者们如何看待手机发烫问题?
- 聊聊iOS中UITableView复用的那些事
- 曾经经典的微信打飞机游戏还有人记得吗?
- iOS 原生渲染与 Flutter 有什么区别 (上)
- 了解 Mach-O文件
- CocoaPods中podsepc文件设置详解
- iOS 原生渲染与 Flutter 有什么区别 (下)
- 简单了解 iOS CVPixelBuffer (上)
- 谈谈 iOS 包瘦身方案
- 播放器重构的探索之路
- 如何使用CocoaPods制作私有库
- iOS 组件化方案