益阳住房和城乡建设局网站,广安建设企业网站,医院网站备案流程,昆山广告公司屏幕渲染原理现代计算机之父冯诺依曼提出了计算机的体系结构: 计算机由运算器#xff0c;存储器#xff0c;控制器#xff0c;输入设备和输出设备构成#xff0c;每部分各司其职#xff0c;它们之间通过控制信号进行交互。计算机发展到现在#xff0c;已经出…屏幕渲染原理现代计算机之父冯·诺依曼提出了计算机的体系结构: 计算机由运算器存储器控制器输入设备和输出设备构成每部分各司其职它们之间通过控制信号进行交互。计算机发展到现在已经出现了各种mini的智能设备比如手机就是典型的微型计算机其中控制器/存储器/运算器是我们看不到的但我们知道它是真实存在的比如内存8G/12G高通、麒麟等一些名词。其中手机的屏幕扮演了一个极其特殊的角色他可以触摸、滑动这证明了它是一个输入设备同时它又能呈现画面证明它又是一个输出设备所以对于手机来说屏幕即是输入又是输出。接下来就来追踪一下手机屏幕是怎么输出的。我们都知道计算机是基于二进制数据流来进行工作的而且又知道计算机五大组成部分是各司其职的其中屏幕就是专门来渲染图像的既然要显示图像肯定要有显示的数据这些数据从哪来呢答案就是cpu(这里为了方便把cpu、gpu、sf等统一称为cpu)这些数据由cpu提供cpu经过各种运算将数据写入一块内存中这块内存叫做帧缓冲我们可以将帧缓冲理解为一个M*N矩阵数据从上到下一行一行保存显示器在显示的时候从上到下逐行扫描依次显示在屏幕上我们把这样的一屏数据叫做一帧当一帧数据渲染完后就开始新一轮扫描如果CPU正好(不正好后面再说)也把下一帧数据写入帧缓冲那么就会显示下一帧画面如此循环我们就看到了不断变化的画面也就是图像。这个过程很简单但是实现起来却很难具体有两点:1 屏幕需要在16.7毫秒内绘制完一帧因为根据研究16.7ms正符合人类能觉察到卡顿的分割点如果低于16.7ms则可能感觉卡顿高于16.7ms则没必要。2 CPU需要在屏幕渲染完毕后正好把下一帧数据写入帧缓冲。如果早了那么屏幕上就会绘制一半上一帧的数据一半下一帧的数据。比如:绘制到第一帧的a行时cpu把下一帧数据送进来了屏幕会接着从a1行接着绘制这样导致前a行是第一帧的数据后面几行是第二帧的数据在我们看来就是两张图片撕开各取一部分拼起来这叫做撕裂。如果晚了那么屏幕会在下一次继续绘制上一帧导致画面没有变化这样就会出现画面不变的情况在我们看起来就是卡了也叫做卡顿。所以CPU和屏幕的这个交互时机很重要。这就跟我们抄作文一样们从上到下从左到右一行一行的挪移到另一张纸上当我们抄完一页就翻到下一页继续抄聪明的人抄的时候会看看不会抄名字、性别、父母信息啥的但是屏幕很傻给什么抄什么往死里抄不带思考的那种甚至在抄第一页的过程中你给他偷偷翻个页他还接着往下抄造成不连贯的后果屏幕不管这个都说了各司其职它的职就是抄至于抄的不对就是因为你翻页了在计算机体系中能翻页的就是cpu那最终就会怪罪于cpu控制不力所以屏幕和cpu的协调沟通就极其重要。我们来看两个概念:屏幕刷新率(Hz): 屏幕在一秒内刷新的次数Android手机一般都是60Hz也就是一秒刷新60次当然也有高刷的但是60Hz足矣。帧速率(FPS): cpu在一秒内合成的帧数比如60FPS就是60 frame per sconds意思就是一秒合成60帧。如上所述当屏幕刷新率大于帧速率的时候会发生卡顿屏幕刷新率小于帧速率的时候会发生撕裂。那么怎么解决这个问题呢我们一个一个来解决先来看撕裂。解决撕裂问题(VSYNC)我们知道撕裂是因为: cpu太快 从而导致 屏幕还没渲染完毕 就把正在渲染的数据 给覆盖掉了那么我们可以限制cpu的速度吗当然可以但是不划算因为这样就等于把cpu的长处给扼杀了所以我们只要让cpu的数据不覆盖掉屏幕正在渲染的数据即可也就是说给cpu新来的数据提供一个存放点而不是往帧缓冲里面写这个存放点叫做后缓冲(BackBuffer)相应的帧缓冲(FrameBuffer)也叫做前缓冲这样cpu新来的数据就会放在后缓冲而屏幕则继续从前缓冲取数据来渲染等到后缓冲数据写入完了前后缓冲的数据就会交换屏幕此时读取的数据就是后缓冲的数据也就是下一帧的数据循环往复我们就看到了画面。但是还是不行举个列子如果cpu非常快前缓冲数据还没刷新完毕后缓冲已经写满此时就会交换数据又发生了撕裂那么怎么办呢 从图中可以看到: 没有vsync的情况下cpu在任意地方开始随心所欲!我们追究原因: 核心点在与数据交换的时机由谁来控制数据交换的发生点应该是在屏幕渲染完一帧后而不是cpu写入一帧数据后所以控制数据是否交换应该由屏幕来决定但是计算机五大组成部分各司其职屏幕只是输出设备和输入设备(因为能触屏)他不是控制器如何控制数据的交换呢当然可以答案就是:VSYNC。VSYNC(vertical sync): 也就是垂直同步当屏幕渲染完一帧数据后即将开始渲染下一帧之前发出的一个同步信号。cpu只要监听VSYNC信号接收到信号后再开始交换后缓冲和前缓冲的数据就等价于屏幕控制了数据交换也就解决了撕裂问题这很明显是设计模式中的监听器模式。现在我们来捋一下流程:1 屏幕正在从前缓冲读取第一帧数据并渲染此时cpu计算完第二帧数据放在后缓冲等待VSYNC信号。2 屏幕将第一帧数据渲染完毕发出VSYNC信号cpu收到VSYNC信号将后缓冲的第二帧数据复制到前缓冲。3 同时屏幕继续绘制第二帧数据cpu开始计算下一帧数据循环往复。从图中可以看到有了VSYNCcpu总是在指定的地方开始。有人会问: 说白了真正解决问题的是VSYNC而不是双缓冲那不要双缓冲只要VSYNC不是也可以吗好我们假设只有VSYNC现在假设屏幕正在渲染数据而cpu在等VSYNC信号屏幕将数据渲染完毕后发送VSYNC信号cpu收到信号后就去计算数据计算完后才会写入帧缓冲那么在cpu计算数据这段时间内屏幕干什么呢嗯它接着刷新帧缓冲的数据反正cpu还没有将新数据计算完毕刷入帧缓冲所以还是上一帧的数据这样就会卡顿说白了有双缓冲的情况下cpu使用后缓冲计算数据屏幕使用前缓冲渲染数据两者可以同时工作你计算一个我渲染一个典型的生产者消费者模式只不过使用VSYNC信号来进行数据的交换而没有双缓冲的情况下两者需要排队使用帧缓冲不能同时工作就变成了我等着你计算你计算完了等着我渲染VSYNC此时的作用就是进行排队这样会大大增加卡顿率所以: VSYNC真正解决了撕裂问题而双缓冲优化了卡顿问题。那么怎么解决卡顿问题呢答曰: 无法根本解决只能优化!优化卡顿问题(多缓冲)我们知道卡顿是因为帧速率屏幕刷新率这是不严谨的准确的说应该是因为:帧速率60fps因为现在屏幕刷新率基本都是60hz的所以帧速率只要取下限60fps即可换句话说1秒内需要计算60个帧也就是16.7ms就能计算完一帧。如果计算不完那么在一个vsync信号过来后cpu还在计算缓冲区的数据并没有改变就还是老数据屏幕就又把老数据刷新一遍就出现了卡顿所以cpu要尽可能在16.7ms内把所有数据计算完准备好以等待vsync信号过来后直接交换数据。我们又知道双缓冲只是优化了卡顿问题并没有根本解决卡顿问题为何呢我们先来大致说明一下Android的屏幕绘制流程:1 任何一个View都是依附于window的2 一个window对应一个surface3 view的measure、layout、draw等均是计算数据这些是cpu干的事4 cpu把这些事干好后在经过一系列计算将数据转交给gpu5 gpu将数据栅格化后就交给SurfeceFlinger(以下简称SF)6 SF将多个surfece数据合并处理后就放入后缓冲区7 屏幕以固定频率从前缓冲区拿出数据渲染渲染完毕后发送VSYNC此时前后缓冲区数据交换屏幕绘制下一帧上述7步是建立在开启硬件加速的情况下的如果没有硬件加速就去掉gpu部分就可以简单理解为cpu直接将数据转交给sf我们简单整理一下数据的传递流程: cpu - gpu - display而且我们看到cpu和gpu是排队工作的它俩和屏幕是并行工作的。好我们来看发生卡顿(jank)的场景:我们可以将Display那一行看作是前缓冲将GPU和CPU两行叠加起来看作是后缓冲(因为它俩排队使用)将VSYNC线隔离开的竖行看作一个帧。我们看到在第一帧里面GPU墨迹了半天没搞完以至于在第二帧里面Display(屏幕)显示的还是第一帧的A数据此时就产生了Jank(卡顿)并且在一个vsync信号过来后cpu什么都没做因为gpu占着后缓冲(那个绿色的长B块)所以cpu只能再等下一个vsync在下一个vsync里面cpu终于拿到了后缓冲的使用权但是cpu计算时间比较长导致了gpu时间不够用数据又没算完再次发生了卡顿可以说这次卡顿直接受到了第一次卡顿的影响试想: 如果在第一次卡顿的时候cpu也能计算数据那么第二次卡顿可能就不存在了因为cpu已经在第一次卡顿的时候把蓝色的A给计算完了第二次完全可以让gpu独自计算(绿色的A)就不存在因为排队导致的时间不够用了但是cpu和gpu共用后缓冲这就导致它们只能轮流使用后缓冲怎么解决呢再加一个后缓冲区让cpu、gpu各用一块。我们来看引入三缓冲后的效果:我们看到在第一次jank内cpu使用了第三块缓冲区自己计算了C帧的数据假如此时没有三缓冲那么cpu就只能再继续等下一个vsync信号也就是在图中蓝色A块的地方才能开始计算C帧数据就又引发下一次卡顿。我们看到通过引入三缓冲虽然不能避免卡顿问题但是却可以大幅优化卡顿问题尤其是避免连续卡顿但是三缓冲也有缺点就是耗资源所以系统并非一直开启三缓冲要想真正解决问题还需要在cpu层对数据尽量优化从而减小cpu和gpu的计算量比如:View尽量扁平化少嵌套少在UI线程做耗时操作等。Tips:Android 3.0引入了硬件加速(GPU)。Android 4.0默认开启了硬件加速。Android 4.1引入了黄油计划(VSYNC)上层开始接收VSYNC(Choreographer)并且加入了三缓冲.VSYNC不仅控制了后缓冲和前缓冲的数据交换还控制了cpu何时开始进行绘制计算。- END -