更新
通过使用 OpenGL 绘制所有内容,我绕过了 CG 的限制。仍然有一些小故障,但到目前为止,它的工作速度要快得多。
一些有趣的观点:
GLKView
:这是一个 iOS 特定的视图,它对设置 OpenGL 上下文和渲染循环有很大帮助。如果你不在 iOS 上,恐怕你自己一个人。- 着色器精度:当前版本的 OpenGL ES (2.0) 中着色器变量的精度为16 位。这对我的目的来说有点低,所以我用一对 16 位变量模拟了 32 位算术。
GL_LINES
: OpenGL ES 可以原生绘制简单的线条。不是很好(没有关节,没有大写,请参见下面屏幕截图顶部的紫色/灰色线),但要改进这一点,您必须编写自定义着色器,将每条线转换为三角形条并祈祷它作品!(据说当浏览器告诉你 Canvas2D 是 GPU 加速时,它们就是这样做的)
- 尽量少画。我认为这是有道理的,但是您可以经常避免渲染例如在视口之外的东西。
- OpenGL ES不支持填充多边形,因此您必须自己对它们进行镶嵌。考虑使用iPhone-GLU:这是 MESA 代码的一个端口,它非常好,虽然它有点难使用(没有标准的 Objective-C 接口)。
原始问题
我试图在drawRect
我的滚动视图的方法中绘制大量 CGPath(通常超过 1000 个),当用户用手指平移时会刷新。我在浏览器的 JavaScript 中有相同的应用程序,我正在尝试将它移植到 iOS 本机应用程序。
iOS测试代码为(100行操作,path
为预制CGMutablePathRef
):
- (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 行操作):
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");
};
现在,我在优化 JavaScript 方面比在 iOS 方面更加精通,但是,经过一些分析后,与 JavaScript 相比,CGPath 的开销似乎绝对非常糟糕。两个片段在真实 iOS 设备上的运行速度大致相同,而且 JavaScript 代码的行操作数是 Quartz2D 代码的 100 倍!
编辑:这是 Instruments 中时间分析器的顶部:
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 上应该更快,仅仅是因为代码是原生的......所以,你知道吗:
- ...我在这里做错了什么?
- ...如果有另一种更好的解决方案来实时绘制那么多线?
非常感谢!