我正在开发一个 iOS 应用程序,它需要实时绘制贝塞尔曲线以响应用户的输入。起初,我决定尝试使用 CoreGraphics,它具有出色的矢量绘图 API。然而,我很快发现性能非常缓慢,令人痛苦,以至于帧率开始严重下降,我的视网膜 iPad 上只有一条曲线。 (不可否认,这是一个使用低效代码的快速测试。例如,曲线每帧都被重新绘制。但今天的计算机肯定足够快,可以处理每 1/60 秒绘制一条简单曲线,对吧?!)
在这个实验之后,我切换到 OpenGL 和 MonkVG图书馆,我再高兴不过了。我现在可以同时渲染数百条曲线,而不会降低帧率,而且对保真度的影响很小(对于我的用例)。
- 是否有可能我以某种方式滥用了 CoreGraphics(以至于它比 OpenGL 解决方案慢了几个数量级),或者性能真的有那么糟糕吗?根据 StackOverflow/论坛关于 CG 性能的问题和答案的数量,我的预感是问题出在 CoreGraphics 上。 (我见过几个人说 CG 不应该进入运行循环,它应该只用于不频繁的渲染。)从技术上讲,为什么会这样?
- 如果 CoreGraphics 真的那么慢,那么 Safari 究竟是如何运行得如此流畅的呢?我的印象是 Safari 没有硬件加速,但它必须同时显示数百个(如果不是数千个)矢量字符而不丢帧。
- 更一般地说,使用大量矢量的应用程序(浏览器、Illustrator 等)如何在没有硬件加速的情况下保持如此快速? (据我了解,许多浏览器和图形套件现在都带有硬件加速选项,但默认情况下通常不会打开。)
更新:
我编写了一个快速测试应用程序来更准确地衡量性能。下面是我的自定义 CALayer 子类的代码。
NUM_PATHS 设置为 5,NUM_POINTS 设置为 15(每条路径 5 个曲线段),代码在我的 iPad 3 上以非视网膜模式以 20fps 运行,以视网膜模式以 6fps 运行。探查器列出 CGContextDrawPath 有 96% CPU 时间。是的——显然,我可以通过限制重绘矩形来优化,但如果我真的、真的需要 60fps 的全屏矢量动画怎么办?
OpenGL 早餐吃这个测试。矢量绘图怎么可能这么慢?
#import "CGTLayer.h"
@implementation CGTLayer
- (id) init
{
self = [super init];
if (self)
{
self.backgroundColor = [[UIColor grayColor] CGColor];
displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(updatePoints:)] retain];
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
initialized = false;
previousTime = 0;
frameTimer = 0;
}
return self;
}
- (void) updatePoints:(CADisplayLink*)displayLink
{
for (int i = 0; i < NUM_PATHS; i++)
{
for (int j = 0; j < NUM_POINTS; j++)
{
points[i][j] = CGPointMake(arc4random()%768, arc4random()%1024);
}
}
for (int i = 0; i < NUM_PATHS; i++)
{
if (initialized)
{
CGPathRelease(paths[i]);
}
paths[i] = CGPathCreateMutable();
CGPathMoveToPoint(paths[i], &CGAffineTransformIdentity, points[i][0].x, points[i][0].y);
for (int j = 0; j < NUM_POINTS; j += 3)
{
CGPathAddCurveToPoint(paths[i], &CGAffineTransformIdentity, points[i][j].x, points[i][j].y, points[i][j+1].x, points[i][j+1].y, points[i][j+2].x, points[i][j+2].y);
}
}
[self setNeedsDisplay];
initialized = YES;
double time = CACurrentMediaTime();
if (frameTimer % 30 == 0)
{
NSLog(@"FPS: %f\n", 1.0f/(time-previousTime));
}
previousTime = time;
frameTimer += 1;
}
- (void)drawInContext:(CGContextRef)ctx
{
// self.contentsScale = [[UIScreen mainScreen] scale];
if (initialized)
{
CGContextSetLineWidth(ctx, 10);
for (int i = 0; i < NUM_PATHS; i++)
{
UIColor* randomColor = [UIColor colorWithRed:(arc4random()%RAND_MAX/((float)RAND_MAX)) green:(arc4random()%RAND_MAX/((float)RAND_MAX)) blue:(arc4random()%RAND_MAX/((float)RAND_MAX)) alpha:1];
CGContextSetStrokeColorWithColor(ctx, randomColor.CGColor);
CGContextAddPath(ctx, paths[i]);
CGContextStrokePath(ctx);
}
}
}
@end
最佳答案
您真的不应该将 Core Graphics 绘图与 OpenGL 进行比较,您是在出于非常不同的目的比较完全不同的功能。
在图像质量方面,Core Graphics 和 Quartz 将以更少的努力远远优于 OpenGL。 Core Graphics 框架旨在实现最佳外观、自然抗锯齿的线条和曲线以及与 Apple UI 相关的润色。但这种图像质量是有代价的:渲染速度。
另一方面,OpenGL 的设计优先考虑速度。高性能、快速绘图是 OpenGL 难以匹敌的。但这种速度是有代价的:使用 OpenGL 获得平滑和优美的图形要困难得多。有许多不同的策略可以在 OpenGL 中执行像抗锯齿这样“简单”的操作,Quartz/Core Graphics 更容易处理。
关于ios - 非常慢的软件矢量,尤其是 CoreGraphics 与 OpenGL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15370344/