Open5

C-WebGL: ESSLシェーダをVulkanのGLSLに変換したい

okuokuokuoku

やってみた方が早いんじゃないかということで。。

okuokuokuoku

実際に手で書き換えてみた

(元コードは https://github.com/KhronosGroup/WebGL/blob/master/conformance-suites/1.0.3/conformance/glsl/bugs/conditional-discard-in-loop.html )

diff: https://gist.github.com/okuoku/bad334177f4966463a21b60cd7356b07/revisions#diff-4c2152da119b4759e2551dcd3313b4d6e08466b0e7c189741838237331dce82b

実際の変更は:

  1. #version 450 core を設定する (ANGLEの該当箇所)
  2. gl_FragColor は専用の out を定義しgl_ で始まる名前はユーザが使えないのでwebgl_ にしておく (ANGLEの該当箇所)
  3. attributeinvaryingin (フラグメントシェーダ) か out (バーテックスシェーダ)にする
  4. texture2Dtexture にする
  5. 基本型の uniform は1つのUBOにまとめる
  6. 入出力に layout を指定する

3 と 4 は WebGL2 fundamentalsにシェーダの移行方法として説明がある 。 5 と 6 はVulkanの要請。

というわけで、

  1. 入出力の列挙
  2. texture2dtextureCube あたりの変換
  3. レイアウトの生成

あたりさえ処理してしまえば簡単に変換できてしまうように見える。 ...本当か。。?

okuokuokuoku

AST を鑑賞する

とりあえず、glslangのASTを変換してやればよさそうなので、元々のASTを観察してみることにする。

$ ./glslangValidator.exe -i orig.frag
orig.frag
ERROR: 0:1: 'float' : type requires declaration of default precision qualifier
ERROR: 0:1: 'TEXEL_COUNT_V' : variables with qualifier 'const' must be initialized
ERROR: 0:1: '' : compilation terminated
ERROR: 3 compilation errors.  No code generated.

Shader version: 100
ERROR: node is still EOpNull!
0:?   Linker Objects
0:?     'TEXEL_COUNT_V' ( temp mediump float)

... 元のもバリデータ通らないじゃないか。。 -r オプションでこの辺のチェックは省略できる

  -r | --relaxed-errors              relaxed GLSL semantic error-checking mode

出力結果: https://gist.github.com/okuoku/bad334177f4966463a21b60cd7356b07#file-out_orig-ast-txt

例えば、

    // Set initial color
    gl_FragColor = BLUE;

の行は、

0:27      move second child to first child ( temp mediump 4-component vector of float)
0:27        'gl_FragColor' ( fragColor mediump 4-component vector of float FragColor)
0:27        Constant:
0:27          0.000000
0:27          0.000000
0:27          1.000000
0:27          1.000000

のようにダンプされる。

okuokuokuoku

複雑なシェーダを手で変換してみる

https://threejs.org/examples/#webgl_loader_gltf_extensions

今回はthreejsのglTF extensions sampleで使われている、glTF標準PBRシェーダを変換してみることにした。

https://gist.github.com/okuoku/89d387d661c0af1ce623357a81e6992b/revisions

Gistって過去の変更にリンク貼れないのか。。

解決方法がわからないのが2点。

  1. diffuse のようにリネームすべき識別子が関数パラメタ等としても使われている場合にどうするのか 。glslang側に識別子のリネーム機能とかないかな。。Schemeで言うところのマクロの健全性問題だ。
  2. gl_FrontFacing のような、頂点シェーダじゃない出力変数をどうやってバインドするのか 。これはVulkanをちゃんと見ないとダメだな。。

あと、

https://armkeil.blob.core.windows.net/developer/Files/pdf/graphics-and-multimedia/Porting_to_Vulkan.pdf

Push constants

  • replace non-opaque uniforms
    -Think of them as small, fast-access uniform buffer memory

と有るし本来GLで言うところの uniform はVulkan的な意味のpush constantsにしたい(実際、push constantsはシェーダ側のレジスタにマップされるので実装的にも近いはず)が、Vulkanの最低保証サイズが128bytesでGL側の最低保証サイズ(128 floats)より小さいので使えない可能性がある。