您好本周末我开始观看2011年WWDC视频。我发现了关于iOS的非常有趣的话题。我的最爱是关于性能和图形,但我发现其中两个显然是矛盾的。当然有一些我没有得到的东西。
我正在谈论的会议是理解UIKit渲染-121和抛光你的应用程序-105。
不幸的是,2011年的示例代码仍然无法下载,因此很难获得整体视图。
在一个会话中,他们解释说,在scrollview等可视化期间,大多数时候应该避免屏幕外渲染。他们修复了示例代码中的性能问题,几乎在-drawRect方法中绘制了所有内容。
在另一个会话中,性能问题(在表视图上)似乎是由于表格单元格的-drawRect方法中的代码太多。
首先我不清楚当系统需要一个OffScreen渲染时,我在视频中看到一些石英功能如:cornerRadious,shadowOffset,shadowColor需要它,但确实存在一般规则?
其次我不知道我是否理解得很好,但似乎没有屏幕外渲染添加图层或视图是要走的路。
我希望有人可以为此带来光明。
谢谢,
安德烈
答案 0 :(得分:131)
我认为在任何地方都没有规定,但希望这会有所帮助:
首先,让我们澄清一些定义。我认为屏幕外渲染与屏幕渲染在大多数情况下都不是最重要的问题,因为屏幕外渲染可以像在屏幕上一样快。主要问题是渲染是在硬件还是软件中完成的。
使用图层和视图之间的实际差异也很小。视图只是CALayer的一个薄包装,它们在大多数情况下不会引入显着的性能损失。如果要使用CAShapeLayer或CATileLayer等支持视图,可以使用+ layerClass方法覆盖视图使用的图层类型。
通常,在iOS上,像素效果和Quartz / Core Graphics绘图不是硬件加速的,而且大多数其他东西都是。
以下内容不是硬件加速,这意味着它们需要在软件中完成(屏幕外):
在drawRect中完成的任何事情。如果你的视图有一个drawRect,即使是一个空的,那么绘图不是在硬件中完成的,并且会有性能损失。
将shouldRasterize属性设置为YES的任何图层。
任何带有蒙版或投影的图层。
文字(任何种类,包括UILabels,CATextLayers,核心文字等)。
使用CGContext自己(在屏幕上或屏幕外)进行的任何绘图。
大多数其他东西都是硬件加速的,所以它们要快得多。但是,这可能并不意味着你的想法。
与硬件加速绘图相比,上述任何类型的绘图都很慢,但它们不一定会降低您的应用程序速度,因为它们不需要每帧都发生。例如,第一次在视图上绘制投影时速度很慢,但在绘制后它会被缓存,并且只有在视图更改大小或形状时才会重绘。
对于使用自定义drawRect的光栅化视图或视图也是如此:视图通常不会每帧重绘,它被绘制一次然后缓存,因此首次设置视图后的性能并不差,除非边界改变或你在它上面调用setNeedsDisplay。
为了获得良好的性能,诀窍是避免使用软件绘制来改变每一帧的视图。例如,如果您需要动画矢量形状,使用CAShapeLayer或OpenGL比使用drawRect和Core Graphics获得更好的性能。但是如果你画一次形状然后不需要改变它,它就没有太大的区别。
同样,不要在动画视图上放置阴影,因为它会降低帧速率。但是视图上的阴影不会在帧与帧之间发生变化,不会产生太大的负面影响。
需要注意的另一件事是减慢视图设置时间。例如,假设您有一页文本,所有文本都有阴影;这将需要很长时间才能绘制,因为文本和阴影都需要在软件中渲染,但一旦绘制它将会很快。因此,您需要在应用程序加载时提前设置此视图,并将其保留在内存中,以便用户不必等待视图在屏幕上首次显示时显示。
这可能是WWDC视频中明显矛盾的原因。对于不改变每个帧的大型复杂视图,在软件中绘制一次(之后将它们缓存并且不需要重新绘制)将比使硬件每帧重新组合它们产生更好的性能,即使第一次画画会慢一些。
但是对于必须不断重绘的视图,例如表格单元格(单元格被回收,因此每当一个单元格在屏幕外滚动时必须重新绘制它们,并且当它作为不同的行向后滚动到另一侧时重新使用它们),软件绘图可能会减慢很多事情。
答案 1 :(得分:21)
Offscreen-rendering是今天iOS渲染中最糟糕的主题之一。当Apple的UIKit工程师参考屏幕外渲染时,它具有非常特殊的含义,并且大量的第三方iOS开发博客都错了。
当你覆盖“drawRect:”时,你正在通过CPU绘图,然后吐出一个位图。该位图被打包并发送到位于iOS(渲染服务器)中的单独进程。理想情况下,渲染服务器只是在屏幕上显示数据。
如果您在CALayer上使用属性,例如打开阴影,GPU将执行其他绘图。这项额外的工作是UIKit工程师在说“屏幕外渲染”时的意思。这总是用硬件执行。
离屏绘图的问题不一定是绘图。当GPU切换其绘图目的地时,屏幕外传递需要上下文切换。在此切换期间,GPU处于空闲状态。
虽然我不知道触发屏幕外传递的完整属性列表,但您可以使用Core Animation Instrument的“Color Offscreen-rendered layer”切换来诊断。我假设除了alpha之外的任何属性都是通过屏幕外传递来执行的。
对于早期的iOS硬件,可以说“在drawRect中做所有事情”。现在GPU更好,UIKit具有像shouldRasterize这样的功能。今天,它是drawRect花费的时间,屏幕外通过的数量和混合量之间的平衡。有关完整的详细信息,请观看2014 WWDC会话419,“iOS应用的高级图形和动画”。
所有人都说,了解幕后发生的事情并将其保留在脑后,这样你就不会做任何疯狂事情,但你应该从最简单的解决方案开始。然后在您支持的最慢硬件上进行测试。如果您没有达到60FPS,请使用仪器测量并计算出来。存在一些可能的瓶颈,如果您不使用数据来诊断事物,那么您只是在猜测。
答案 2 :(得分:10)
图形性能的最大瓶颈是屏幕外渲染和混合 - 它们可能会在动画的每一帧中发生,并且可能导致不连贯的滚动。
屏幕渲染(软件渲染)发生在必须在软件中进行绘图(屏幕外)之后才能切换到GPU。硬件不处理带有蒙版和阴影的文本渲染和高级合成。
以下内容将触发屏幕外渲染:
任何带面具的图层(layer.mask
)
layer.masksToBounds
/ view.clipsToBounds
为真的任何图层
layer.allowsGroupOpacity
设置为YES且layer.opacity
的任何图层都小于1.0
When does a view (or layer) require offscreen rendering?
任何带阴影的图层(layer.shadow*
)
有关如何修复的提示:https://markpospesel.wordpress.com/tag/performance/
layer.shouldRasterize
为真的任何图层
包含layer.cornerRadius
,layer.edgeAntialiasingMask
,layer.allowsEdgeAntialiasing
包含layer.borderWith
和layer.borderColor
的任何图层?
缺少参考/证明
文字(任何种类,包括UILabel
,CATextLayer
,Core Text
等。
您在CGContext
中使用drawRect:
执行的大多数绘图。即使是空的实现也会在屏幕外呈现。
这篇文章介绍了影响效果的混合和其他因素:What triggers offscreen rendering, blending and layoutSubviews in iOS?