ios-视图(或图层)何时需要屏幕外渲染?

你好
这个周末,我开始观看2011年WWDC视频。 我发现了关于iOS的非常有趣的话题。 我最喜欢的是性能和图形,但是我发现其中两个显然是矛盾的。 当然,我没有得到一些东西。我正在谈论的会话是了解UIKit渲染-121和完善您的应用程序-105。
不幸的是,2011年的示例代码仍然无法下载,因此很难全面了解。在一个会话中,他们解释了在滚动视图等的可视化过程中通常应避免屏幕外渲染。他们修复了示例代码中的性能问题,几乎在-drawRect方法中绘制了所有内容。在另一个会话中,性能问题(在表视图上)似乎是由于表单元格的-drawRect方法中的代码过多所致。
首先我不清楚系统是否需要OffScreen渲染,我在视频中看到一些石英函数,例如:cornerRadious,shadowOffset,shadowColor需要它,但是是否存在一般规则?
其次,我不知道我是否理解得很好,但是似乎没有屏幕渲染时,添加图层或视图是必经之路。我希望有人能对此有所启发。
谢谢,
安德里亚

Andrea asked 2020-02-13T20:59:06Z
3个解决方案
139 votes

我认为任何地方都没有写下规则,但是希望这会有所帮助:

首先,让我们澄清一些定义。 我认为屏幕外渲染与屏幕上渲染在大多数时候并不是最重要的问题,因为屏幕外渲染的速度可以与屏幕上一样快。 主要问题是渲染是在硬件还是软件中完成的。

使用图层和视图之间的实用差异也很小。 视图只是围绕CALayer的一个薄薄的包装,它们在大多数情况下不会带来明显的性能损失。 如果要使视图由CAShapeLayer或CATileLayer等支持,则可以使用+ layerClass方法覆盖视图使用的图层类型。

通常,在iOS上,像素效果和Quartz / Core Graphics绘图不是硬件加速的,而其他大多数东西都是硬件加速的。

以下内容不是硬件加速的,这意味着它们需要在软件中完成(屏幕外):

  1. 在drawRect中完成的所有操作。 如果您的视图有一个drawRect,甚至是一个空的视图,那么绘图就不会在硬件中完成,并且会降低性能。

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

  3. 具有遮罩或阴影的任何图层。

  4. 文本(任何类型,包括UILabels,CATextLayers,Core Text等)。

  5. 您使用CGContext自己绘制的任何图形(屏幕上或屏幕外)。

大多数其他事情都是硬件加速的,因此它们要快得多。 但是,这可能并不意味着您认为的那样。

与硬件加速绘图相比,上述任何一种绘图方式都较慢,但是它们并不一定会使您的应用程序变慢,因为它们不需要在每一帧都发生。 例如,第一次在视图上绘制阴影很慢,但是在绘制后会对其进行缓存,并且仅在视图更改大小或形状时才重新绘制。

栅格化视图或具有自定义drawRect的视图也是如此:通常不会在每一帧都重新绘制视图,而是先绘制一次然后将其缓存,因此,除非边界发生变化或 您可以在其上调用setNeedsDisplay。

为了获得良好的性能,关键在于避免使用软件绘图来更改每帧的视图。 例如,如果您需要动画矢量形状,则使用CAShapeLayer或OpenGL将获得比drawRect和Core Graphics更好的性能。 但是,如果您绘制一次形状,然后无需更改它,则不会有太大变化。

同样,请勿在动画视图上放置阴影,因为这会降低帧速率。 但是,视图之间的阴影在帧之间不变时不会产生太多负面影响。

要注意的另一件事是减慢视图设置时间。 例如,假设您有一个文本页面,所有文本上都带有阴影。 由于文本和阴影都需要在软件中进行渲染,因此初始绘制将花费很长时间,但是一旦绘制,它将很快。 因此,您将需要在应用程序加载时预先设置此视图,并将其副本保存在内存中,以便用户不必等待年龄就可以在视图首次出现在屏幕上时显示该视图。

这可能是WWDC视频中明显矛盾的原因。 对于不会改变每一帧的大型复杂视图,在软件中对其进行一次绘制(之后将其缓存并不需要重绘)将比使硬件在每一帧中重新组合它们产生更好的性能。 第一次绘制会比较慢。

但是对于必须不断重绘的视图(例如表格单元)(单元被回收,因此每当一个单元滚动到屏幕外时必须重新绘制视图,并在滚动到另一侧作为另一行时重新使用它们),软件绘图可能会 减慢了很多速度。

Nick Lockwood answered 2020-02-13T21:00:34Z
25 votes

屏幕外渲染是当今iOS渲染中定义最差的主题之一。 当苹果公司的UIKit工程师提到屏幕外渲染时,它具有非常特殊的含义,并且大量的第三方iOS开发博客都将其弄错了。

当您覆盖“ drawRect:”时,您正在通过CPU进行绘制,并吐出一个位图。 将位图打包并发送到位于渲染服务器iOS中的单独进程。 理想情况下,渲染服务器仅在屏幕上显示数据。

如果您在CALayer上摆弄一些属性,例如打开阴影,GPU将执行其他绘制。 UIKit工程师在说“屏幕外渲染”时的意思是这项额外的工作。 始终使用硬件执行此操作。

屏幕外绘图的问题不一定是绘图。 屏幕外传递需要上下文切换,因为GPU会切换其绘制目标。 在此切换期间,GPU处于空闲状态。

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

使用早期的iOS硬件,可以说“在drawRect中执行所有操作”是合理的。 如今,GPU更好,UIKit具有诸如shouldRasterize之类的功能。 如今,这是在drawRect中花费的时间,屏幕外传递的次数和混合量之间的一种平衡行为。 有关详细信息,请观看2014 WWDC会议419,“ iOS应用程序的高级图形和动画”。

综上所述,最好了解幕后发生的事情,并将其隐藏在脑后,这样您就不会做任何疯狂的事情,但是您应该从最简单的解决方案开始。 然后在您支持的最慢的硬件上对其进行测试。 如果您未达到60FPS,请使用Instruments进行测量并弄清楚。 可能存在一些瓶颈,如果您不使用数据来诊断问题,那只是在猜测。

Ben Sandofsky answered 2020-02-13T21:01:24Z
11 votes

屏幕外渲染/在CPU上渲染

图形性能的最大瓶颈是屏幕外渲染和混合-它们可能发生在动画的每一帧中,并可能导致滚动不稳定。

屏幕外渲染(软件渲染)发生在需要在软件(屏幕外)中进行绘制才能将其移交给GPU之前。 硬件不处理带有遮罩和阴影的文本渲染和高级合成。

以下内容将触发屏幕外渲染:

  • 带有遮罩的任何层(CGContext

  • CGContext/drawRect:为真的任何层

  • CGContext设置为YES和drawRect:的任何层均小于1.0
    视图(或图层)何时需要屏幕外渲染?

  • 具有阴影的任何层(CGContext)。
    有关修复方法的提示:[https://markpospesel.wordpress.com/tag/performance/]

  • CGContext为真的任何层

  • 具有CGContextdrawRect:Core Text的任何层

  • 具有CGContextdrawRect:的任何层吗?
    缺少参考/证明

  • 文本(任何类型,包括CGContextdrawRect:Core Text等)。

  • 您使用drawRect:中的CGContext所做的大多数绘图。即使是空的实现也会在屏幕外呈现。


这篇文章涵盖了混合和其他影响性能的因素:是什么触发了iOS中的屏幕外渲染,混合和layoutSubviews?

hfossli answered 2020-02-13T21:02:55Z
translate from https://stackoverflow.com:/questions/6731545/when-does-a-view-or-layer-require-offscreen-rendering