2013-03-12 2 views
7

私は、ユーザーの入力に応じてリアルタイムでベジエ曲線を描画する必要があるiOSアプリケーションを開発しています。最初は、素晴らしいベクター描画APIを備えたCoreGraphicsを試してみることにしました。しかし、私はすぐに、私の網膜iPad上でただ1つの曲線でフレームレートがひどく落ち始めるまで、パフォーマンスは非常に辛抱強く遅かったことを発見しました。 (確かに、これは非効率的なコードを使った簡単なテストでした。たとえば、カーブはフレームごとに再描画されていましたが、確かに今日のコンピュータは1/60秒ごとに単純なカーブを描画するのに十分速いでしょうか?)穏やかなソフトウェアベクトル、特にCoreGraphics vs. OpenGL

この実験の後、私はOpenGLとMonkVGライブラリに切り替えました。私はもっと幸せになれませんでした。私は、フレームレートを落とすことなく、カーネルのHUNDREDSを同時にレンダリングできるようになりました(私のユースケースの場合)。

  1. それは私が何とか(これはOpenGLのソリューションよりも遅く数桁だったポイントまで)CoreGraphicsを誤用、またはパフォーマンスは本当に恐ろしいであることは可能ですか?私の感想は、CGパフォーマンスに関するStackOverflow /フォーラムの質問と回答の数に基づいて、CoreGraphicsに問題があることです。 (私は、CGが実行ループに入ることを意図しておらず、まれにしかレンダリングに使用されていないことをいくつかの人々が見てきたことがあります)。
  2. CoreGraphicsが本当に遅い場合、Safariはどのようにスムーズに動作しますか?私はSafariがハードウェアアクセラレーションではないという印象を受けていましたが、フレームを落とさずにベクトル文字を数百(数千ではないにしても)表示する必要がありました。
  3. さらに一般的には、ハードウェアアクセラレーションを使用せずに、ヘビーベクタを使用するアプリケーション(ブラウザ、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 
+2

コードを表示せずにCore Graphicsを誤用した場合や、少なくともより詳細な説明がある場合は、言うことは難しいです。各フレームに(明示的または暗黙的に)新しいCGPathRefを作成しましたか、または事前に作成して再使用しましたか?私はそれがパフォーマンスに影響するだろうと確信しています。 – benzado

+0

私は各フレームに新しいCGPathRefを作成しているかもしれませんが、私は再確認する必要があります。 (しかし、私がしたとしても、パフォーマンスは数桁向上するとは想像できません。)スプラインの新しく追加された各セグメントにのみ再描画を制限しようとしたことは知っていますが、それでもあまり役に立ちませんでした。 – Archagon

+1

Core Graphicsを使用して、各フレームに何度も複雑なパスを数回描くアプリケーションを作成しました。パフォーマンスは予想よりも良く、良い結果でした。経路は約100個の要素から構成され、線幅は100 pxまでで、未接続部分の間に丸いキャップが多数あります。私は、iPad 2と3(網膜解像度で)でフルスクリーンを描くときのパフォーマンスに感心しました。 –

答えて

3

まず、Why is UIBezierPath faster than Core Graphics path?を参照して、パスを最適に設定していることを確認してください。既定では、CGContextは、多くのオーバーヘッドを追加することができるパスに多くの「かなり」オプションを追加します。これらをオフにすると、スピードが飛躍的に向上します。

コアグラフィックスベジエ曲線で見つかった次の問題は、1つの曲線に多くのコンポーネントがある場合です(約3000〜5000個の要素を調べたときに問題が発生していました)。私はCGPathAdd...で過ごした時間の非常に驚くべき量を発見した。あなたのパスの要素の数を減らすことは、大きな勝利になる可能性があります。昨年のCore Graphicsチームとの私の話から、これはCore Graphicsのバグであり、修正されている可能性があります。私は再テストしていない。


EDIT:

はループの外 CGContextStrokePath()を移動

:私は次の変更を行うことでiPadの3に網膜に18-20FPSを見ています。すべての道を踏むべきではありません。あなたは最後に一度ストロークする必要があります。これは私のテストを〜8FPSから〜12FPSにします。

は(おそらくあなたのOpenGLのテストで、デフォルトではオフになって)アンチエイリアシングをオフにし

CGContextSetShouldAntialias(ctx, false); 

非網膜を40FPS周り18-20FPS(網膜)に、最大に私を取得すること。

私はあなたがOpenGLで何を見ているのか分かりません。 Core Graphicsは美しいものになるように設計されていることを忘れないでください。 OpenGLは物事を速くするように設計されています。 Core GraphicsはOpenGLに依存しています。だから、私はいつもよく書かれたOpenGLコードがもっと速くなると期待しています。

+0

私は上記のコードサンプルを追加しました:SDモードでは20fps、網膜モードでは6fps、試行された60fpsでアニメーション化されたわずか5本のカーブです。 UIBezierPathメソッドを使用すると、1秒あたり数フレームしか追加されませんでした。 – Archagon

4

Core Craphicsの描画とOpenGLを比較しないでください。まったく異なる目的で全く異なる機能を比較しています。

コアグラフィックスとクォーツは、画質の観点から、OpenGLよりもはるかに優れています。 Core Graphicsフレームワークは、最適な外観、自然にアンチエイリアス処理されたラインとカーブ、Apple UIに関連するポリッシュ用に設計されています。しかし、この画質は価格で提供されます:レンダリングのスピード。

一方、OpenGLは速度を優先して設計されています。高性能で高速な描画は、OpenGLでは難しいです。しかし、この速度にはコストがかかります。OpenGLを使って滑らかで洗練されたグラフィックスを作成するのはずっと難しくなります。 OpenGLでは「シンプル」なアンチエイリアスを行うための戦略がたくさんありますが、これはQuartz/Core Graphicsでより簡単に処理できます。

+0

私が主に驚いているのは、遅いCoreGraphicsがベクトルグラフィックスのためのものであることです。それは特に困難な仕事のようには見えませんが、おそらく1秒間に約100万画素を押し込むことがどれほど難しいかを過小評価しているかもしれません。 – Archagon

+0

いいえ、あなたが過小評価しているのは、隣接するピクセルの色合いを計算するときにスムーズな線や曲線を作成するためのフードの下で行われるすべての数学的な作業です。 OpenGLでは、これを自分で行う必要があります。 – johnbakers

+0

この引数行を拡張するには、@Archagon:あなたの比較ポイントはそれほど同等ではありません。 Safariは、ベジエ曲線をフルスクリーンで60fpsでラスタライズしようとしていないため、テストアプリほど遅くはありません。レンダリング(およびスクロール)タイプは非常に異なるプロセスで、ラスタライズジョブが少なくて済み、多くのキャッシュが必要になります。 – rickster

1

あなたの減速があるため、このコード行である:それはすべてのフレームを変更したものを、長方形を計算するのはあなた次第ですが、場合

[self setNeedsDisplayInRect:changedRect]; 

[self setNeedsDisplay]; 

あなたはこれを変更する必要がありますこれを適切に行うと、他の変更がなくてもパフォーマンスの向上が一桁以上見られる可能性があります。

3

免責事項:私はMonkVGの著者です。 MonkVGはそんなに速くCoreGraphics、その後であることを

最大の理由は、実際にレンダリングが行われ前に、ポリゴンに輪郭をテッセレーションによってバッキングをレンダリングそれ「詐欺」ためとしてのOpenGL ESを用いて実装されていることはあまりないです。輪郭のテッセレーションは実際には非常に遅く、輪郭を動的に生成する場合、大きな減速が見られます。 OpenGLバッキング(CoreGraphicsの詩の直接ビットマップレンダリング)の大きな利点は、そのような変換、回転、または拡大縮小が輪郭の完全な再テッセレーションを強制することではないことです。

関連する問題