C-WebGL: ANGLEのVulkanバックエンドを見てみる会
em2nativeの次の目標としてビデオAPIの整備があるけど、HDRやVRRを良くサポートするためには、ローレベルなAPIを使用せざるを得ない。SDL2はちょっとターゲットが低くてこの辺をよく抽象化していない。
というわけで、WebGLをVulkanを使って直接実装するのを次の目標にしてみる。
ANGLEのドキュメント
Vulkanバックエンドはかなり資料が充実している。例えば線分描画アルゴリズムはVulkanとOpenGL ESで異なっているが、それをちゃんとアニメGIF( https://github.com/google/angle/blob/ea6dd8b31387fc1af8a9b71e316bbcc4e1440f64/src/libANGLE/renderer/vulkan/doc/img/LineRasterComparison.gif )で説明している -- Vulkanは直線が通ったピクセルを塗り潰すが、OpenGL ESでは ブレゼンハムのアルゴリズム なので、縦横どちらの方向でも2つ以上のピクセルを重ねることがない。
ESSL → GLSL 変換
※ ESSL = OpenGL ESのシェーダ言語、GLSL = Vulkanのシェーダ言語 -- OpenGLのシェーダ言語もあるが 今回は Vulkan固有方言 なのに注意
ANGLEはシェーダをVulkan用に変換するために
- ESSL → Vulkan互換のGLSL変換
- glslang フロントエンドを使用したSPIR-V中間表現への変換
の2ステップを取っている。より細かい内容は ShaderModuleCompilation.md にドキュメントされている。
ANGLEは前出の線分描画アルゴリズムの違いやGLES3に対応するためにかなり複雑な変換を導入しているが、WebGL1を実装するにあたってそこまでの精度は必要ないのである程度妥協すればそこそこ単純に変換できるのではないかと思う。
ASTレベル変換される要素
Vulkan向けのANGLEはglslangを内蔵するため、ANGLE本来のGLSL(= ESSL)実装とglslangのGLSL実装の2つのGLSLパーサを持つことになる。
実際の変換を担う TranslatorVulkan.cpp では、ANGLE側の実装を使ってASTレベルで変換した後、それを文字列に変換してからglslangに渡している。
変換は TranslatorVulkan::translateImpl
から開始される。
ShaderBuiltinsWorkaround
↑ このコミットで導入。WebGL1では配慮不要(ANGLE拡張なので)。
RemoveInactiveInterfaceVariables
謎。たぶん不要。
MonomorphizeUnsupportedFunctionsInVulkanGLSL
ESSL1でVulkanがサポートできないbuilt-inは存在しないはず。。というわけで配慮不要。
SeparateStructFromUniformDeclarations、RewriteStructSamplers
... これ以降もあんまり必要そうな変換が無いな。。