3

CAShapeLayerレンダリングしているものがかなり大きいです。レイヤーは完全に静的ですが、に含まれているUIScrollViewため、移動したりズームしたりできます。基本的には、時々再描画する必要があります。このスクロールのフレームレートを改善するために、私shouldRasterize = YESはレイヤーを設定しました。これは完全に機能しました。レイヤーのプロパティを変更することはないため、ラスタライズミスが発生することはなく、60fpsで安定しています。いたるところにハイタッチしますよね?

レイヤーが少し大きくなるまで。最終的には(そしてそれほど時間はかかりませんが)、ラスタライズされた画像が大きくなりすぎて、GPUで処理できなくなります。私のコンソールによると、、、<Notice>: CoreAnimation: surface 2560 x 4288 is too largeそしてそれは画面上に何も描画しません。私はそれを本当に非難していません-2560 x 4288かなり大きいです-しかし、私はデバイスコンソールでこれに気付く前に頭をかいてしばらく過ごしました。

さて、私の質問は、この制限をどのように回避できるかということです。本当に大きなレイヤーをラスタライズするにはどうすればよいですか?

明らかな解決策は、レイヤーを複数のサブレイヤーに分割し、たとえば各象限に1つずつ分割し、それぞれを個別にラスタライズすることです。これを行う「簡単な」方法はありますか?別のレイヤーから長方形の領域をレンダリングする新しいレイヤーを作成できますか?または、私が探求すべき他の解決策はありますか?

編集

タイル化されたコンポジットを作成すると、画面に入るたびにレイヤーが再ラスタライズされ、非常にぎくしゃくしたスクロールエクスペリエンスが作成されるため、パフォーマンスが非常に悪いようです。それらのラスター化をキャッシュする方法はありますか?それとも、これは完全に間違ったアプローチですか?

編集

了解しました。現在の解決策は次のとおりです。レイヤーを1回レンダリングしますCGImageRef。その画像からサブ長方形を使用して複数のタイルレイヤーを作成し、実際にそれらを画面に配置します。

- (CALayer *)getTiledLayerFromLayer:(CALayer *)sourceLayer withHorizontalTiles:(int)horizontalTiles verticalTiles:(int)verticalTiles
{
    CALayer *containerLayer = [CALayer layer];
    CGFloat tileWidth = sourceLayer.bounds.size.width / horizontalTiles;
    CGFloat tileHeight = sourceLayer.bounds.size.height / verticalTiles;

    // make sure these are integral, otherwise you'll have image alignment issues!
    NSLog(@"tileWidth:%f height:%f", tileWidth, tileHeight);

    UIGraphicsBeginImageContextWithOptions(sourceLayer.bounds.size, NO, 0);
    CGContextRef tileContext = UIGraphicsGetCurrentContext();
    [sourceLayer renderInContext:tileContext];
    CGImageRef image = CGBitmapContextCreateImage(tileContext);
    UIGraphicsEndImageContext();

    for(int horizontalIndex = 0; horizontalIndex < horizontalTiles; horizontalIndex++) {
        for(int verticalIndex = 0; verticalIndex < verticalTiles; verticalIndex++) {
            CGRect frame = CGRectMake(horizontalIndex * tileWidth, verticalIndex * tileHeight, tileWidth, tileHeight);
            CGRect visibleRect = CGRectMake(horizontalIndex / (CGFloat)horizontalTiles, verticalIndex / (CGFloat)verticalTiles, 1.0f / horizontalTiles, 1.0f / verticalTiles);
            CALayer *tile = [CALayer layer];
            tile.frame = frame;
            tile.contents = (__bridge id)image;
            tile.contentsRect = visibleRect;
            [containerLayer addSublayer:tile];
        }
    }

    CGImageRelease(image);

    return containerLayer;
}

これはうまくいきます...ある種。一方では1980 x 3330、網膜iPadでレイヤーの60fpsのパンとズームを取得します。一方、起動には20秒かかります!したがって、このソリューションは私の元の問題を解決しますが、新しい問題をもたらします。タイルをより速く生成するにはどうすればよいですか?

文字通り、すべての時間が[sourceLayer renderInContext:tileContext];通話に費やされます。Core Animation Instrumentによると、そのレイヤーを直接追加するだけで、1秒間に約40回レンダリングできるため、これは奇妙に思えます。独自の画像コンテキストを作成すると、GPUなどが使用されなくなる可能性はありますか?

4

1 に答える 1

2

レイヤーをタイルに分割することが唯一の解決策です。ただし、さまざまな方法で実装できます。手動で行うことをお勧めします (自分でレイヤーとサブレイヤーを作成する) が、多くの人が CATiledLayer http://www.mlsite.net/blog/?p=1857 を使用することを推奨していますこれでかなり簡単。CATiledLayer のタイルは、画面に配置された直後にオンデマンドで読み込まれます (描画されます)。これは、タイルが完全に描画される前に短い遅延 (点滅) が発生することを意味し、知る限り、この動作を取り除くのは非常に困難です。

于 2012-04-10T18:30:07.983 に答える