私は、ユーザーの入力に応じてリアルタイムでベジエ曲線を描画する必要があるiOSアプリケーションを開発しています。最初は、素晴らしいベクター描画APIを備えたCoreGraphicsを試してみることにしました。しかし、私はすぐに、私の網膜iPad上でただ1つの曲線でフレームレートがひどく落ち始めるまで、パフォーマンスは非常に辛抱強く遅かったことを発見しました。 (確かに、これは非効率的なコードを使った簡単なテストでした。たとえば、カーブはフレームごとに再描画されていましたが、確かに今日のコンピュータは1/60秒ごとに単純なカーブを描画するのに十分速いでしょうか?)穏やかなソフトウェアベクトル、特にCoreGraphics vs. OpenGL
この実験の後、私はOpenGLとMonkVGライブラリに切り替えました。私はもっと幸せになれませんでした。私は、フレームレートを落とすことなく、カーネルのHUNDREDSを同時にレンダリングできるようになりました(私のユースケースの場合)。
- それは私が何とか(これはOpenGLのソリューションよりも遅く数桁だったポイントまで)CoreGraphicsを誤用、またはパフォーマンスは本当に恐ろしいであることは可能ですか?私の感想は、CGパフォーマンスに関するStackOverflow /フォーラムの質問と回答の数に基づいて、CoreGraphicsに問題があることです。 (私は、CGが実行ループに入ることを意図しておらず、まれにしかレンダリングに使用されていないことをいくつかの人々が見てきたことがあります)。
- CoreGraphicsが本当に遅い場合、Safariはどのようにスムーズに動作しますか?私はSafariがハードウェアアクセラレーションではないという印象を受けていましたが、フレームを落とさずにベクトル文字を数百(数千ではないにしても)表示する必要がありました。
- さらに一般的には、ハードウェアアクセラレーションを使用せずに、ヘビーベクタを使用するアプリケーション(ブラウザ、Illustratorなど)は非常に高速になりますか? (私はそれを理解したように、多くのブラウザやグラフィックススイートは現在、ハードウェアアクセラレーションのオプションが付属していますが、それは多くの場合、デフォルトでオンになっていない。)
はUPDATE:
私は簡単なテストを書かれていますより正確にパフォーマンスを測定することができます。以下は私のカスタム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を誤用した場合や、少なくともより詳細な説明がある場合は、言うことは難しいです。各フレームに(明示的または暗黙的に)新しいCGPathRefを作成しましたか、または事前に作成して再使用しましたか?私はそれがパフォーマンスに影響するだろうと確信しています。 – benzado
私は各フレームに新しいCGPathRefを作成しているかもしれませんが、私は再確認する必要があります。 (しかし、私がしたとしても、パフォーマンスは数桁向上するとは想像できません。)スプラインの新しく追加された各セグメントにのみ再描画を制限しようとしたことは知っていますが、それでもあまり役に立ちませんでした。 – Archagon
Core Graphicsを使用して、各フレームに何度も複雑なパスを数回描くアプリケーションを作成しました。パフォーマンスは予想よりも良く、良い結果でした。経路は約100個の要素から構成され、線幅は100 pxまでで、未接続部分の間に丸いキャップが多数あります。私は、iPad 2と3(網膜解像度で)でフルスクリーンを描くときのパフォーマンスに感心しました。 –