首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS CGPath性能

iOS CGPath性能
EN

Stack Overflow用户
提问于 2012-07-12 20:02:16
回答 2查看 2.2K关注 0票数 6

更新

我克服了CG的局限性,用OpenGL绘制了所有的东西。仍然有一些小故障,但到目前为止,它运行得更快了。

一些有趣的观点:

  • GLKView:这是一个特定于iOS的视图,它在设置OpenGL上下文和呈现循环方面有很大帮助。如果你不在iOS,恐怕只能靠你自己了。
  • 着色精度:当前版本的OpenGL ES (2.0)中着色器变量的精度为16位。这对我来说有点低,所以我用16位变量对来模拟32位算术。
  • GL_LINES:OpenGL ES可以本机绘制简单的线条。不是很好(没有关节,没有帽子,见下面屏幕截图顶部的紫色/灰色线),但是要改善你必须写一个自定义着色器,将每一行转换成一个三角形条,并祈祷它的工作!(据说,当浏览器告诉你Canvas2D是GPU加速的时候,浏览器就是这样做的)

  • 绘制尽可能少的。我认为这是有意义的,但是您可以经常避免渲染那些在视口之外的东西。
  • OpenGL ES没有对填充多边形的支持,所以您必须自己对它们进行tesselate。考虑使用iPhone:这是MESA代码的一个端口,它非常好,尽管它有点难用(没有标准的Objective接口)。

原始问题

我正在我的滚动视图的drawRect方法中绘制大量的drawRect(通常超过1000),当用户用手指平移时,这个方法会被刷新。我在JavaScript中为浏览器提供了相同的应用程序,我正在尝试将其移植到iOS原生应用程序中。

iOS测试代码是(有100行操作,path是预先生成的CGMutablePathRef):

代码语言:javascript
复制
- (void) drawRect:(CGRect)rect {
    // Start the timer
    BSInitClass(@"Renderer");
    BSStartTimedOp(@"Rendering");

    // Get the context
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 2.0);
    CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
    CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
    CGContextTranslateCTM(context, 800, 800);

    // Draw the points
    CGContextAddPath(context, path);
    CGContextStrokePath(context);

    // Display the elapsed time
    BSEndTimedOp(@"Rendering");
}

在JavaScript中,用于参考的代码是(具有10000行操作):

代码语言:javascript
复制
window.onload = function() {
  canvas = document.getElementById("test");
  ctx = canvas.getContext("2d");

  // Prepare the points before drawing
  var data = [];
  for (var i = 0; i < 100; i++) data.push ({x: Math.random()*canvas.width, y: Math.random()*canvas.height});

  // Draw those points, and write the elapsed time
  var __start = new Date().getTime();
  for (var i = 0; i < 100; i++) {
    for (var j = 0; j < data.length; j++) {
      var d = data[j];
      if (j == 0) ctx.moveTo (d.x, d.y);
      else ctx.lineTo(d.x,d.y)
    }
  }
  ctx.stroke();
  document.write ("Finished in " + (new Date().getTime() - __start) + "ms");
};

现在,与iOS相比,我在优化iOS方面要熟练得多,但是,经过一些分析之后,与JavaScript相比,CGPath的开销似乎绝对是非常糟糕的。这两个代码段在真正的设备上以大约相同的速度运行,而JavaScript代码的行数是Quartz2D代码的100倍!

编辑:这里是仪器时间分析器的顶部:

代码语言:javascript
复制
Running Time   Self             Symbol Name
6487.0ms       77.8%  6487.0    aa_render
449.0ms        5.3%   449.0     aa_intersection_event
112.0ms        1.3%   112.0     CGSColorMaskCopyARGB8888
73.0ms         0.8%   73.0      objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*>, objc::DenseMapInfo<unsigned long> >::LookupBucketFor(objc_object* const&, std::pair<objc_object*, unsigned long>*&) const
69.0ms         0.8%   69.0      CGSFillDRAM8by1
66.0ms         0.7%   66.0      ml_set_interrupts_enabled
46.0ms         0.5%   46.0      objc_msgSend
42.0ms         0.5%   42.0      floor
29.0ms         0.3%   29.0      aa_ael_insert

我的理解是,这在iOS上应该要快得多,因为代码是本机的.所以,你知道吗

  • ...what我在这里做错了吗?
  • 如果有另一种更好的解决方案来实时绘制那么多的线,...and?

非常感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-01 18:44:39

正如您在问题中所描述的,使用OpenGL是正确的解决方案。理论上,您可以用OpenGL来模拟各种图形,但是您需要自己实现所有的形状算法。例如,您需要自己扩展线条的边缘角。在OpenGL中没有行的概念。线条绘制是一种实用功能,几乎只用于调试。你应该把每件事看成是一组三角形。

我相信16位浮点数对大多数绘图来说都足够了。如果您使用的坐标具有较大的数字,请考虑将空间划分为多个扇区,以使坐标数更小。当浮标变得非常大或非常小时,它的精度就会变差。

更新

我认为,如果您尝试在UIKit显示器上显示OpenGL,您很快就会遇到这个问题。不幸的是,我还没有找到解决办法。

票数 0
EN

Stack Overflow用户

发布于 2013-07-28 14:52:53

您通过使用CGPath来破坏CGContextAddPath的性能。

苹果明确表示,这将缓慢运行--如果您希望它运行得很快,则需要将您的CGPath对象附加到CAShapeLayer实例。

您正在进行动态的、运行时绘图--阻止了所有Apple的性能优化。尝试切换到CALayer --尤其是CAShapeLayer --您应该会看到性能有了很大的提高。

(注意: CG呈现中还有其他可能影响此用例的性能缺陷,例如CG/Quartz/CA中模糊的默认设置,但是.您首先需要消除CGContextAddPath上的瓶颈)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11459713

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档