glsl-optimizer で手元の GLSL で書いたシェーダが高速になるか試してみました。
使うのはとても簡単でした。
ソースコードを落としてきて、コンパイルして、glsl_optimizer_lib-x64.libを作って、インクルードパスを通して、下記のような感じのコードを書いて、コンパイル時にglsl_optimizer_lib-x64.libをリンクするだけ。
#include <glsl/glsl_optimizer.h>
void LoadShader(const char* vertex_shader_path)
{
std::string resolved_vertex_shader_text;
resolved_vertex_shader_text = シェーダのソースコード読み込み;
glslopt_target target_version = kGlslTargetOpenGLES30;
glslopt_ctx* ctx = glslopt_initialize(target_version);
uint options = 0;
glslopt_shader* vertex_shader = glslopt_optimize(ctx, kGlslOptShaderVertex, resolved_vertex_shader_text.c_str(), options);
if (!glslopt_get_status(vertex_shader))
{
printf("error: %s", glslopt_get_log(vertex_shader));
glslopt_shader_delete(vertex_shader);
glslopt_cleanup(ctx);
return;
}
resolved_vertex_shader_text = glslopt_get_output(vertex_shader);
glslopt_shader_delete(vertex_shader);
resolved_vertex_shader_textからシェーダコンパイル;
glslopt_cleanup(ctx);
}
手元にあるシェーダをひと通り最適化してみた感想。
- Windowsでついていたテストコードのコンパイルは通らなかったが、使い方はとても簡単だった
- サポートしているのがGLSL 1.2、GLES 2.0、GLES 3.0だけなのがきつい
- switch が正しく変換されなくてコンパイルできないコードになるので、switchは使えなくなる
- ユニフォームブロックがユニフォーム変数に変換されてしまうのでユニフォームブロックは使えなくなる
- 一部のシェーダはglslopt_optimizeで不正アクセスになってしまい最適化できない
- ちゃんと計測出来てないが、GPU時間はあまり速くなった感がなかった
という感じで、Unity で使われているという話から期待を膨らませていたのですが、残念ながら自分の期待していた結果は得られませんでした。
もともと、Unity で HLSL とかから GLSL に変換したコードが遅すぎるから、それをマシにするために使われている?とどこかに書いてあった気がします。 ある程度最適化を意識して自分で書いたソースコードをさらに最適化するような自分の目的とは違うので、あまり効果が目に見えなかったのかもしれません。
まぁ、簡単にオン、オフを切り替え出来るので、今後もシェーダが遅い場合はワンチャン glsl-optimizer で速くなることを期待して、計測しながら速くなったら有効にするような感じで使っていきたいと思います。