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などが使用されなくなる可能性はありますか?