blog

iOSのオフスクリーンレンダリングの認識と解決方法

オフスクリーンレンダリングを理解するには、まずOffScreen BufferとFrame Bufferという2つの用語を理解する必要があります。 一般的に、システムは表示する必要があるビットマップを...

Jul 4, 2020 · 6 min. read
シェア

オフスクリーンレンダリング

オフスクリーンレンダリングを理解するには、まず2つの用語、オフスクリーンバッファとフレームバッファを理解する必要があります。

  • 一般的に、システムは表示する必要のあるビットマップを直接フレームバッファに入れ、それを表示します。
  • オフスクリーンレンダリングがある場合は、新しいバッファOffScreenバッファがあり、OffScreenバッファでは、フレームバッファ内の操作を完了することはできません完了し、フレームバッファに提出し、最終的に表示されます!

オフスクリーンレンダリングがパフォーマンスの問題を引き起こすのはなぜですか?

  1. オフスクリーンレンダリングが生成され、追加のメモリ領域が開放されます OffScreen Buffer
  2. OffScreen BufferでレンダリングしてからFrame Bufferにサブミットするのに時間がかかります。
  • オフスクリーンバッファーのサイズは、スクリーンピクセルの2.5倍と限られています。

原因

角丸を設定するとオフスクリーンレンダリングになることはご存知かもしれませんが、なぜ角丸を設定するとオフスクリーンレンダリングになるのでしょうか?backgroundColorコンテンツ、ボーダーウィズ/borderColorは、レイヤーの表示には3つの部分があります。

AppleによるcornerRadiusの説明 このように、cornerRadiusで角丸を設定する場合、実際には背景に対してのみ機能し、コンテンツにも角丸を設定する必要がある場合は、maskToBoundsプロパティを設定する必要があります。この問題を確認するために、次のコードを見てください。

 // backgroundColorが設定される。
 UIImageView * imageOne = [[UIImageView alloc] init];
 imageOne.frame = CGRectMake(, );
 imageOne.image = [UIImage imageNamed:@"photo"];
 imageOne.backgroundColor = [UIColor greenColor];
 imageOne.layer.cornerRadius = 50.f;
 imageOne.layer.masksToBounds = YES;
 [self.view addSubview:imageOne];
 
 //backgroundColorが設定されていない
 UIImageView * imageTwo = [[UIImageView alloc] init];
 imageTwo.frame = CGRectMake(, );
 imageTwo.image = [UIImage imageNamed:@"photo"];
 imageTwo.layer.cornerRadius = 50.f;
 imageTwo.layer.masksToBounds = YES;
 [self.view addSubview:imageTwo];

cornerRadiusとmaskToBoundsのみが設定されている場合、オフスクリーンレンダリングは発生しませんが、backgroundが同時に設定されている場合、オフスクリーンレンダリングが発生します。

根本的な理由は、backgroundColorを設定しない場合、デフォルトでは背景レイヤーを処理する必要がなく、imageViewでコンテンツをレンダリングし、maskToBoundsをカットしてFrame Bufferに入れれば、そのまま表示できるからです。背景を設定したら、背景をレンダリングし、コンテンツをレンダリングし、ブレンド後に角丸処理を行い、Frame Bufferに投入して表示する必要があります。同じレイヤーの下に複数のレイヤーがあるため、角丸カットはミキシング操作をしてからカットする必要があり、上記の例から、ImageViewは実際には背景、コンテンツを持っていることがわかります。backgroundColorが設定されていない場合、背景をレンダリングする必要はなく、cornerRadiusの操作に基づいてコンテンツが角丸になり、ライン上のフレームバッファに送信されます。これはまた、デフォルトでは、メモリの最適化であり、唯一の同じレイヤーマルチレイヤーの下で発生したときに、直接スクリーンバッファに提出されたディスプレイの融合を扱うことができない、オフスクリーンレンダリングを生成します、対応するアルゴリズムでOffScreenバッファ、OffScreenバッファを開きます。

オフスクリーンレンダリングのトリガー

  1. レイヤーのマスクを使用します。
  2. レイヤーの masksToBounds、clipsToBounds を使用します。
  3. レイヤーに投影を追加します。
  4. テキストが描かれたレイヤー。
  5. 透明度が1でないグループの透明度を設定します。透明度が1でないため、ピクセルポイントカラーの混合操作は、異なる透明度を持つこれらのレイヤーがレンダリングされ、さらなる操作のためにスクリーンバッファに送信され、最終的に表示のためにフレームバッファに送信されるまで待つ必要があります。
  6. ラスタライズlayer.shouldRasterize

shouldRasterizeの使用に関する推奨事項:

  • レイヤーを多重化できない場合は、ラスタライズをオンにする必要はありません。
  • レイヤーが静的でなく、アニメーションの途中など頻繁に変更する必要がある場合、オフスクリーンレンダリングをオンにすると効率に影響します。
  • キャッシュされたコンテンツのオフスクリーンレンダリングには時間制限があり、キャッシュされたコンテンツが100ミリ秒使用されないと破棄され、再利用できなくなります。
  • 画面外のレンダリングスペースは、画面ピクセルの2.5倍までに制限されており、それを超えるとキャッシュされません。

修正方法

オフスクリーンレンダリングのパフォーマンス問題が最適化されました:iOS 9.0 UImageViewとUIButtonは、角丸を設定するとオフスクリーンレンダリングをトリガーします。iOS 9.0 以降では、UIButton は角丸を設定するとオフスクリーンレンダリングをトリガします。一方、UIImageView は png イメージに角丸を設定してもオフスクリーンレンダリングをトリガしませんが、他のシャドウ効果を設定するとオフスクリーンレンダリングをトリガします。

maskToBounds/clipsToBoundsimageViewなどのレイヤーには使用しないでください。

 imageView.clipsToBounds = YES;
 imageView.layer.cornerRadius = 50.f;

ベジェ曲線を使った円のプロット

[[UIBezierPath bezierPathWithRoundedRect:imageView.boundscornerRadius:imageView.frame.size.width]addClip];
[imageView drawRect:imageView.bounds];
imageView.image=UIGraphicsGetImageFromCurrentImageContext();
//図面終了
UIGraphicsEndImageContext();
[self.view addSubview:imageView];

CAShapeLayerとUIBezierPathによる角丸の設定

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(, )];
imageView.image = [UIImage imageNamed:@"myImg"];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
//サイズを設定する
maskLayer.frame = imageView.bounds;
//グラフィックのルックを設定する
maskLayer.path = maskPath.CGPath;
imageView.layer.mask = maskLayer;
[self.view addSubview:imageView];

あなたはCAShapeLayerはCALayerのサブクラスであることを知っていることができ、あなたはCALayerのすべてのプロパティを使用することができますが、唯一のUIBezierPathで動作します、CAShapeLayerを使用して(CoreAnimationに属する)とベジエ曲線は、ビューのdrawRectメソッドで描画せずに実現することができます。目的のグラフィックスのいくつかは、携帯電話のGPUに直接レンダリングCAShapeLayerアニメーションは、CPUレンダリングを使用してdrawRectメソッドのビューに比べて、その効率は非常に高く、大幅にメモリ使用量を最適化することができます。

シャドウについては、レイヤーが単純な幾何学的形状や丸みを帯びた形状である場合、shadowPathを設定することでパフォーマンスを最適化することができ、パフォーマンスを劇的に向上させることができます。

imageView.layer.shadowColor=[UIColorgrayColor].CGColor;
imageView.layer.shadowOpacity=1.0;
imageView.layer.shadowRadius=2.0;
UIBezierPath *path=[UIBezierPathbezierPathWithRect:imageView.frame];
imageView.layer.shadowPath=path.CGPath;

YYImageオープンソースライブラリは、imageViewも角丸を研究することができます。

オフスクリーンレンダリングは本当に無駄なのか?

オフスクリーンレンダリング オフスクリーンレンダリングは、多くの余分なオーバーヘッドを引き起こしますが、無駄ではありません。オフスクリーンレンダリングが発生するのは、開発者の注意をパフォーマンスに向けさせ、不要な透過ビューのレイヤーを減らすためです。

現在のディスプレイでオフスクリーンレンダリングが発生したかどうかを確認する方法

シミュレータメニューのデバッグモードで開きます。Color Off-Screen Rendered

Read next

DOMイベントの仕組み|イベント・デリゲート

ドキュメント・オブジェクト・モデルは、ウェブページとスクリプトを他のプログラミング言語とリンクします。 言い換えると、DOM イベントにはブラウザ内部のイベントと、ブラウザがユーザーとやりとりする際に発生するイベントの両方が含まれます。一般的なイベントの種類は、リソースイベント|ウェブイベント|フォーカスイベント|CSSアニメーションイベント|フォームイベント|キーボードイベント|マウスイベントなどです。 JavaScrip...

Jul 4, 2020 · 2 min read