对应一个客户端开发来说,平时做的的最多的就是写页面,所以有必要了解从视图代码到图像显示到屏幕上的整个过程和原理。
下面以从视图代码到显示器图像的中间产物帧缓冲区图像位图为目标,分析从视图代码到帧缓冲区位图和从帧缓冲区位图到显示器图像这2个过程。 这里把这2个过程命名为:帧缓冲区数据怎么来的、帧缓冲区数据怎么用的。
帧数据怎么来的
帧数据产生主要分为2个阶段:把视图布局代码生成图像3D数据模型、把图像3D数据模型转成位图。
把视图布局代码生成图像3D数据模型
CPU创建视图对象,计算布局,生成图像3D数据模型,并将这个图像3D数据模型交给GPU图像处理器将它加工成页面展示的位图。
把图像3D数据模型转成位图
根据GPU的渲染流水线把这个步骤可分为六个步骤
第一步骤:顶点着色器(Vertex Shader)
GPU收到图像3D数据模型后,首先通过顶点着色器将3D图像模型计算成屏幕上展示的2D图像模型,并对顶点数据做一些处理。
第二步骤:形状装配(Shape Assembly),又称 图元装配
然后使用图元装配器将这些2D Vertex转成基本的图元信息,图元指屏幕中图像的基本表示单位(点,线,三角形)。
第三步骤:几何着色器(Geometry Shader)
然后将这些图元元素数组传递给几何着色器,由几何着色器根据图像效果生成更细微的图元信息,来表现图像效果。
第四步骤:光栅化(Rasterization)
然后使用光栅化将达到展示效果的图元信息转换成一系列的像素。转换成像素的规则是以三角形图元覆盖在屏幕像素图层上,按照每个像素中心是否在图元三角形的内层,在内侧的都被选中的成为图像像素,根据像素生成片段模型,每个片段模型存储了一个像素渲染所需要的所有信息。
第五步骤:片段着色器(Fragment Shader)
然后将这些片段数据传递给片段着色器,片段着色器会计算每个像素所在的坐标是否超出了屏幕展示之外,对于屏幕之外的像素直接剪裁掉,只留下对展示有用的片段,提示渲染效率。
第六步骤:测试与混合(Tests and Blending)
测试与混合,在一个UI页面中用两套对应关系的树,一个是视图树,一个图层树。对应稍微复杂一点的视图如:按钮,它里面可以设置背景色,标题,这两种属性在显示时是有上下级关系的。而GPU在往帧缓冲区通过画家算法做深度优先遍历不断绘制图形时,是以与视图树对应的图层树中的图层为单位的,所以再将图层绘制到帧缓冲区之前要把图层内的多层属性进行测试与混合。
测试与混合阶段的操作内容是根据每个像素片段的深度和alpha值进行计算,像素深度Z在上面的显示,下面的忽略。像素alpha值小于1的则会对应上下两个深度的像素进行混合计算,得出要展示的像素效果。
经过这2个阶段,GPU得到了整棵图层树的位图,为后面往帧缓冲区做画家算法深度优先绘制提供了位图数据。
帧数据怎么用的
帧缓冲区中数据的使用对应的就是屏幕图像显示原理了,屏幕图像显示的原理是和CRT 显示器原理一样的。
CRT 显示器原理
CRT电子枪从上到下进行逐行扫描,当一行像素扫描完后电子枪换行到下一行等待显示器时钟发送水平同步信号HSync,等收到HSync信号后开始扫描,扫描完成后换行到下一个行,继续等待水平同步信号。当一帧页面显示完成后,扫描枪会回到屏幕开始的位置等待显示器时钟发送垂直同步信号VSync, 等收到垂直同步信号后先进行双帧缓冲区交互,然后通知CPU,GPU开始渲染下一帧数据,然后再开始新一轮的帧画面的扫描。HSync水平同步信号和VSync垂直同步信号是为了同步显示器的显示过程和系统视频控制器的读取过程的。
显示器以固定的频率进行刷新,这个固定频率就是VSync垂直同步信号的频率。
CPU,GPU,显示器协调工作模式
CPU通过视图创建,布局计算,文本渲染生成图像3D数据模型传给GPU。GPU将这些3D图像模型数据转成屏幕2D图像模型,然后经过GPU渲染流程生成位图放入帧缓冲区。视频控制器读取帧缓冲区的数据,通过数模转换显示到屏幕上。
双缓存机制
在屏幕图像显示机制中最简单的是使用一个帧缓冲区,但会有性能问题,显示器读完一帧位图后,GPU才能渲染下一帧位图数据往帧缓冲区里放。这里引入双缓冲区机制,GPU先往第一缓冲区中写入一帧位图,等县市区读取第一个缓冲区数据时,GPU开始渲染下一帧数据往第二缓冲区写入,等第一帧图像渲染完成,视频控制器会直接交互指针,将指针指向第二缓冲区,然后重复这一个过程。
图像撕裂问题
引入了双缓存区后,图像显示效率提升了,但是又带来了一个新问题:图像撕裂。
当视频控制器读取到第一个帧缓冲区数据一半时,此时GPU写入第二帧缓冲区位图数据结束,并进行了缓冲区指针交互。此时屏幕的下半部分就显示的第二帧的图片,造成了图像上下部分不一致。为了解决这个问题,采用了时钟垂直信号机制,当视频控制器完成一帧扫描后回到初始位置,此时要等待VSync垂直信号,只有收到VSyn信号后,才会进行帧缓冲区指针的交互,然后开始显示下一帧数据同时GPU开始渲染后面一帧的位图数据。
参考文章:
http://chuquan.me/2018/08/26/graphics-rending-principle-gpu/
https://www.jianshu.com/p/5bf1f9bbe233
https://juejin.cn/post/7114236347539259428#heading-20