经常绘制CGPath时的性能

时间:2012-01-03 16:57:59

标签: objective-c ios core-graphics cgpath

我正在开发一款将数据可视化为线图的iOS应用程序。该图表在全屏自定义CGPath中绘制为UIView,最多包含320个数据点。数据经常更新,图表需要相应地重新绘制 - 刷新率为10 /秒会很好。

到目前为止这么容易。但是,我的方法似乎占用了大量的CPU时间。使用320个段以每秒10次刷新图形会导致iPhone 4S上的进程占CPU负载的45%。

也许我低估了引擎盖下的图形工作,但对我而言,CPU负载对于该任务似乎很重要。

下面是我的drawRect()函数,每次准备好一组新数据时都会调用它。 N保留点数,pointsCGPoint*向量,其中包含要绘制的坐标。

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    // set attributes
    CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
    CGContextSetLineWidth(context, 1.f);

    // create path
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddLines(path, NULL, points, N+1);

    // stroke path
    CGContextAddPath(context, path);
    CGContextStrokePath(context);

    // clean up
    CGPathRelease(path); 
}

我尝试先将路径渲染到离线CGContext,然后按照建议的here将其添加到当前图层,但没有任何正面结果。我也直接向CALayer绘制了一个方法,但这也没有任何区别。

如何提高此任务的性能?或者渲染对我认识到的CPU更有用吗? OpenGL会有任何意义/差异吗?

谢谢/ Andi

更新:我还尝试使用UIBezierPath代替CGPath。这篇文章here给出了一个很好的解释,为什么这没有帮助。调整CGContextSetMiterLimit等。也没有带来很大的解脱。

更新#2:我最终切换到了OpenGL。这是一个陡峭而令人沮丧的学习曲线,但性能提升令人难以置信。但是,CoreGraphics的抗锯齿算法比OpenGL中的4x多重采样可以实现更好的工作。

5 个答案:

答案 0 :(得分:8)

  

这篇文章here给出了一个很好的解释,为什么这没有帮助。

它还解释了为什么drawRect:方法很慢。

每次绘制时都会创建一个CGPath对象。你不需要这样做;每次修改点集时,只需要创建一个新的CGPath对象。将CGPath的创建移动到仅在点集更改时调用的新方法,并在对该方法的调用之间保留CGPath对象。让drawRect:只是检索它。

你已经发现渲染是你正在做的最昂贵的事情,这很好:你不能让渲染速度更快,是吗?实际上,drawRect:理想情况下应该除了渲染之外,所以你的目标应该是尽可能将渲染所花费的时间推到100% - 这意味着尽可能地移动其他所有内容,没有绘图代码。

答案 1 :(得分:5)

根据您制作路径的方式,绘制300个单独路径可能比一个路径300点快。这样做的原因是绘图算法通常会寻找重叠线以及如何使交叉点看起来“完美” - 当你可能只希望线条不透明地相互重叠时。许多重叠和交叉算法的复杂度为N ** 2左右,因此绘制速度与一条路径中的点数平方成比例。

这取决于您使用的确切选项(其中一些是默认选项)。你需要尝试一下。

答案 2 :(得分:0)

您是否尝试过使用UIBezierPath? UIBezierPath在引擎盖下使用了CGPath,但是看看性能是否因某些微妙原因而有所不同。来自Apple's Documentation

  

要在iOS中创建路径,建议您使用UIBezierPath   除非你需要一些功能,否则不是CGPath函数   只有Core Graphics提供,例如向路径添加省略号。   有关在UIKit中创建和渲染路径的更多信息,请参阅“绘制形状”   使用Bezier路径。“

我还会尝试在CGContext上设置不同的属性,特别是使用CGContextSetLineJoin()设置不同的行连接样式,看看是否有任何区别。

您是否使用仪器中的Time Profiler仪器分析了您的代码?这可能是找到性能瓶颈实际发生位置的最佳方法,即使瓶颈在系统框架内的某个地方也是如此。

答案 3 :(得分:0)

我不是这方面的专家,但我首先怀疑的是,它可能需要时间来更新'点'而不是渲染自己。在这种情况下,您可以简单地停止更新点并重复渲染相同的路径,并查看它是否需要几乎相同的CPU时间。如果没有,您可以提高注重更新算法的性能。

如果它确实是渲染的问题,我认为OpenGL肯定会提高性能,因为它理论上会同时渲染所有320行。

答案 4 :(得分:0)

我在我的项目中使用Metal完成了这项工作。使用Metal显然有额外的复杂性,因此根据您的性能要求,它可能适合也可能不适合。

使用Metal,所有工作都在GPU中完成,因此CPU使用率接近于零。在大多数iOS设备上,您可以平滑地渲染数百或数千条曲线,速度为60 FPS。

以下是我编写的一些示例代码,它可能为某人提供一个良好的起点:https://github.com/eldade/ios_metal_bezier_renderer