屏幕渲染原理及优化方式
2021-07-28 11:18:49 16 举报
AI智能生成
屏幕渲染原理及优化方式
作者其他创作
大纲/内容
屏幕渲染原理
时钟信号
水平同步信号HSync
垂直同步信号VSync
CPU
计算视图frame,图片编码,绘制纹理交给CPU
GPU
纹理混合,顶点变化,渲染到帧缓冲区
iOS 设备双缓冲机制
前帧缓冲区
后帧缓冲区
弊端
图像撕裂
原因
当视频控制器还未读取完成时,GPU将新的一帧内容提交到帧缓冲区并把两个缓冲区进行交换后,视频控制器就会把新的一帧数据的下半段显示到屏幕上,造成画面撕裂现象.
解决方案:垂直同步
GPU会等待显示器的VSync信号发出后,才进行新的一帧渲染和缓冲区更新.能解决画面撕裂现象,也增加了画面流畅度,但需要消耗更多的计算资源,由此可能导致卡顿.
卡顿
渲染
离屏渲染
CPU渲染
非GPU缓冲区渲染
触发情况
CoreGraphics的CGContext绘制
drawRect绘制
Layer圆角,边框,阴影,抗锯齿,渐变,光栅化(shouldRasterize为YES)
光栅化: 隐式创建一个位图,各种阴影遮罩等效果也会保存到位图中缓存起来,从而减少渲染的频度,把GPU的操作转到CPU上,生成位图缓存,直接读取调用.(注:对于经常变动的内容,不要开启光栅化,防止性能浪费,如cell的复用)
弊端:离屏渲染会单独在内存中创建一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的.
instuments的CoreAnimation工具实时监测->Debug Options
color Offscreen-Rendered
Yellow:开启后会把那些需要离屏渲染的图层高亮成黄色,黄色图层可能存在性能问题.
Color Hits Green and Misses
Red:若shouldRasterize设置为YES,对应的渲染结果会缓存,如果图层是绿色,表示缓存被复用;如果是红色,就表示缓存会被重复创建,可能存在性能问题.
GPU缓冲区渲染
优势:为图像显示做了高度优化,速度较快
instruments工具监测
Time Profiler->Call Tree Options
Separate By THread
按线程划分
Invert Call Tree
逆向Call Tree, 方便查看调用顺序
Hide System Libraries
隐藏系统库
Core Animation->Debug Options
Color Blended layers
监测图层混合情况,没有混合的部分为绿色,混合最严重的部分为红色,大量图层混合会消耗GPU的时间
Color Copied images
监测图片颜色格式,如果GPU不支持当前图片的颜色格式,会将其交给CPU预先进行格式转化,并且这张图片被标记为蓝色.(Apple的GPU值解析32bit的颜色格式,RGBA)
Color immediately
设置调试颜色每帧更新(一般不用)
Color Compositing-Fast-Path Blue
对任何直接使用OpenGL绘制的图层高亮
Flash Updated Regions
对重绘的内容高亮成黄色(软件层面使用Core Graphics 绘制的图层)
Color Hits Green and Misses Red
前面以述
Color Offscreen-Renderded Yellow
前面以述
Color Non-Standard Surface Formats
Apple 开发文档没注释(一般不用)
AsyncDisplayKit开源框架
简介
为使iOS界面刘畅,性能极致优化.FaceBook创建并开源了AsyncDisplayKit库.
基本原理
将文本和布局的计算、渲染、解码、绘制都通过各种方式异步进行,尽量优化UIKit及Core Animation 必须在主线程执行的相关操作.
分析:沿用UIView->CALayer方式,实现了ASDislayNode->UIView的映射关系. ASDisplayNode是线程安全的,它可以在后台线程创建和修改.Node刚创建时,并不会在内部新建UIView和CALayer,直到第一次在主线程访问view或layer属性时,它才会在内部生成对应的对象.当它的属性(比如frame/transform)改变后,它并不会立即同步到其持有的view或layer去,而是把被改变的属性保存到内部的一个中间变量,稍后在需要时,再通过某一个机制一次性设置到内部的view或layer.
图层预合成
分析:有时一个layer会包含很多sub-layer,而这些sub-layer并不需要响应触摸事件,也不需要进行动画和位置调整.ASDK为此实现了一个被称为pre-composing的技术,可以把这些subkayer合成渲染为一张图片.当ASNode替代UIView和CALayer后,设置layer backed后,ASNode甚至可以通过预合成来避免创建内部的UIView和CALayer.
优势:通过这种方式,把一个大的层级,通过一个大的绘制方法绘制到一张图上,性能会获得很大提升,CPU避免创建UIKit对象的资源消耗,GPU避免了多张texture合成和渲染的消耗,更少的bitmap也意味着更少的内存占用.
异步并发
ASDK把布局计算、文本排版、图片/文本/图形渲染等操作都封装成较小的任务,并利用GCD异步并发执行.使用ASNode相关的控件,那么这些并发操作会自动在后台执行,无需进行过多配置.
Runloop任务分发
分析:所有针对ASNode的修改和提交,总有些任务需放到主线程执行.当出现这种任务时,ASNode会把任务用ASAsyncTransaction (Group)封装并提交到一个全局的内容中去.ASDK在主线程runloop中注册了一个observer,监视BeforeWaiting和Exit事件,在runloop进入休眠前CoreAnimation处理完事件后,ASDK就会执行该loop内提交的所有任务.
滑动列表的预加载
解决方案
对象创建
分析:对象的创建会分配内存、调整属性、甚至还有读取文件等操作,比较消耗CPU资源.尽量采取轻量对象,尽量放到后台线程处理,尽量推迟对象创建时间.(UIView/CALayer)
对象调整
分析:frame、bounds、fransform及视图层次等属性调整很耗费CPU资源.尽量减少不必要属性的修改,尽量避免调整视图层次、添加和移除视图.
布局计算
分析:对属性的调整非常消耗资源,尽量提前算好布局,在需要时一次性调整好对应属性.
Autolayout
分析:随着视图数量的增长,Autolayout带来的CPU消耗会呈指数级上升.推荐视同AsyncDisplayKit、Masonry等第三方框架.
文本渲染
分析:屏幕上能看到的所有文本内容控件,包括UIWebView,底层都是通过CoreText排版、绘制为位图显示的.常见的文本控件,其排版与绘制都是在主线程进行的,显示大量使CPU压力很大.对此解决方案唯一就是自定义文本控件,用CoreText对文本异步绘制.(很麻烦,开发成本高)
图片解码
分析:当用UIImage或CGImageSource创建图片时,图片数据并不会立刻解码.图片设置到UIImageView或CALayer.Contents中去,并且CALayer被提交到GPU前,CGImage中的数据才会得到解码.这一步是发生在主线程的,然后从Bitmap直接创建图片.
图像绘制
分析:图像的绘制通常是指用那些以C开头的方法把图像绘制到画布中,然后从画布创建图片并显示的一个过程.CoreGraphics方法通常是线程安全的,可以异步绘制,主线程回调.
纹理渲染
分析:尽量减少短时间内大量图片的显示,尽可能将多张图片合成一张进行显示.
视图混合
分析:尽量减少视图层次和数量,并在不透明的视图里标明opaque属性以避免无用的Alpha通道合成.
图形生成
分析:尽量避免离屏渲染,尽量采用异步绘制,尽量避免使用圆角、阴影、遮罩等属性.必要时用静态图片实现展示效果,也可尝试光栅化缓存复用属性.CALayer属性shouldRasterize设置为YES.
性能优化方案
预加载
无限滚动列表
无限滚动列表并不能算是一种预加载的实现原理,它只是提供一种分页显示的方法,在每次滚动到UITableView底部时,才会开始发起网络请求向服务器获取对应的资源。
threshold
使用 Threshold 进行预加载是一种最为常见的预加载方式,知乎客户端就使用了这种方式预加载条目,而其原理也非常简单,根据当前UITableView的所在位置,除以目前整个UITableView.contentView的高度,来判断当前是否需要发起网络请求:
惰性加载
惰性加载,就是在用户滚动的时候会对用户滚动结束的区域进行计算,只加载目标区域中的资源。
用户在飞速滚动中会看到巨多的空白条目,因为用户并不想阅读这些条目,所以,我们并不需要真正去加载这些内容,只需要在ASTableView/ASCollectionView中只根据用户滚动的目标区域惰性加载资源。
惰性加载的方式不仅仅减少了网络请求的冗余资源,同时也减少了渲染视图、数据绑定的耗时。
智能预加载
可以点击前方链接进行自行查看
异步绘制
可以点击前方链接进行自行查看
全局并发控制
可以点击前方链接进行自行查看
0 条评论
下一页