iOS图形渲染流程图解析(硬件、软件、OpenGL)

一、硬件渲染流程

image

上图为图片硬件中的流程。

GPU具有纹理(位图),可以在每帧中将它们合成在一起(即每秒60次)。每个纹理占用VRAM(视频RAM),因此GPU可以保留多少个纹理是有限制的。GPU的合成效率非常高,但是某些合成任务比其他任务更为复杂,并且GPU在16.7毫秒(1/60 s)内可以完成的工作量是有限制的。

下一步就是将数据传输到GPU,为了使GPU访问到数据,需要将其从RAM移到VRAM。这看似微不足道,但是对于大图而言,这可能会非常耗时。

当CPU运行程序时,程序判断图片格式,将图片解压缩,然后以某种方式上传到GPU。但是对于CPU来说,像显示文本这样平凡的事情是一项极其复杂的任务,它促进了Core Text和Core Graphics框架之间的紧密集成以从文本生成位图。准备就绪后,它会作为纹理上传到GPU,准备显示。但是,当您在屏幕上滚动或移动该文本时,可以重复使用相同的纹理,CPU会简单地告诉GPU新位置是什么,以便GPU可以重复使用现有纹理。CPU不必重新渲染文本,位图也不必重新上传。

二、iOS图形软件渲染流程

image

GPU是高度并发的处理单元,专门为图形的并行计算量身定制。这样便可以更新所有这些像素并将结果推送到显示器上。它的并行特性还使其可以非常有效地将纹理合成到彼此。关键是GPU非常专业,因此在某些工作中效率很高,也就是说,它非常快并且比CPU消耗的功率少。特点是专一、高并发。

iOS 渲染框架

1.Core Animation

Core Animation 源自于 Layer Kit,动画只是 Core Animation 特性的冰山一角。

Core Animation 是一个复合引擎,其职责是 尽可能快地组合屏幕上不同的可视内容,这些可视内容可被分解成独立的图层(即 CALayer),这些图层会被存储在一个叫做图层树的体系之中。从本质上而言,CALayer 是用户所能在屏幕上看见的一切的基础。

2.Core Graphics

Core Graphics 基于 Quartz 高级绘图引擎,主要用于运行时绘制图像。开发者可以使用此框架来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像创建和图像遮罩以及 PDF 文档创建,显示和分析

当开发者需要在 运行时创建图像 时,可以使用 Core Graphics 去绘制。与之相对的是 运行前创建图像,例如用 Photoshop 提前做好图片素材直接导入应用。相比之下,我们更需要 Core Graphics 去在运行时实时计算、绘制一系列图像帧来实现动画。

3.Core Image

Core Image 与 Core Graphics 恰恰相反,Core Graphics 用于在 运行时创建图像,而 Core Image 是用来处理 运行前创建的图像 的。Core Image 框架拥有一系列现成的图像过滤器,能对已存在的图像进行高效的处理。

大部分情况下,Core Image 会在 GPU 中完成工作,但如果 GPU 忙,会使用 CPU 进行处理。

4.OpenGL ES

OpenGL ES(OpenGL for Embedded Systems,简称 GLES),是 OpenGL 的子集。在前面的 图形渲染原理综述 一文中提到过 OpenGL 是一套第三方标准,函数的内部实现由对应的 GPU 厂商开发实现。

UIView 与 CALayer 的关系

UIKit 中的每一个 UI 视图控件其实内部都有一个关联的 CALayer,即 backing layer。

image

视图的职责是 创建并管理 图层,以确保当子视图在层级关系中 添加或被移除 时,其关联的图层在图层树中也有相同的操作,即保证视图树和图层树在结构上的一致性。as

其原因在于要做 职责分离,这样也能避免很多重复代码。在 iOS 和 Mac OS X 两个平台上,事件和用户交互有很多地方的不同,基于多点触控的用户界面和基于鼠标键盘的交互有着本质的区别,这就是为什么 iOS 有 UIKit 和 UIView,对应 Mac OS X 有 AppKit 和 NSView 的原因。它们在功能上很相似,但是在实现上有着显著的区别。

那么为什么 iOS 要基于 UIView 和 CALayer 提供两个平行的层级关系呢?

其原因在于要做 职责分离,这样也能避免很多重复代码。在 iOS 和 Mac OS X 两个平台上,事件和用户交互有很多地方的不同,基于多点触控的用户界面和基于鼠标键盘的交互有着本质的区别,这就是为什么 iOS 有 UIKit 和 UIView,对应 Mac OS X 有 AppKit 和 NSView 的原因。它们在功能上很相似,但是在实现上有着显著的区别。

实际上,这里并不是两个层级关系,而是四个。每一个都扮演着不同的角色。除了 视图树图层树,还有 呈现树渲染树

CALayer

CALayer 基本等同于一个 纹理。纹理是 GPU 进行图像渲染的重要依据。在 图形渲染原理 中提到纹理本质上就是一张图片,因此 CALayer 也包含一个 contents 属性指向一块缓存区,称为 backing store,可以存放位图(Bitmap)。iOS 中将该缓存区保存的图片称为 寄宿图

image

Contents Image

该属性对 CGImage 和 NSImage 类型的值都起作用,而在 iOS 系统中,该属性只对 CGImage 起作用。本质上,contents 属性指向的一块缓存区域,称为 backing store,可以存放 bitmap 数据。

三、OpenGL渲染架构

image

①渲染流程:

1.设置顶点数据等参数。

2.在顶点着色器中进行运算获取裁剪坐标。

3.细分着色器、几何着色器,不可自定义,跳过。

4.图元设置,根据设置构成点、线、三角形。

5.裁剪,裁剪掉超出显示区域的部分。

6.光栅化, 将图源栅格化为一个个的像素点。

7.片元着色器,将对应的栅格(像素)填充为具体的颜色。

8.渲染图像。

②参数

attrubutes属性只能传入顶点着色器,不能直接传递到片元着色器,只能通过GLSL代码间接传递。

顶点数据

纹理坐标

光照法线

颜色数据

uniforms值只是一个通道,可以传入矩阵、顶点着色器、片元着色器等。

③参数的使用

顶点着色器

我们可以通过attrubutes获取到顶点数据,通过uniforms获取到mvp矩阵,再进行运算得到最终的顶点坐标。

片元着色器

比如在处理视频帧时,一般会使用YUV格式。要渲染到屏幕上需要将YUV格式转换为RGB格式。在片元着色器中,通过YUV数据进行矩阵运算就可以得到具体的RBG颜色值了。Alpha通道直接赋值为1.0。

纹理

像素填充数据。片元着色器中,可以通过纹理坐标获取到对应的颜色值。如果对得到的颜色值进行处理,就可以得到“滤镜”效果。

④9种基本元图

image

GL_POINTS每个顶点在屏幕上都是单独点

GL_LINES每⼀对顶点定义⼀个线段

GL_LINE_STRIP一个从第⼀个顶点依次经过每⼀个后续顶点而绘制的线条

GL_LINE_LOOP和GL_LINE_STRIP相同,但是最后⼀个顶点和第⼀个顶点连接起来了

GL_TRIANGLES每3个顶点定义⼀个新的三角形

GL_TRIANGLE_STRIP共⽤一个条带(strip)上的顶点的一组三⻆形

GL_TRIANGLE_FAN以⼀个圆点为中⼼呈扇形排列,共⽤相邻顶点的⼀组三⻆形

四、常用API

1.初始化

// GLShaderManager 的初始化
GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();

单元着⾊器

参数1: 存储着⾊器种类-单元着⾊器
参数2: 颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY, 
                                 GLfloat vColor[4]);

平⾯着⾊器

参数1: 存储着⾊器种类-平⾯着⾊器
参数2: 允许变化的4*4矩阵
参数3: 颜⾊色值
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,
                                 GLfloat mvp[16],
                                 GLfloat vColor[4]);
使⽤场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。

上⾊着⾊器

参数1: 存储着⾊器种类-上⾊着⾊器
参数2: 允许变化的4*4矩阵
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,
                                 GLfloat mvp[16]);
使⽤场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。颜色将会平滑地插入到顶点之间,称为平滑着色。

默认光源着⾊器

参数1: 存储着⾊器种类-默认光源着⾊器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,
                                 GLfloat mvMatrix[16],
                                 GLfloat pMatrix[16],
                                 GLfloat vColor[4]);
使⽤场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。这种着⾊器会使绘制的图形产生阴影和光照的效果。

点光源着⾊器

参数1: 存储着⾊器种类-点光源着⾊器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源的位置
参数5: 漫反射颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,
                                 GLfloat mvMatrix[16],
                                 GLfloat pMatrix[16],
                                 GLfloat vLightPos[3],
                                 GLfloat vColor[4]);
使⽤场景:在绘制图形时, 可以应用变换(模型/投影变化)

纹理替换矩阵着⾊器

参数1: 存储着⾊器种类-纹理替换矩阵着⾊器
参数2: 模型4*4矩阵
参数3: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,
                                 GLfloat mvMatrix[16],
                                 GLint nTextureUnit);
使⽤场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。这种着⾊器通过给定的模型视图投影矩阵,使⽤纹理单元来进⾏颜⾊填充。其中每个像素点的颜⾊是从纹理中获取。

纹理调整着⾊器

参数1: 存储着⾊器种类-纹理调整着⾊器
参数2: 模型4*4矩阵
参数3: 颜⾊值
参数4: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,
                                 GLfloat mvMatrix[16],
                                 GLfloat vColor[4],
                                 GLint nTextureUnit);
使⽤场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。这种着⾊器通过给定的模型视图投影矩阵。着⾊器将⼀个基本⾊乘以⼀个取⾃纹理单元nTextureUnit 的纹理,将颜⾊与纹理进⾏颜⾊混合后才填充到⽚段中。

纹理光源着⾊器

参数1: 存储着⾊器种类-纹理光源着⾊器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源位置
参数5: 颜⾊值
参数6: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,
                                 GLfloat mvMatrix[16],
                                 GLfloat pMatrix[16],
                                 GLfloat vLightPos[3],
                                 GLfloat vBaseColor[4],
                                 GLint nTextureUnit);
使⽤用场景:在绘制图形时, 可以应⽤变换(模型/投影变化)。这种着⾊器通过给定的模型视图投影矩阵,着⾊器将⼀个纹理通过漫反射照明计算进⾏调整(相乘)。

你可能感兴趣的:(iOS图形渲染流程图解析(硬件、软件、OpenGL))