在iPad 3上CGContextDrawLayerAtPoint很慢

Bob*_*sky 0 core-graphics ipad ios ipad-3

UIView我的应用程序中有自定义视图(继承自).自定义视图覆盖

- (void) drawRect:(CGRect) rect

问题是:drawRect:在iPad 3上的执行时间比在iPad 2上执行的时间长许多倍(在iPad 3上大约0.1秒,在iPad 2上大约0.003秒).它慢了约30倍.

基本上,我正在使用一些预先创建的图层并在其中绘制它们drawRect:.最后一个电话

CGContextDrawLayerAtPoint(context, CGPointZero, m_currentLayer);
Run Code Online (Sandbox Code Playgroud)

占用大部分时间(约占总时间的95%drawRect:)

什么可能会使事情变得如此缓慢,我该如何解决问题呢?

更新:

没有直接涉及的线程.我确实setNeedsDisplay:在一个线程中调用并drawRect:从另一个线程调用,但就是这样.锁也是如此(没有使用锁).

视图会重新绘制以响应触摸(它是着色书应用程序).在iPad 2上,我可以在触摸和更新屏幕之间获得合理的延迟.我想在iPad 3上实现同样的目标.

Aar*_*man 7

因此,iPad 3在许多领域肯定都比较慢.我对此有一个理论. Marco Arment指出,这种方法renderInContext在新iPad上的速度非常慢.我还发现在尝试为自定义文本视图创建放大镜时就是这种情况.最后,我不得不放弃renderInContext自定义Core Graphics绘图.

我也遇到了wait_fences在我的核心图形绘图上遇到可怕错误的问题:仅在新的iPad 3上:wait_fences:未能收到回复:10004003.

这是我到目前为止所想到的.iPad 3显然是驱动像素的4倍.这可能会导致两个问题:

  1. 首先是CPU.所有核心图形绘制都由CPU完成.在旋转事件的情况下,如果CPU花费太长时间来绘制,它会遇到wait_fences错误,我认为这只是一个调用,告诉设备等待一段时间来实际执行旋转,从而延迟.
  2. 将图像传输到GPU.GPU显然可以很好地处理视网膜分辨率(参见Infinity Blade 2).但是当核心图形绘制时,它会将图像直接绘制到GPU缓冲区以避免memcpy.但是,自从iPad 2以来,GPU缓冲区都没有变化,或者它们只是没有足够大,因为重载这些缓冲区非常容易.当发生这种情况,我认为CPU写入图像标准内存,然后将它们复制到GPU时,GPU缓存可以处理它.我认为是导致性能问题的原因.额外的副本耗费大量像素并且会大大减慢速度.

为了避免memcpy我推荐几件事:

  1. 只画出你需要的东西.避免不惜一切代价在屏幕外绘图.如果您正在绘制一个大视图,但只显示该视图的一部分(例如,覆盖它的子视图),请尝试找到一种仅绘制可见内容的方法.
  2. 如果您必须绘制一个大视图,请考虑将视图分解为子视图或子图层(在您的情况下可能是子图层).只重绘你需要的东西.例如,使用notability app.放大时,您可以逐字地观看它重绘一个方格.或者在safari中,您可以在滚动时观看它更新方块.不幸的是,我没有必要这样做,所以我不确定方法.
  3. 尽量保持简单的图纸.我有一个很棒的自定义核心文本视图,必须重绘每个输入的字符.非常慢.我将背景改为简单的白色(在核心图形中),它加速了.更好的是我不重绘背景.

我想指出我的理论是猜想.Apple并没有真正解释他们到底做了什么.我的理论仅仅基于他们所说的内容以及iPad如何响应以及我自己的实验.

UPDATE

因此Apple现在发布了2012 WWDC开发者视频.他们有两个视频可以帮助您(需要开发者帐户):

  1. iOS应用程序性能:响应能力
  2. iOS App性能:图形和动画

他们谈论的一件事我认为可以帮助你使用这个方法:setNeedsDisplayInRect:(CGRect)rect.使用此方法代替正常方法setNeedsDisplay并确保您的drawRect方法仅绘制给定的矩形可以极大地帮助提高性能.就个人而言,我使用的功能是:CGContextClipToRect(context, rect);仅将我的绘图剪辑到提供的矩形.

作为一个例子,我有一个单独的类,我使用Core Text直接将文本绘制到我的视图.我的UIView子类保留对此对象的引用,并使用它来绘制文本,而不是使用UILabel.我曾经setNeedsDisplay在文本改变时刷新整个视图().现在,我有我的CoreText对象计算改变的CGRect并使用setNeedsDisplayInRect只更改包含文本视图的一部分.滚动时,这确实有助于我的表现.