Android Skia
iOS CoreGraphics
Windows GDI/DX3D/DX2D
Linux Cario
AGG
等等都是大家常用的渲染器(Path Render, 这里的渲染器特指最终会通过算法做像素染色. 而不是不是Web前端提到的渲染
, 两者之间存在着本质的差异),这些渲染器把程序提交的渲染Command(例如:DrawLine DrawArcTo..)最后转化成了光栅图,然后提交给硬件上屏就OK了.
那么实际上就是生成一张位图而已?
可以这么理解, 操作系统或者程序就是不停的构建当前界面的位图,在另一篇里面我介绍了硬件加速构建UI的原理.
1. 打印机-曾经的显示器
计算机刚刚出现的时候没有好用的输出设备,最常用的是打印机
,对的你没有听错。打印机是曾经的显示设备,每次程序运行结束后会通过打印机把结果打印出来。用过打印机的同学可能没有注意到一个事实:打印机是独占设备(所谓独占设备指的是在同一个时刻只能由一个程序持有该设备,其他程序只能等待直到能够获取到)。
后面终于可以用显示器来实时显示计算的绘图结果了,极大解决显示的成本。但是在早期的显示系统架构下显示器也是独占设备(和打印机一样),也就是一个时刻只能由一个程序往显示器输出结果(是不是很傻@@@!)。随着操作系统的发展,尤其是分时多任务
(通过CPU切割时间片来实现的多任务,也就是多线程的技术)系统的发展。需要多个程序同时往屏幕输出图像(试想一下如果现在的显示器还是独占设计,那么你在用chrome上网的时候没有版本聊QQ了,写Office的时候也不能切换到网易云音乐听一段了),同时显示多个程序的输出可以极大的提升显示器的利用率,也能极大的提升用户的使用效率。
2. 如何让多个程序同时绘制到屏幕上去
所以上面已经阐述了,对于硬件驱动测我们能做的就是提交给他那张渲染好的位图,基本这个方式动不了。所以我们在操作系统测这边动动奶子~ 额 脑子哦!
首先从操作系统测接管了对显示设备的控制,也就是显示器交给了操作系统独占,当然这个时候有其他程序需要独占显示器有不太可能(现在也提供了独占的方式,主要提供给游戏使用。独占的好处是可以更快速的和硬件通讯,数据可以快速发送到屏幕上面并显示给用户)。
当程序需要向屏幕绘制内容的时候,首先向系统申请一个窗口
然后系统会给这个窗口
分配一块RAM存储空间(可以是内存也可以是显存),这个存储空间可以看做是一个RGBA的二维数组(也就是一张位图)。这样程序只要把绘制的内容绘制到这块存储空间上面去就好。那么当有多个程序(进程)同时需要绘制的话,那么系统这个时候其实就已经分配了多个窗口
。那么操作系统只要定时统计所有窗口
的位图,然后按照窗口
的上下层叠顺序通过AlphaBlend
合并在一张位图上,然后操作系统把这张合成后的位图提交给显示器显示就好了。
3. 双缓冲和三缓冲
上面多窗口
的架构确实能解决多进程渲染到屏幕的问题,通过系统定时合并
多窗口分别渲染
的方式解决。就按Android系统来说,这个窗口
就叫做Surface
而合并Surface
的系统程序就叫做SurfaceFlinger
。其他的操作系统以此类推。
但是存在一个问题:多窗口
的RAM数据空间在被系统合并的时候,对应渲染的程序不能操作这块RAM数据(你想啊,如果系统正在把当前这帧合并到屏幕上去,合并不是瞬时完成的啊,需要一定的时间啊。你的程序恰好在这个时间也在操作这帧的数据就会出现上下两帧错位的情况)。这样影响了软件渲染的性能,毕竟不能真正的并行处理。当系统在合并上屏的时候,程序如果需要绘制只能等待了,那么如何解决这个问题?
答案:程序在系统申请窗口
系统可以分配2块一模一样的RAM空间,每块RAM存储空间都可以独立存储
程序渲染的位图。一块位图叫做前景图
另一块叫后景图
。程序每次只能绘制到前景图
,当程序绘制完当前这帧的时候就会通知系统交换前后景图
(系统内核只是交换了一下指针,成本非常低)。操作系统定期把后景图
合并上屏幕,通过这种双缓冲
的方式就可以让系统合并上屏
和软件绘制
并行处理,互相之间基本不影响。
总结:系统自己持有了一张用来合并结果的位图,每个程序在分配窗口
的时候其实有2张位图数据空间。这样整个渲染系统基本上是由3张位图数据共同作用。单纯从软件测来说叫双缓冲
。整个架构体系又叫做三缓冲
。
4. 多缓冲在操作系统的各种使用场景
操作系统利用多缓冲的方式把显示设备
从独占设备
改变到了共享设备
。让多个进程可以同时渲染到显示器上面,大大增强了显示器这种外接设备使用效率。那么这类技巧还用在哪里?
答案: 硬盘,声卡,网卡 等等都采用了类似的方案。
比如声卡:传统声卡早期只支持一路声音数据的播发,也就是同一时刻只能播发一个程序的一个声音(大白话)。现在的显卡已经支持有效多路
(比如声卡的接口支持同时输入3路声音的数据)。但是有的时候我们的系统采用还是多缓冲
的方式来解决这个问题。每个程序当需要播发声音的时候,就把声音的数据(PCM编码的声音数据)提交给系统。系统利用混音算法
(颜色用的Alpha融合,声音用的是混合算法)把多路混合成一路。得到这一路的数据后再丢给声卡播发就好了(这类算法只要CPU的运算性能足够,理论可以同时播发任意路。当你在看电影顺带聊着QQ,系统时不时还给点提醒声音等等,就都可以同时播发了)。
那还有一点需要讨论,屏幕在接受到系统的显示位图后,是如何显示到屏幕的?
5. 屏幕刷新和VSYNC垂直同步型号
屏幕也是采用扫描线的算法来实现对屏幕显示像素的刷新。比如常见的横向扫描屏幕,屏幕就按照位图的像素的数据从左到右,从上到下依次设置屏幕颜色的亮度。每一帧从第一个像素处理完到最后一个像素处理完成成为一帧刷新
。那么刷新一帧需要多少时间?这个从显示器出厂就定死了。比如常规的显示器都是60HZ
刷新率的(也就是一秒可以刷新60张),也有用于游戏的80HZ
和144H
Z的屏幕。
按照60HZ
的刷新频率来说,一帧数据从第一个像素到最后一个像素需要 1000ms/60 = 16ms
的时间。如果屏幕刷新到一半的时候,系统提交了新的一帧数据。那么就会出现当前屏幕显示的,已经刷新的一半内容是上一帧的,后面的部分绘制下一帧的数据,这样的现象被叫做帧撕裂
,甚至会出现屏幕闪烁。
那么系统如何在屏幕一帧完全刷新完成后才提交下一帧的数据?这就要说到垂直同步
了。显示器在刷新完一帧的时候回向系统提交一个叫VSYNC
的信号,系统受到这个硬件信号后才提交数据。同样操作系统也模拟了类似这个信号功能的软信号
,用来告知软件渲染算法,减少不必要的多余的渲染(比如屏幕只有60HZ,那么我的软件性能很好每秒可以渲染120帧,那么多出来的60帧就被丢弃了,这样就导致了性能的浪费)。
6. 运动模糊
最后: 我们来探讨下运动模糊具体是什么?不知道大家关注过这个问题么?电视机的28HZ大家就觉得很流畅,但是游戏60HZ了还是觉得有卡顿。这个问题主要原因就是存在于 运动模糊
的原因。电视机的界面基本全是靠摄像机拍摄的结果,大家可以挨帧分析下摄像机拍摄的影片。你会发现其中有很多的帧是模拟
的。这种运动模糊
是由于摄像机的CCD芯片
需要曝光时间导致的。也正是这种现象,让人脑在看到这类视频的时候回觉得非常流畅。但是游戏的每一帧都是程序生成的,每一帧都是精确
的不存在这种运动模糊效果。所以游戏即使刷新频率到60HZ大家也觉得没有电视来的流畅。目前有些游戏通过渲染前后2帧的插值来模拟这种运动模糊,当游戏里面有大场景的转动的时候效果会比传统游戏更加流畅(当然大家都在60HZ满帧渲染的情况下的)。
总结下: 额~ 没啥总结的,那就这样吧!
</br></br>
版权所有,如有转载请联系我本人http://www.breakerror.com/archives/68-i.html