【Android】SurfaceFlingerの5つの法則

SurfaceFlinger は、Android 分野全体のほぼすべての知識を網羅しています。HAL ハードウェア抽象化層からフレームワーク層まで、CPU 描画から OpenGL やその他のハードウェア描画まで。

SurfaceFlinger は、Android オペレーティング システムの重要なコンポーネントであり、すべてのグラフィカル インターフェイス (Surface) の表面の管理とレンダリングを担当します。個々のアプリケーションの画像を合成、拡大縮小、ブレンドすることで画面に描画します。SurfaceFlinger は、ウィンドウ管理、アニメーション効果、ハードウェア アクセラレーションなどの機能を処理して、スムーズなユーザー インターフェイス エクスペリエンスを保証します。

SurfaceFlinger のレンダリングの第一法則:

SurfaceFlinger は、Android システム全体のレンダリングの中核となるプロセスです。すべてのアプリケーション レンダリング ロジックは最終的に処理のために SurfaceFlinger に送られ、最終的に処理された画像データは描画のために CPU または GPU に渡されます。

この文を Android レンダリング システムの第一法則として考えてみましょう。Android システム全体において、SurfaceFlinger はレンダリングの役割を果たしませんが、プリミティブなスローマシンとして、すべてのアプリケーションプロセスから渡されるプリミティブデータを処理した後、実際の描画のために CPU と GPU に引き渡されます。

SurfaceFlinger のレンダリングの第 2 法則:

各アプリケーションでは、Surface がプリミティブ データを SurfaceFlinger サーバーに転送するためのプリミティブ転送ユニットとして使用されます。

これは Android レンダリング システムの第 2 法則です。これら 2 つの法則を組み合わせると、次の簡単な図になります。
SurfaceFlinger インタラクション設計図.png

SurfaceFlinger のレンダリングの第 3 法則:

SurfaceFlinger はプロデューサーとコンシューマーを中心的な設計アイデアとして採用し、各アプリケーション プロセスをプロデューサーとして保存して、SurfaceFlinger のプリミティブ キューにプリミティブを生成し、SurfaceFlinger はコンシューマーとして、特定のルールに従ってプロデューサーを SurfaceFlinger のキューに保存します。

グラフで表すと以下のようになります。

原始的な消費の中心原則.png

SurfaceFlinger システム レンダリングの第 4 法則:

大容量のメタデータをプロセス間で転送できるようにするため、メタデータを SurfaceFlinger に転送して処理するツールとして匿名共有メモリが使用されます。

ご存知のとおり、メタデータをアプリケーション プロセスから SurfaceFlinger プロセスに転送して処理する必要があるため、ソケットなどのプロセス間通信が必要になります。これは、それ自体の効率性とデータの 2 つのコピー (物理メモリ ページ レベルの観点から) を考慮すると、実際には良い選択ではありません。大量のデータをコピーすること自体が問題です。では、その一回限りのプロセス間通信が必要になると思いますが、真っ先に思い浮かぶのはもちろんBinderですが、Binderのプロセス間通信は、特にアプリケーション内の通信データ量の合計が1M未満の場合、他の通信アプリケーションと同様に不足する問題が必ず出てきます。

この問題を解決するために、Android は匿名共有メモリ (Ashmem) を使用して共有メモリを使用します。匿名共有メモリもコピーワンスのプロセス間通信方式であり、その核心はバインダーの複雑な mmap よりも Linux 共有メモリの概念に近いです。
アシュメム.png

SurfaceFlinger システム レンダリングの第 5 法則:

SurfaceFlinger の下部には、ハードウェア割り込み、またはタイミング呼び出しをトリガーするソフトウェア シミュレーションから常にループしているタイム クロックがあり、時々、SurfaceFlinger のグラフィックス要素キューが CPU/GPU を通じて画面上に描画されます。

第 5 法則の誕生は、実際には Android システムの設計と一致しています。Android アプリケーションには、SurfaceFlinger にレンダリング モードを通知する方法が必要であることに加えて、もちろん、SurfaceFlinger は画面にプリミティブを継続的に描画し、自身の動作をコールバックする必要があります。SurfaceFlinger 自体は、常に SurfaceFlinger にプリミティブ データを描画します。
SurfaceFlinger Vsync.png

その中でもEventThreadは非常に重要な役割を果たしており、SurfaceFlingerにおける設計は大まかに以下のようなものとなっています。

イベントスレッド.png

垂直同期の概要

新しいランキング VSync があります。実は、これはゲームをプレイするときによく言う垂直同期信号です。

ここではまず、UI エクスペリエンスを向上させるための Android の反復的な取り組みである Butter プロジェクトを紹介します。システムの UI をバターの表面のように滑らかにするために、バター プロジェクトは Siwei と名付けられました。このため、Vsync とトリプル バッファという 2 つの重要な概念、つまり垂直信号とトリプル バッファリングが生まれました。

ダブルバッファリングとは、最初のフレームのレンダリング中に 2 番目のフレームのコンテンツがすでに描画されており、2 番目のフレームの描画後に表示されることを意味します。これを行うことの利点は明白で、あるフレームを描画してから次のフレームの描画を開始すると、必然的に計算処理が発生し、UI インタラクションが遅くなります。
ダブルバッファリング.png

このように、前のフレームを表示する際に、あらかじめ次のフレームのプリミティブを描画し、後ろに置いて入れ替えの機会を待つと、感覚的にスムーズになります。

とても理想的ですが、前後2枠を交換するタイミングをどうやって見つけるかが問題です。誰かが考えている場合は、画面のリフレッシュ レートに従い、一般的に 60 fps の一般的な画面のリフレッシュ レートに従います。つまり、約 16 ミリ秒に 1 回リフレッシュします。

実際、このプロセスには 2 つの変数があり、1 つは描画速度、もう 1 つは表示速度です。描画速度でもCPUとGPUの描画速度に分かれます。

ここでは引き続きGoogleがバター計画を推進していた頃の模式図を使います。まず、バッファリングなしの通常の動作の概略図を見てみましょう。

描画_vsync.png

最良の状況は上の写真で、0 番目のフレームが表示されると、CPU/GPU は 16ms 以内に 1 番目のフレームを合成して描画し、vsync 信号が来ると 1 番目のフレームをディスプレイにスワップして表示します。

仮想同期とは何ですか? ゲームをプレイしているときによく見かける垂直同期です。その機能は、画面ハードウェア割り込みを通じて画面をいつ更新するかをシステムに伝えることです。このようにして、システムをリフレッシュするために割り込みを送信するのに約 16 ミリ秒かかります。

ただし、CPU が多忙のため、1 フレーム目を表示した時点で 2 フレーム目をレンダリングする時間がなく、SurfaceFlinger が Vsync 信号を受信して​​も、レンダリングされた 1 フレーム目しか取り出して画面に表示できない、という状況が発生する可能性が高くなります。これは、Google 開発チームがジャンクと呼ぶ最初のフレームを繰り返します。

ジャンク.png

最初のフレームが表示されるのは、2 番目のフレームの準備ができていないためです。そのため、最初のフレームは繰り返し表示することしかできないことがわかります。

複数のバッファーを使用した動作原理のプロセスを見てみましょう。

ダブルバッファ.png

このとき、単純に1フレーム目と2フレーム目ではなく、AバッファとBバッファに分割されていることがわかります。通常の状況では、A バッファの内容が最初に表示され、同時に B バッファが準備されていることがわかります。すべてが正常な場合、B バッファは次の vsync の前に準備ができている必要があります。vsync が到着すると、B バッファが表示され、A バッファはバックグラウンドに戻って描画を続行します。

では、このメソッドでジャンクが発生するとどうなるでしょうか?

ダブルジャンク.png

ダブルバッファリングであれば問題ないようですが、一度ジャンクが発生すると表示がジャンク表示になり続けます。バッファ A を表示中にバッファ B の準備時間が 16ms を超えた場合、バッファ A が繰り返し表示され、b が表示されるときに A も準備時間が 16ms 未満になる場合があり、描画が完了せず、バッファ B の内容のみを繰り返し表示できます。

この方法はさらに危険であり、この問題を解決するために、Google はトリプル バッファリングを導入しました。

トリプルバッファリングがジャンクを処理するときの原理的なフローチャートは次のとおりです。

トリプルバッファ.png

後続のチェーン エラーを回避するために、トリプル バッファリングの導入により、アイドル待機時間により多くの処理が実行できるようになっていることがわかります。ダブル バッファリングでジャンクが発生した後と同様に、B バッファの CPU+GPU 時間が次の vsync 時間を超えると、CPU と GPU は一定期間何もすることがないことがわかり、次の Vsync が到着するのを待っているだけで、システム全体の背後の描画にジャンクの連鎖が発生します。

3 つのバッファの出現により、A バッファが繰り返し表示されると、CPU はただ待つだけでなく、C バッファのプリミティブを準備してから、C バッファに接続できるようになります。Google がトリプル バッファーと呼んでいるのはここから来ています。

ただし、ほとんどの場合、バッファリング戦略は SurfaceFlinger システム自体によって決定され、一般にダブル バッファリングおよびトリプル バッファリングと呼ばれます。

実はこの方法はオーディオやビデオの編集を最適化するためにも利用でき、一般的に使われているバッファ設計はここと似ていますが、これほど極端なシステムはありません。システムの videoView ソース コードを読んだことがあれば、NullPlayer は基本的に Surface プリミティブ バッファーを使用して究極のエクスペリエンスを実現していることがわかりますが、VideoView にも無理な設計があることがわかります。Android レンダリング システムを学習した後、これらのソース コードを分析してみましょう。

しかし、この部分の知識だけでは法則 5 を理解するのに十分ではありません。実際、ハードウェア/ソフトウェアから Vsync が発生するたびに、Dispsync は SurfaceFlinger とアプリに通知しようとします。これはまったく問題ありませんが、後者の Phase フェーズとは何でしょうか?

実はこれがシステムの巧妙な設計なのですが、アプリとSurfaceFlingerに同時に通知したらどうなるでしょうか?

フェーズなしの競合.png

この時点でアプリがプリミティブを返しても、SurfaceFlinger がすでに更新合成描画動作を実行している場合 (SurfaceFlinger へのアプリの転送速度が SurfaceFlinger 自体が通知する速度よりも遅いはずなので、その可能性が非常に高いです)、ジャンクのような問題が発生し、次の vsync で現在のフレーム番号が表示されたままになるため、次の時間差が必要です。以下に示すように、最初にアプリに通知してから、SurfaceFlinger に通知します。

SurfaceFlinger と app.png の時間差

この理解を加えて第 5 法則を理解してください。5 点目の議論に関しては、Vsync 同期信号の原理について詳しく議論されています。

まとめ

これら 5 つの法則は、SurfaceFlinger の設計を導く中心的な考え方であり、Android 4.1 から 9.0 まで大きな変更はありません。これら 5 つの核となるアイデアを理解していれば、SurfaceFlinger を読むことの難易度は大幅に下がります。

それでは、SurfaceFlinger システムは、前に話した Skia とどのような関係があるのでしょうか? それはトップレベルのビューの描画プロセスとどのような関係があるのでしょうか?

役割別に分けてみましょう。

framework面向开发者所有的View是便于开发的控件,里面仅仅只是提供了当前View各种属性以及功能。
而Android底层的Skia是Android对于屏幕上的画笔,经过View绘制流程的onDraw方法回调,把需要绘制的东西通过Skia绘制成像素图元保存起来
SurfaceFlinger则是最后接受Skia的绘制结果,最后绘制到屏幕上。

したがって、Skia が Android レンダリングの中核であることは事実ですが、最終的には Skia によって提供され、そのシステムが完全な Android レンダリング システムになる必要があります。

このシールド層の後は、開発者は Android の基盤となるレンダリング システムを理解する必要がなく、良好な結果を引き出すこともできます。
Android レンダリング プロセス.png

最後に描画結果が画面に転送されます。

そこで今回の計画では、Androidレンダリングシステム全体を徹底的に読み込むために、最下層のコアからViewの描画処理までをゆっくり解析していきます。
プラン

この計画の SurfaceFlinger の記事は、次のモジュールを通じて 1 つずつ分析されます (ただし、モジュールに記事が 1 つだけあるという意味ではなく、最終的な順序を意味するものでもありません。単に読む内容を意味します)。

グラフィックス コア転送ツール、匿名共有メモリ ashmem ドライバーの中心原理、ashmem の概略図は次のとおりです。

ここに画像の説明を挿入

詳細については、匿名メモリ ashmem ソース コード分析を参照してください。ただし、Android の上位バージョンでは、ashemem は廃止され、代わりに ion ドライバーが使用されます。イオンの概略図は次のとおりです。
GraphicBuffer と ion.png

イオンの解析については、イオンドライバーのソースコード解析を参照してください。

実際には、メモリに直接アクセスするために DMA を生成します。元の ashmem メソッドでは、GPU から CPU、そしてメモリ内のアドレスにアクセスする必要があります。ただし、ここでは GPU が DMA に直接アクセスして変更することになり、CPU も DMA を直接変更できます。これが最大の変化です。

SurfaceFlinger を起動します。
詳細については、SurfaceFlinger の初期化を参照してください。概略図は次のとおりです。
ここに画像の説明を挿入

    开机没有Activity,只能直接使用SurfaceFlinger机制加上OpenGL es显示开机动画,来看看从linux开机动画到Android开机动画 BootAnimation 。
    详见系统启动动画,原理图大致如下:

ここに画像の説明を挿入

    理解应用进程如何和SurfaceFlinger构建起联系。
    详见Vsync同步信号原理。SurfaceFlinger是通过一个名为Choreographer监听VSync进而得知绘制周期的。原理图大致如下:

ここに画像の説明を挿入

    SurfaceFlinger硬件抽象层hal的理解和运作,理解SurfaceFlinger如何和底层HWC/fb驱动关联起来。

詳細については、「SurfaceFlinger の HAL 層の初期化」を参照してください。
コア データ構造は次のとおりです。
ここに画像の説明を挿入

基礎となるハードウェア コールバックと SurfaceFlinger の間の関連付けの概略図は次のとおりです。

ComposerCallback.png

    SurfaceFlinger是如何连通DisplayManagerService[略,之后有机会进行补充],只是简单的通过SurfaceFlinger获取屏幕信息放在Framework层管理。
    Android端在opengl es的核心原理,看看Android对opengl es上做了什么封装。
    这个模块分为两部分解析:
    一个是正常的OpenGL es使用流程中,软件模拟每一个关键步骤的工作原理是什么,Android在其中进行了什么优化。详见OpenGL es上的封装(上)
    其中有一个十分关键的数据结构,UML图如下:

ここに画像の説明を挿入

OpenGL es でテクスチャがどのように合成および描画されるか、Android はローカル テクスチャを最適化しています。詳細については、OpenGL es のパッケージ (下記) を参照してください。OpenGL es 全体の描画原理は次のとおりです。
ここに画像の説明を挿入

    图元是怎么通过hal层生产出图元数据;应用的图元数据又是获取到应用,如何进入SurfaceFlinger的缓冲队列。
    详见GraphicBuffer的诞生。其中涉及了几个重要的数据结构:

ここに画像の説明を挿入

同時動作の模式図は以下の通りです。
ここに画像の説明を挿入
GraphicBufferが誕生して使えるようになります

    应用的图元数据是如何消费的。
    详见图元的消费,交换缓冲绘制参数,本质是取出一个GraphicBuffer存到缓冲队列的时间和当前时间预计显示最接近的一个,渲染到屏幕中。同时把上一帧的GraphicBuffer放到空闲队列中。

その中で、SurfaceFlinger のバッファ キュー設計の次のデータ構造を覚えておく必要があります。
ここに画像の説明を挿入

レイヤとバッファキューの設計

    SurfaceFlinger是如何通过HWC合成图层,如何合并各个Layer,输出到opengles中处理。
    大致上可以分为如下如下7步骤:
    1.preComposition 预处理合成
    2.rebuildLayerStacks 重新构建Layer栈
    3.setUpHWComposer HWC的渲染或者准备
    这三步骤,我称为绘制准备,详见图元的合成(上) 绘制的准备
    在绘制准备的过程中,最重要的是区分了如下几种绘制模式,已经存储相关的数据到HWC的Hal层中。
コンポジションのレイヤーのタイプ hasClientComposition hasDeviceComposition レンダリング方法
HWC2::構成::クライアント 真実 - OpenGLは
HWC2::構成::デバイス - 真実 HWC
HWC2::Composition::SolidColor - 真実 HWC
HWC2::構成::側波帯 - 真実 HWC または OpenGL

4.doDebugFlashRegions デバッグ描画モードをオンにします。
5.doTracing トレース印刷
6.doComposition 複合プリミティブ
7.postComposition vysnc などの複合プリミティブの仕上げ作業。

次の 4 つのステップでは、最後の 2 つのステップだけに注目する必要があります。詳細については、プリミティブの合成 (下記) を参照してください。

消費から合成までの一連のプロセスの概略図はおおよそ次のとおりです。
ここに画像の説明を挿入

SurfaceFlinger のプリミティブ合成

合成過程ではHWCとOpenGL esの2種類に分かれており、両者の役割は大まかに以下の通りです。
ここに画像の説明を挿入

SurfaceFlinger の原始的な合成デザイン
もちろん、Android レンダリング システムには、プロデューサーとコンシューマーのペアだけが存在するわけではありません。
ここに画像の説明を挿入

SurfaceFlinger のすべての生産消費者.png

SurfaceFlinger の Vsync 原理と位相差計算原理
VSync 送信全体には 3 つの送信サイクルがあります。ハードウェアが VSync サイクルを送信し、ソフトウェアが VSync サイクルを送信し、アプリが VSync サイクルを処理し、SurfaceFlinger が VSync サイクルを処理します。
詳細については、「Vsync 同期信号の原理」を参照してください。

便宜上、Android は一時的にサイクル全体をサイクルの連続性の関数としてみなします。計算原理は次のとおりです。
ここに画像の説明を挿入

角度を計算する

実際には、各サンプリング点の位相を求め、そのサンプリング点の位相の平均値を理想的な位相として計算することになります。同様に、周期は、VSync 軸を送信するための適切なソフトウェアを計算するために、サンプリング ポイントを計算するための平均周期でもあります。

最後に、ソフトウェア レンダリングに基づいて、アプリの VSync と SurfaceFlinger の VSync はそれぞれ遅延受け入れ処理を実行して、定期的なタイミングの競合を回避します (上の青い図)。

SurfaceFlinger のフェンス同期ゲートの動作原理については、
フェンスの原理で詳しく
説明されています。フェンスを理解するには、GraphicBuffer の状態変化を理解する必要があります。大まかに次の
状態に分けられます: デキュー (アプリケーションで描画するためにキューから外される)、キュー (消費を待つために SurfaceFlinger バッファに入る)、取得 (レンダリング用の GraphicBuffer を選択する)、解放 (消費後のデキューを待つ)
ここに画像の説明を挿入

    GraphicBuffer状态流转

Fence の状態はより単純で、取得、解放、取得された状態の流れはおおよそ次のようになります。
ここに画像の説明を挿入

フェンス改造フローチャート

リトライは描画されるたびに未使用のフェンスに記録されます。

要約すると、Fence の取得状態は実際に、いつデータを消費して画面にレンダリングできるかをブロックしていますが、Fence のリリース状態は、いつ描画のためにアプリケーションにデキューできるか、いつメモリにマップできるかを制御します。

この 12 のポイントを理解するだけでは、SurfaceFlinger を理解しているとは言えませんし、熟練したとは言えません。

おすすめ

転載: blog.csdn.net/weixin_43233219/article/details/131634530