non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

GPUを使って、mrubyでのaobenchを更に速くした

おはようございます。先週は、次男のトビヒがひどくなり、奥さんが皮膚科に連れて行き、 その指示に従い、自分が、毎日次男の患部に薬をつけ、包帯を巻いていました。 それが、長男にもうつった疑惑があり、週の後半は長男もプール見学させてました。 kjunichiです。

背景

aobenchの高速化にあたり、julialangでマルチプロセス化するも、パフォーマンス悪化、そこでmruby-aobench-nativeを作った。 折角なのでと、pthread使ってマルチスレッド化を試みるも、これまた、思うようなパフォーマンスが出なかった。 何とかしたい!

GPUのちからを借り、mruby-glslを作った。

f:id:kjw_junichi:20160809072340p:plain

mruby-glslとは

GLSLをmrubyのヒアドキュメントに書いて、これのレンダリング結果をバイナリ形式のppmデータとして 取得できるmrbgem。

そこそこの演算が必要になる画像データをGLSLによりGPUの高速な演算能力を利用して高速に取得可能となる。

ほんとに速いのか?

aobenchで比較

time bin/mruby benchmark/bm_ao_render.rb >ba.ppm

real    7m16.417s
user    7m10.905s
sys 0m2.536s

出力画像サイズを256x256に変更して実行。

  • 先日のmruby-aobench-native
  • OSX
time bin/mruby aon.rb > aon.ppm

real    0m2.991s
user    0m2.960s
sys 0m0.019s
  • 今回のmruby-glsl
  • OSX
time bin/mruby aoglsl.rb >aoglsl.ppm

real    0m1.011s
user    0m0.074s
sys 0m0.056s

CPU実行に比べて、速くなった。

mruby-glslを通して学べたこと

インスタンス変数の取得

rubyで定義したクラスの中のインスタンス変数にCからアクセスする。

mrb_intern_litでインスタンス変数名をmrubyのシンボル型に変換して、 これをmrb_iv_getに指定することで、インスタンス変数が取得出来た。

mrb_value shader;
shader = mrb_iv_get(mrb, obj, mrb_intern_lit(mrb, "@vertexShader"));

Cの文字列とmrubyの文字列の相互変換

mrubyからC

int len;
const char *source;

len = RSTRING_LEN(shader);
source = RSTRING_PTR(shader);

Cからmruby

int size;
const char *buf="hogefuga";
mrb_value mrbStr;

mrbStr = mrb_str_new(mrb, buf, stelen(buf));

snprintfの返り値がヤバい

書き込んだバイト数ではなく、書き込んだとしたら 何バイト使うかを返す。

ググって出てきたIBMサンプルが、paiza.ioで動かず、調査してわかった。 どうも、昔のsnprintfとC99あたりで規格ができてからのsnprintfは 挙動が違うものがあるのかも?

glReadPixelsでOpenGLの描画内容の取得

遅いと評判のglReadPixelsは大昔に使ったことがあるハズなので、 一旦これで実装してみた。

WindowsでMSVC++環境下での外部ライブラリを参照するmrbgemsの作りか

OSX以外でも試したく、Windowsにも対応してみた。

今回はWindows環境で、glfw3+Openglな描画環境でうごくコードが扱えた。

に成果が詰まってる。

OpenGLの新しめのバージョンをglfwで利用するには

まだ、これはmrbgemには取り込んでいないが、

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

特に

glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

が重要、これがないとOpenGLの初期化で失敗した。

関連記事