视图(或图层)何时需要离屏渲染?

Posted

技术标签:

【中文标题】视图(或图层)何时需要离屏渲染?【英文标题】:When does a view (or layer) require offscreen rendering? 【发布时间】:2011-10-07 13:48:07 【问题描述】:

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

【问题讨论】:

能否添加视频链接? 没有直接链接。您应该是注册的开发人员。 link 当我看到视频时我也在想同样的事情,想知道当视图被拉出屏幕时是否有官方规定以及如何禁止它。 【参考方案1】:

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

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

使用图层和视图之间也几乎没有实际区别。视图只是 CALayer 的一个薄包装器,它们在大多数情况下不会引入显着的性能损失。如果你想要一个由 CAShapeLayer 或 CATileLayer 等支持的视图,你可以使用 +layerClass 方法覆盖视图使用的图层类型。

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

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

    在 drawRect 中完成的任何事情。如果您的视图有一个drawRect,即使是一个空的,绘图也不是在硬件中完成的,并且会降低性能。

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

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

    文本(任何类型,包括 UILabel、CATextLayers、Core Text 等)。

    您自己使用 CGContext 进行的任何绘图(屏幕上或屏幕外)。

大多数其他东西都是硬件加速的,所以它们要快得多。但是,这可能并不意味着您认为它确实如此。

与硬件加速绘图相比,上述任何类型的绘图都较慢,但它们不一定会降低您的应用程序的速度,因为它们不需要每帧都发生。例如,第一次在视图上绘制阴影很慢,但绘制后会被缓存,并且只有在视图改变大小或形状时才会重新绘制。

光栅化视图或带有自定义 drawRect 的视图也是如此:视图通常不会在每一帧都重绘,它会绘制一次然后缓存,因此首次设置视图后的性能不会更差,除非bounds 改变或者你调用 setNeedsDisplay 就可以了。

为了获得良好的性能,诀窍是避免使用软件绘图来绘制每一帧都会发生变化的视图。例如,如果您需要动画矢量形状,使用 CAShapeLayer 或 OpenGL 将获得比 drawRect 和 Core Graphics 更好的性能。但是如果你画了一个形状,然后就不需要改变它,它不会有太大的不同。

同样,不要在动画视图上放置阴影,因为它会降低帧速率。但是视图上的阴影不会因帧而异,不会产生太大的负面影响。

要注意的另一件事是减慢视图设置时间。例如,假设您有一页文本,所有文本都带有阴影;最初绘制需要很长时间,因为文本和阴影都需要在软件中呈现,但是一旦绘制它就会很快。因此,您需要在应用程序加载时提前设置此视图,并将其副本保存在内存中,这样用户就不必等待很长时间才能在视图首次出现在屏幕上时显示出来。

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

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

【讨论】:

好答案。赏金。谢谢。 shouldRasterize 的默认值为 NO。这是否意味着所有这些图层既不会在屏幕外绘制也不会被缓存? @devgr 不一定,不。出于上述某些原因,需要离屏渲染,例如动态阴影和遮罩。即使没有将shouldRasterize 设置为true,这也需要离屏渲染。此外,据我了解,内部层会尽可能缓存,尤其是在 iOS 7 引入实时模糊和其他视觉效果之后。 Core Animation 在可能的情况下积极缓存图层内容(可能是模糊的变体)。 shouldRasterize 只是强制层树在合成之前进行光栅化,这可能会或可能不会提高性能。【参考方案2】:

离屏渲染是当今 iOS 渲染中定义最差的主题之一。当 Apple 的 UIKit 工程师提到离屏渲染时,它有一个非常具体的含义,大量的第三方 iOS 开发者博客都搞错了。

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

如果您在 CALayer 上调整属性,例如打开阴影,GPU 将执行额外的绘图。这种额外的工作就是 UIKit 工程师所说的“离屏渲染”的意思。这始终使用硬件执行。

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

虽然我不知道触发离屏传递的属性的完整列表,但您可以使用 Core Animation Instrument 的“Color Offscreen-rendered layer”切换进行诊断。我假设除 alpha 之外的任何属性都是通过屏幕外传递执行的。

对于早期的 iO​​S 硬件,说“在 drawRect 中做所有事情”是合理的。现在 GPU 更好了,UIKit 有 shouldRasterize 之类的功能。今天,它是在 drawRect 中花费的时间、离屏通道数和混合量之间的平衡行为。有关完整的详细信息,请观看 2014 年 WWDC 会议 419,“iOS 应用程序的高级图形和动画”。

总而言之,最好了解幕后发生的事情,并将其放在脑后,这样您就不会做任何疯狂的事情,但您应该从最简单的解决方案开始。然后在您支持的最慢硬件上进行测试。如果您没有达到 60FPS,请使用 Instruments 来测量并找出答案。存在一些可能的瓶颈,如果您不使用数据来诊断问题,那么您只是在猜测。

【讨论】:

【参考方案3】:

离屏渲染/在 CPU 上渲染

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

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

以下将触发离屏渲染:

任何带有蒙版的图层 (layer.mask)

layer.masksToBounds / view.clipsToBounds 为真的任何层

layer.allowsGroupOpacity 设置为 YES 和 layer.opacity 的任何层小于 1.0When does a view (or layer) require offscreen rendering?

任何带有阴影的图层 (layer.shadow*)。 修复提示:https://markpospesel.wordpress.com/tag/performance/

layer.shouldRasterize 为真的任何层

任何带有layer.cornerRadiuslayer.edgeAntialiasingMasklayer.allowsEdgeAntialiasing的层

任何带有layer.borderWithlayer.borderColor 的层? 缺少参考/证明

文本(任何类型,包括UILabelCATextLayerCore Text 等)。

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


这篇文章涵盖了混合和其他影响性能的事情:What triggers offscreen rendering, blending and layoutSubviews in iOS?

【讨论】:

clipsToBounds/masksToBounds/cornerRadius 不再导致离屏渲染

以上是关于视图(或图层)何时需要离屏渲染?的主要内容,如果未能解决你的问题,请参考以下文章

离屏渲染,OpenGL的三种渲染方式

iOS离屏渲染

离屏渲染(图层性能 15.2)

GPU性能:光栅化图层混合离屏渲染

离屏渲染优化

什么是离屏渲染?什么情况下会触发?该如何应对?