https://chromium.googlesource.com/chromium/src/+/master/docs/how_cc_works.md
tl;dr
cc/は歴史的には不正確にChrome Compositorの意味であった。ccはChromeの唯一の構成機ではないし(たくさんある)、いまや構成機ですらない。danakjは代替案として"content collator"を提案している。
ccはui/compositorまたはAndroidコード経由でブラウザプロセス内部で組み込まれる。あるいはui/compositor経由でmusユーティリティプロセス内部で組み込まれる。Blink/RenderWidget経由でレンダプロセス内部でも組み込まれる。ccの任務はペイントされた入力を組込者から受け取り、それをディスプレイのどこに表示するかを決め、ラスタライズやデコード、アニメーションなどほどこしgpuテクスチャに変換し、コンポジタフレーム形状をしているディプレイコンポジタに転送する。またccはブサウザプロセス上でのピンチやスクロールジェスチャを入力として受け取りBlinkを巻き込むことなく処理する。
プロセス/スレッド構成
ccはシングルスレッドでもマルチスレッドでも組み込むことができる。シングルスレッドの場合はオーバーヘッドが少ない。マルチスレッドの場合は遅延コストが発生するが、入力やアニメーションをスレッドで動作させることができる。一般的に言って、ブラウザはメインスレッドが軽いのでシングルスレッドバージョンを使い、メインスレッド(Blink)が忙しいレンダラはマルチスレッドバージョンを使う。
どちらのバージョンでもcc::Schedulerを使って動かす。これはフレームをする出力するタイミングを決定する。1つの例外(1箇所でしか使われない第3のモード)はBlinkのレイアウトテストとsimテストであり、ここではスケジューラを使わずにccに同期的にコンポジットするタイミングを通知する(LayerTreeHost::Composite経由)。これは歴史的理由があり、テストのときにコントロールが効きやすいということもある。
コンテントデータの流れの概略
<図>
組込者とccのメインインターフェースはLayerTreeHost(様々なLayerTreeSettingsとともに作成される)とレイヤツリーである。レイヤはコンテントの矩形であり、それがどのように表示されるべきかを指定する様々なプロパティとともに存在する。ccはコンテントをペイントしたものをラスタライズされた表現(ソフトウェアビットマップまたはGPUテクスチャ)に変換し、その矩形をどこに表示するかを決定するのが仕事である。
ccはこのレイヤツリーをPropertyTreeBuilderをつかってプロパティツリーの集合に変換し、レイヤツリーを可視レイヤーの順序付きリストに単純化する。スリミングペイントプロジェクトの一部として、Blinkはプロパティツリーとレイヤリストを歴史的なレイヤツリーインタフェースを経由せずに直接設定しパイプラインを省く。
コミットプロセスにおいて、ccはメインスレッドのデータ構造の入力すべてをコンポジタスレッドデータへ変換する。この時点において、ccはそれぞれのレイヤのどの部分が可視であるかを決定しイメージのデコードとラスタを実行する。コンテントのすべてがスクリーンに表示する用意ができたら、ccはコミットされたツリーを実行し、そこから「描画」ができる。
ccは不幸にもいまだに多くの箇所で「描画」や「スワップ」という言葉を使っている。実際にこの言葉の意味していることをしてはいないにも関わらずである。ここでいう「描画」は多くのクワッドとレンダパスを含むコンポジタフレームを構築することである。「スワップ」はCompositorFrameSinkを経由してフレームをディスプレイコンポジタへ送ることである。これらのフレームはvizのSurfaceAggregatorに送られ、作成されたフレームが全て統合される。
入力データフローの概略
ccへの入力で他の主要なものはマウスクリックやホイール、タッチジェスチャーなどのユーザからの入力である。レンダプロセスにおいて、入力はブラウザプロセスから転送される。ui::InputHandlerProxy(cc::InputHanderClientnのひとつ)で処理される。
この入力のうちのいくつかはLayerTreeHostImple(cc:InputHandlerのひとつ)へ転送される。これによりアクティブレイヤのプロパティツリーやスクロールやピンチを必要に応じて修正できる。いくつかの入力はコンポジタスレッドでは処理できない(Javascriptの同期のタッチやホイールのハンドラなど)ので入力はBlinkに沿って転送される。この入力の流れは上記のコンテントデータフローとは逆のパスになる。
コミットフロー
コミットはメインスレッドからコンポジタスレッドへのアトミックなデータ取得である。(シングルスレッドモードでもデータを正しい構造へ移動するためにこの操作は発生する。)IPCを送るのとは違い、コミットはメインスレッドをブロックしコピーすることで行う。
<図>
いくつかの方法でメインスレッドはコミットを要求できる。ほどんどのウェブページはrequestAnimationFrame経由でコミットを要求する。それはLayerTreeHostにおいてSetNeedsAnimateを呼び出す。さらに、ccの入力()の修正はLayerTreeHostのSetNeedsAnimate、SetNeedsUpdate、SetNeedsCommitを呼び出す。
Additionally, modifying any of cc’s inputs (e.g. a layer property, such as its transform or a change to the layer’s content), will call either SetNeedsAnimate, SetNeedsUpdate, or SetNeedsCommit on LayerTreeHost. The different SetNeeds functions allow for different levels of early-out aborts of the commit if no work is determined to be needed. (For example, if the requestAnimationFrame callback does no work, then there’s no need to do the commit or even update layers.) All of these functions request a BeginMainFrame from the scheduler, if not currently in the middle of servicing one.
At some point, the scheduler will respond with a ScheduledActionBeginMainFrame. This sends BeginFrameArgs from the compositor thread to the main thread to start a BeginMainFrame. BeginFrameArgs contain a time (for animation purposes) as well as any scroll deltas that have been applied on the compositor thread (mainly as a result of handling user scroll gestures) that Blink doesn’t know about. When Blink is embedding cc, a BeginMainFrame applies any compositor scroll deltas to Blink, kicks off requestAnimationFrame logic, and finishes the Blink half of the rendering lifecycle.
Once this is done, cc updates all layers. If at any point in this update pipeline, cc determines that no work left is required (e.g. a compositor thread scroll updates Blink, but Blink makes no changes to the page in response to that scroll), then it may abort the commit early. (Single-threaded cc never aborts commits, currently.) Once the embedder has finished its BeginMainFrame work and if the commit has not been aborted, then ProxyMain sends a synchronous NotifyReadyToCommit and blocks by forwarding a mutex to the compositor thread.
When the scheduler is ready to commit, it will respond with a ScheduledActionCommit. The ProxyImpl on the compositor thread then does all the work of copying the data from the main thread (while it is blocked) to compositor thread data structures. It then releases the mutex so that the main thread can proceed.
ProxyImpl is the only class that accesses data structures on both the main thread and the compositor thread. It only accesses the LayerTreeHost and Layers on the main thread when the main thread is blocked and enforces this through accessor DCHECKs. ProxyMain is its counterpart that exists on the main thread and is owned by the LayerTreeHost. For the single threaded case, SingleThreadProxy encompasses the tasks of both ProxyMain and ProxyImpl.