9月24日、Figmaが「Figma Rendering: Powered by WebGPU」と題した記事を公開した。この記事では、Figmaが長年利用してきたWebGLベースのレンダリングから、次世代グラフィックスAPIであるWebGPUへの移行と、その背景にある技術的な課題や最適化の工夫について詳しく紹介されている。以下に、その内容を紹介する。

WebGLからWebGPUへ
Figmaは2015年のローンチ以来、WebGLを活用してブラウザ上で無限キャンバスを実現してきた。しかしWebGLはグローバルステート依存やエラーハンドリングの不明確さといった制約を抱えていた。2023年、ChromiumがWebGPUをサポートしたことで、Figmaは計算シェーダーや効率的なエラー処理といった新たな最適化を実現できる環境を得た。
注釈
- WebGL:ブラウザで動作するグラフィックスAPI。2D/3D描画をJavaScriptから行える。
- WebGPU:WebGLの後継として開発された次世代API。GPUの性能をより直接的に活用でき、高度な並列処理や効率的なエラーハンドリングが可能。
グラフィックスインターフェースの刷新
描画呼び出し引数の明示化
従来のWebGL的なインターフェースはグローバルバインディングに依存していたため、更新漏れによる不具合が発生しやすかった。これを解消するため、Figmaは引数としてすべてのリソースを明示的に指定する新しいAPIを導入した。
// 従来
context->bindVertexBuffer(vertexBuffer, ...);
context->bindTextureUniform(texture, ...);
context->bindMaterial(material, ...);
context->bindFramebuffer(framebuffer, ...);
context->draw();
// 改良後
context->draw(vertexBuffer, framebuffer, {texture}, material, …);
この変更はWebGPU的な設計に近づけると同時に、WebGL上でも既存のバグを解消する効果をもたらした。
シェーダー処理
WebGLはGLSL、WebGPUはWGSLという異なる言語でシェーダーを記述する。Figmaは既存の古いGLSLシェーダーを維持しつつ、独自のシェーダープロセッサを開発。これによりGLSLからWGSLへの変換を自動化し、naga
ツールと組み合わせて両形式の同時運用を可能にした。
注釈
- シェーダー:GPUで動作する小さなプログラム。ピクセルの色や形状を計算して画面に描画する役割を持つ。
- naga : シェーダーコードを別の形式に変換するRust製のオープンソースのコンパイラ/トランスパイラ
Uniformバッファ
WebGLではuniform(シェーダーに渡す変数)を個別に設定できるが、WebGPUではすべてをバッファにまとめて送る必要がある。Figmaは単純な移植による性能劣化を避けるため、複数の描画呼び出し命令をまとめてエンコードし、最後に一括送信する仕組みを導入した。
context->encodeDraw(uniformStructData, material1, ...);
context->encodeDraw(otherUniformStructData, material2, ...);
context->submit(); // submit時にまとめてアップロード
注釈
- uniform:シェーダーに渡す外部からの定数。色や変換行列などを指定するために使われる。
- バッファ:データを一時的に格納する領域。GPUにまとめてデータを送る際に利用される。
実装と移行
FigmaのレンダラーはC++で書かれており、Emscriptenを用いてWebAssemblyに変換してブラウザで利用される。また、サーバーサイドやネイティブ環境向けにはx64/arm64向けにコンパイルされる。WebGPU対応にあたり、Chromiumが採用する実装「Dawn」を統合し、Webとネイティブ双方で共通の基盤を利用できるようにした。
注釈
- **WebAssembly (Wasm)**:ブラウザ上で高速に動作するバイナリ形式。C++やRustなどで書いたコードを変換して実行できる。
- Emscripten:C/C++コードをWebAssemblyやJavaScriptに変換するためのツールチェーン。
- Dawn:Googleが開発するWebGPUの実装。Chromiumでも利用されている。
WebGPUは非同期エラーハンドリングや非同期ピクセル読み出しといった大きなAPIの違いを持つ。これらへの対応は開発チームにとって大きな設計上の挑戦となった。
ロールアウトと最適化
新しいバックエンドを導入した後、FigmaはWindows、Mac、ChromeOSなど複数の環境でベンチマークを実施し、パフォーマンス回帰が起きたシナリオを徹底的に調整した。バインドグループのキャッシュ化やレンダーパス単位でのバッチ処理など、最適化を重ねた結果、性能低下は発生せず、一部環境では顕著な改善が確認された。
特にWindows環境ではGPUやドライバの不具合が発生しやすく、WebGPUセッションの途中でデバイスを失うケースも報告された。これに対応するため、Figmaはセッション中にWebGPUからWebGLへ動的にフォールバックできる仕組みを導入した。
補足
- レンダーパス:描画命令をまとめてGPUに送信する単位。効率化のために複数の描画をまとめて処理できる。
- バインドグループ:シェーダーに渡すリソースのまとまり。WebGPUのリソース管理の基本単位。
WebGPUの未来
Figmaは今後、WebGPUを活用してさらなる描画最適化を計画している。たとえばコンピュートシェーダーを用いた高効率なぼかし処理や、MSAAによるアンチエイリアス改善、RenderBundlesによるCPUオーバーヘッド削減などだ。
補足
- コンピュートシェーダー:描画だけでなく、汎用的な計算処理をGPUで並列に実行できる仕組み。
- **MSAA (Multi-Sample Anti-Aliasing)**:ギザギザした線を滑らかに見せるための処理手法。
- RenderBundle:複数の描画命令を事前にまとめ、CPUからGPUへの命令送信を効率化する仕組み。
1年以上にわたる取り組みにより、FigmaはWebGPUを基盤とした新しいレンダリング時代の扉を開いたといえる。
詳細はFigma Rendering: Powered by WebGPUを参照していただきたい。