Linux で C++ グラフィックスアプリに CPU 描画の GUI をさくっと付けて, サーバから X11 画面転送したい


背景

  • レンダリング(レイトレーシング)や, データ可視化(形状処理)などの CPU のみ利用の C++ アプリをサーバ CPU など性能がよいマシンで実行したい
  • 処理結果として画像を表示する必要がある
  • さらに GUI を付けたい(パラメータをちょっと変えたりなど)
    • JSON-RPC とかでやるのはめんどいので, C++ アプリ単体で全部完結したい.
    • VNC とかで画面転送も, 画面転送で帯域使うので重い
    • libui https://github.com/andlabs/libui という手もあるが, 画像を表示するのが実はめんどい
  • すごい full-featured な GUI でなくてもよい
    • SwiftShader で OpenGL アプリを CPU 描画で動かす手もあるが, SwiftShader のビルドがめんどい.

既存の C++ GUI ライブラリは, だいたいが OpenGL(GLX) 使っていて, X11 画面転送というのができません.

ライブラリ

imgui と nanogui を動かすことができました.
どちらも基本は GPU 描画ですが, バックエンドを変えることで CPU 描画も可能になります.

SDL2. 描画のベースライブラリ

SDL2 で, OpenGL を使わない + Software renderer を使うことで, CPU 描画が可能になります.

Ubuntu などでは SDL2 は apt で入りますが, Ubuntu 18.04 では OpenGL や Wayland あたりに固定されているようで, GLX エラーがでました.

にあるように, 環境変数で x11 指定しても

export SDL_VIDEODRIVER=x11

X11 backend に切り替えできませんでした. その場合はソースコードから SDL2 をビルドする必要があります(OpenGL あたりを off にしておく).

SDL2 自体は GUI widget は無いので, この上に GUI ライブラリを乗っけて CPU 描画します.

imgui

imgui + SDL2 backend です. 上記のように SDL を software render にすることで CPU 描画できます.

nanogui

nanogui + SDL2 backend です. これも同じく SDL を software render にすることで CPU 描画できます.
(example1.cpp をちょっと改変する)

colorwheel には現時点では対応してません
(Eigen を使っているため. Eigen の部分をちょっと自前で実装すれば動くはず)

ありがたいことに NanoVG の部分は, nanort を使っていただいています.

NanoVG を CPU で描画する
https://qiita.com/syoyo/items/1b7fe6a1035394a7efe4

内部の実装としては, アイコンなどは SDL の texture にいったん NanoVG で描画して, それを表示しているようです(そのため, 毎回一から描画するよりは高速なはず)

感想

CPU 描画なので, やはり CPU は 1 core ぶん 100% になってしまいます. 多コアの高性能 CPU では気にならないかもしれませんが, ちょっと気にはなりますね.

画面に変更ないときは描画しないなどを制御できれば, CPU 負荷を減らすことができるかもしれません.

VNC で画面転送よりはレスポンスはよいかと思います(ネットワーク環境次第か. 少なくとも 1 GB イーサネットでは VNC はきびしい)

TODO

  • nanogui-sdl で, colorwheel 対応をして PR を送る
  • 画面に変更がないときは描画リフレッシュしないようにして, CPU 負荷を下げることができないか検討する.