痛苦地减慢软件向量,特别是CoreGraphics与OpenGL

Arc*_*gon 7 opengl-es core-graphics vector-graphics openvg ios

我正在开发一个iOS应用程序,需要实时绘制Bézier曲线以响应用户的输入.起初,我决定尝试使用CoreGraphics,它具有出色的矢量绘图API.然而,我很快就发现性能很痛苦,极其缓慢,在我的视网膜iPad上只有一条曲线,帧速率开始严重下降.(不可否认,这是一个代码效率低下的快速测试.例如,曲线每帧都重新绘制.但是今天的计算机确实足够快,每隔1/60秒处理一条简单的曲线,对吧?!)

在这个实验之后,我切换到OpenGL和MonkVG库,我感到非常高兴.我现在可以在没有任何帧速率下降的情况下同时渲染HUNDREDS曲线,对保真度的影响很小(对于我的用例).

  1. 我是否有可能以某种方式滥用CoreGraphics(至少比OpenGL解决方案慢几个数量级),还是表现真的那么可怕?我的预感是问题在于CoreGraphics,基于StackOverflow /论坛问题的数量以及有关CG性能的答案.(我已经看到有几个人声称CG并不意味着进入一个运行循环,并且它只应该用于不频繁的渲染.)从技术上讲,为什么会这样呢?
  2. 如果CoreGraphics真的那么慢,Safari究竟如何顺利地工作?我的印象是Safari不是硬件加速的,但它必须同时显示数百个(如果不是数千个)矢量字符而不丢弃任何帧.
  3. 更一般地说,如果没有硬件加速,使用重载矢的应用程序(浏览器,Illustrator等)如何保持如此快速?(据我所知,许多浏览器和图形套件现在都带有硬件加速选项,但默认情况下它通常不会打开.)

更新:

我编写了一个快速测试应用程序来更准确地衡量性能.下面是我的自定义CALayer子类的代码.

将NUM_PATHS设置为5并将NUM_POINTS设置为15(每个路径5个曲线段),代码在非视网膜模式下以20fps运行,在iPad 3上以视网膜模式运行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
Run Code Online (Sandbox Code Playgroud)

Rob*_*ier 3

首先,请参阅为什么 UIBezierPath 比 Core Graphics 路径更快?并确保您正在以最佳方式配置路径。默认情况下,CGContext向路径添加许多“漂亮”选项,这会增加大量开销。如果您关闭这些功能,您可能会发现速度显着提高。

\n\n

我在 Core Graphics B\xc3\xa9zier 曲线中发现的下一个问题是,当单条曲线中有许多组件时(当我检查大约 3000-5000 个元素时,我发现了问题)。我发现花在上面的时间非常惊人CGPathAdd...。减少路径中的元素数量可能是一个重大胜利。从我去年与 Core Graphics 团队的谈话来看,这可能是 Core Graphics 中的一个错误,并且可能已被修复。我没有重新测试过。

\n\n
\n\n

编辑:通过进行以下更改,我在 iPad 3 上的 Retina 中看到 18-20FPS:

\n\n

移动CGContextStrokePath()循环之外。你不应该抚摸每条路。最后应该抚摸一次。这使我的测试从 ~8FPS 到 ~12FPS。

\n\n

关闭抗锯齿功能(在 OpenGL 测试中可能默认关闭):

\n\n
CGContextSetShouldAntialias(ctx, false);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这使我的帧速率达到 18-20FPS(视网膜),非视网膜帧速率高达 40FPS 左右。

\n\n

我不知道你在 OpenGL 中看到了什么。请记住,Core Graphics 的设计目的是让事物变得美丽;OpenGL 旨在让事情变得更快。Core Graphics依赖于OpenGL;所以我总是期望编写良好的 OpenGL 代码会更快。

\n