統合ターミナルのパフォーマンス改善
2017年10月3日 Daniel Imms, @Tyriar
Visual Studio Codeの次期バージョン1.17に向けて、統合ターミナルのレンダリングエンジンはパフォーマンスを念頭に置いて完全に書き直されました。このバージョンでは、DOMベースのレンダリングシステムからHTMLのcanvas要素を使用するシステムへと移行します。
DOMレンダリング
多少驚くかもしれませんが、静的ドキュメントの表示用に設計されたシステムで対話型ターミナルをレンダリングすることは可能でした。しかし、時間が経つにつれて、DOMが提供する特定の機能をオーバーライドしていくつかの問題を修正する必要があることがわかりました。
選択: ターミナルのユースケースをカバーするために、DOMの選択システムに逆らって多くの作業が行われました。常にDOMに表示されているものだけをレンダリングしていたため、選択を再実装せずに複数ページのコンテンツを選択することはできませんでした。スクロールすると選択が解除されることもありました。これらの問題を解決するために、カスタム選択ロジックが追加されました。
文字のずれ: 多くの等幅フォントが一部のUnicode文字に対して厳密に等幅ではないため、下の画像の右側のような状況が発生する可能性がありました。

これに対する回避策は、すべてのUnicode文字を固定幅のスパンで囲むことでしたが、これによりフレームのレンダリングにかかる時間が増加します。
過剰なガベージコレクション: ターミナルをレンダリングするために必要な要素の数が多いため、ガベージコレクタは頻繁にメモリをクリーンアップする必要があり、レンダリング時間を著しく押し下げることがよくありました。この問題を回避するためにオブジェクトプールが導入され、DOM要素をリサイクルできるようになりました。
パフォーマンス: これらの問題を解決しようとどんなに努力しても、パフォーマンスはレイアウトエンジンによって課せられるハードキャップによって常に制限されます。
レイアウトエンジンの回避
場合によっては、要素の構成とレイアウトだけで1フレーム(16.6ms)よりも時間がかかることがあり、ターミナルでスムーズな60フレーム/秒(FPS)を維持したい場合、これは許容できません。この解決策が、新しいキャンバスベースのレンダリングエンジンでした。
<canvas> HTML要素を使用すると、JavaScript APIを使用してグラフィックスとテキストを描画できます。
レンダリングレイヤー
「レンダリングレイヤー」として知られる多数のキャンバス要素が、ターミナルの異なる部分のレンダリングを簡素化するために使用されます。
現在のレイヤーは、順に次のとおりです。
- テキスト: 背景色と前景テキスト。このレイヤーは不透明です。
- 選択: マウスによる選択。
- リンク: リンクにマウスオーバーしたときのアンダーライン。
- カーソル: ターミナルのカーソル。
これらの部分をそれぞれ独立した小さなコンポーネントに分離することで、描画方法が大幅に簡素化されました。
変更された部分のみを描画
新しいレンダラーの重要な部分は、変更されたものだけを描画することです。これを行うために、セルの描画状態に関する最小限の情報を含むスリムな内部モデルが保持されます。この状態は、より高価な描画アクションが実行される前に、セルが変更する必要があるかどうかをすばやくチェックするために使用されます。テキストレイヤーの場合、このモデルには文字、テキストスタイル、前景色、背景色への参照が含まれます。
これは、何も変更されていない場合でも、行全体がDOMから削除され、再構築され、再追加されていた以前のレンダリングエンジンと比較されます。

上の画像の緑色の長方形は、再描画された領域を示しています。
テクスチャアトラス
テクスチャアトラスは、レンダリング時間をさらに短縮するために使用されます。舞台裏には、最も一般的なスタイルでデフォルトの背景色にすべてのASCII文字を含むImageBitmapがあります。
これらのスタイルのテキストを描画する場合、CanvasRenderingContext2D.fillTextへの通常の呼び出しの代わりにテクスチャアトラスが使用されます。ImageBitmapはGPU上に配置されているため、描画速度が大幅に向上します。

強制フレームスキップ
DOMでのレンダリング速度のため、パーサーが十分なCPU時間を確保するために余分なフレームをスキップする必要がありました。これによりコマンドの実行は以前よりも高速になりましたが、ターミナルを介して大量のデータがストリーミングされると、フレームレートが10 FPSを下回ることがありました。
新しいレンダラーでは、この制限が解除され、ターミナルで最大60 FPSを楽しむことができます。

結果
私たちのベンチマークでは、統合ターミナルが状況に応じて以前よりも約5〜45倍高速にレンダリングされることが測定されています。応答性とフレームレートの向上に気づかなくても、レンダリングが高速化することでバッテリー使用量も削減されます!このパフォーマンス改善を気に入っていただけると幸いです。数日中にはVS Codeバージョン1.17で利用可能になり、現在Insidersビルドでテストできます。
機能を追加した元のxterm.jsプルリクエストで、より詳細な情報を見ることもできます。
ハッピーコーディング!
Daniel Imms, VS Codeチームメンバー @Tyriar