什么时候视图(或图层)需要离屏渲染?

你好
本周末我开始观看2011年的WWDCvideo。 我发现了关于iOS的非常有趣的话题。 我最喜欢的是关于性能和graphics,但我发现其中两个显然是相互矛盾的。 当然,有一些我没有得到。 我所说的会话是理解UIKit渲染-121和抛光你的应用程序-105。
不幸的是,2011年的示例代码仍然无法下载,所以很难有一个全面的看法。 在一个会话中,他们解释说,在滚动视图中的可视化过程中,应避免大部分离屏渲染。他们修复了示例代码中的性能问题,几乎在-drawRect方法中绘制了所有内容。 在另一个会话中,性能问题(在表视图上)似乎是由于表单元的-drawRect方法中的代码太多。
首先我不清楚当系统需要离屏渲染时,我在video中看到一些石英函数,如:cornerRadious,shadowOffset,shadowColor需要它,但确实存在一个通用规则?
其次,我不知道我是否理解得很好,但似乎在没有离线渲染的情况下,添加图层或视图是最好的select。 我希望有人能够提出这个问题..
谢谢,
安德里亚

我不认为在任何地方都有规定,但希望这有助于:

首先,我们来澄清一些定义。 我认为屏幕外渲染并不是绝大多数时候的首要问题,因为屏幕外渲染可以像屏幕一样快。 主要问题是渲染是用硬件还是软件完成的。

使用图层和视图之间的实际区别也很小。 视图仅仅是CALayer的一个简单的包装,大部分时间它们不会引入显着的性能损失。 如果你想拥有由CAShapeLayer或CATileLayer等支持的视图,可以使用+ layerClass方法覆盖视图使用的图层types。

一般来说,在iOS上,像素效果和Quartz / Core Graphics绘图不是硬件加速的,大部分情况是。

下面的事情不是硬件加速,这意味着他们需要在软件(屏幕外)完成:

  1. 在drawRect中完成的任何事情。 如果你的视图有一个drawRect,即使是空的,绘图也不是用硬件完成的,性能会受到影响。

  2. shouldRasterize属性设置为YES的任何图层。

  3. 任何带有蒙版或阴影的图层。

  4. 文本(包括UILabels,CATextLayers,核心文本等)。

  5. 使用CGContext自己做的任何绘图(在屏幕上或离屏)。

大多数其他的东西都是硬件加速的,所以速度要快得多。 但是,这可能并不意味着你的想法。

与硬件加速绘图相比,上述任何绘图types都较慢,但是它们不一定会减慢您的应用程序,因为它们不需要每一帧都发生。 例如,第一次在视图上绘制阴影很慢,但在绘制之后会caching,并且只有在视图更改大小或形状时才会重绘。

对于具有自定义drawRect的光栅化视图或视图也是如此:视图通常不会在每一帧重绘,只绘制一次然后caching,因此视图之后的性能首次设置不会更糟,除非边界更改或你可以调用setNeedsDisplay。

为了获得良好的性能,诀窍是避免使用软件绘图来改变每一帧的视图。 例如,如果您需要animationvector形状,则使用CAShapeLayer或OpenGL比drawRect和Core Graphics可以获得更好的性能。 但是,如果你画一个形状,然后不需要改变它,它不会有太大的区别。

同样,不要在animation视图上放置阴影,因为它会减慢帧速率。 但是,一个不会逐帧改变的观点的阴影不会有太多的负面影响。

另一个需要注意的是放慢视图设置时间。 例如,假设您在所有文本上都有一个带有阴影的文本页面; 这将需要很长时间才能绘制出来,因为文本和阴影都需要用软件来渲染,但一旦绘制就会很快。 因此,您需要在加载应用程序时预先设置此视图,并将其副本保存在内存中,以便用户在屏幕上首次出现时不必等待视图显示的年龄。

这可能是WWDCvideo中明显矛盾的原因。 对于不改变每一帧的大的,复杂的视图,在软件中绘制一次(之后它们被caching并且不需要重绘)将比硬件在每一帧重新复合它们产生更好的性能,尽pipe第一次绘制会慢一些。

但对于必须不断重绘的视图,如表格单元格(单元格被循环使用,所以每当单元格在屏幕外滚动并重新使用时,它们必须重新绘制,因为它可以滚动到另一侧作为不同的行),软件绘图可能慢下来很多东西。

离线渲染是今天iOS渲染中定义最差的主题之一。 当苹果的UIKit工程师提到屏外渲染时,它具有非常明确的含义,大量的第三方iOS开发人员博客错了。

当你重写“drawRect:”时,你正在通过CPU绘图,并吐出一个位图。 位图被打包并发送到位于iOS(渲染服务器)中的独立进程。 理想情况下,渲染服务器只显示屏幕上的数据。

如果你在CALayer上捣鼓属性,就像打开阴影一样,GPU将执行额外的绘图。 这个额外的工作是UIKit工程师们说“离屏渲染”的意思。 这总是与硬件一起执行。

离屏绘图的问题不一定是绘图。 GPU切换其绘图目标时,屏幕外通道需要上下文切换。 在此切换期间,GPU处于空闲状态。

虽然我不知道触发屏幕外传递的属性的完整列表,但您可以使用Core Animation乐器的“颜色外屏渲染图层”切换进行诊断。 我假设除alpha之外的任何其他属性都是通过屏幕外传递执行的。

使用早期的iOS硬件,可以说“在drawRect中做所有事情”是合理的。 现在的GPU比较好,而UIKit的function就像shouldRasterize。 今天,这是在drawRect所花的时间,离屏通道的数量和混合的数量之间的平衡。 有关详细信息,请观看2014年WWDC会议419“iOS应用程序的高级graphics和animation”。

所有人都说,理解幕后的事情是很好的,并且把它放在脑后,所以你不要做任何疯狂的事情,但是你应该从最简单的解决scheme开始。 然后在您支持的最慢的硬件上进行testing。 如果你没有达到60FPS,使用仪器测量的东西,并找出它。 有几个可能的瓶颈,如果你不使用数据来诊断事情,你只是猜测。

离屏渲染/在CPU上渲染

graphics性能的最大瓶颈是屏幕外渲染和混合 – 它们可能发生在animation的每一帧,并可能导致不连贯的滚动。

离屏渲染(软件渲染)发生在需要在软件(屏幕外)进行绘图之前,可以将其交给GPU。 硬件不处理文本呈现和高级构图与面具和阴影。

以下将触发离屏渲染:

  • 任何带有掩码的图层( layer.mask

  • layer.masksToBounds / view.clipsToBounds为true的任何图层

  • layer.allowsGroupOpacity设置为YES且layer.opacity小于1.0的任何图层
    什么时候视图(或图层)需要离屏渲染?

  • 任何带有阴影的图层( layer.shadow* )。
    有关如何解决的提示: https : //markpospesel.wordpress.com/tag/performance/

  • layer.shouldRasterize为true的任何图层

  • 任何图层与layer.cornerRadiuslayer.edgeAntialiasingMasklayer.allowsEdgeAntialiasing

  • 任何与layer.borderWithlayer.borderColor
    缺less参考/certificate

  • 文本(任何types,包括UILabelCATextLayerCore Text等)。

  • drawRect:大部分绘图都使用CGContext 。 即使是一个空的实现将被渲染离屏。


这篇文章涵盖了混合和其他影响性能的事情: 什么触发iOS的离屏渲染,混合和layoutSubviews?