gpt4 book ai didi

iOS CGPath 性能

转载 作者:可可西里 更新时间:2023-11-01 04:03:30 28 4
gpt4 key购买 nike

更新

我通过使用 OpenGL 绘制所有内容来绕过 CG 的限制。仍然存在一些问题,但到目前为止,它的工作速度要快得多。

一些有趣的点:

  • GLKView :这是一个特定于 iOS 的 View ,它对设置 OpenGL 上下文和渲染循环有很大帮助。如果您不使用 iOS,恐怕您只能靠自己了。
  • Shader precision : 当前版本的OpenGL ES (2.0) shader变量的精度是16-bit .这对我的目的来说有点低,所以我用成对的 16 位变量模拟了 32 位算术。
  • GL_LINES :OpenGL ES 可以原生绘制简单的线条。不太好(没有接头,没有帽,请参见下面屏幕截图顶部的紫色/灰色线),但要改进这一点,您必须编写自定义着色器,将每一行转换为一个三角形 strip 并祈祷它有效! (据说当浏览器告诉您 Canvas2D 是 GPU 加速时浏览器就是这样做的)

Example rendering

  • 画画尽可能少。我想这是有道理的,但您通常可以避免渲染视口(viewport)之外的东西。
  • OpenGL ES 支持填充的多边形,因此您必须自己分割它们。考虑使用 iPhone-GLU : 这是 MESA 代码的一个端口,它非常好,虽然它有点难用(没有标准的 Objective-C 接口(interface))。

原始问题

我试图在我的 ScrollView 的 drawRect 方法中绘制大量 CGPath(通常超过 1000 个),当用户用手指平移时,它会刷新。我有相同的浏览器 JavaScript 应用程序,我正在尝试将它移植到 iOS native 应用程序。

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 方面更精通,但是,经过一些分析后,似乎 CGPath 的开销与 JavaScript 相比绝对非常糟糕。这两个片段在真实的 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 上应该更快,因为代码是原生的......所以,你知道吗:

  • ...我做错了什么?
  • ...如果有其他更好的实时绘制那么多线条的解决方案?

非常感谢!

最佳答案

正如您在问题中所述,使用 OpenGL 是正确的解决方案。理论上,你可以用OpenGL模拟各种图形的绘制,但是你需要自己实现所有的形状算法。例如,您需要自己延长线条的边角。 OpenGL 中没有线 的概念。画线是一种实用功能,几乎只用于调试。您应该将所有内容都视为一组三角形。

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

更新

如果您尝试在 OpenGL 显示器上显示 UIKit,我想您很快就会遇到这个问题。不幸的是,我也找不到解决方案。

关于iOS CGPath 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11459713/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com