Ver.2.0.11 でのモード7 の改善について
2.0.11をリリースした後、Raspberry Pi 3で試しに使っていたのですがどうも重たいのでいろいろチェックしていたら、どうやら改善するための仕組みの実装がバグっていたというオチになっていました。(Ver.2.0.12では改善策が正しく動作しており動作速度が改善されていることを確認しました)
改善と言っても普通当たり前のようにやっていることをやっていなかったというだけなのですけど。
簡単にいうと「不要な処理はしない」という基本的な最適化ですね。
Qt BrynhildtはBrynhildrサーバからネットワーク経由でVP8データを受け取ります。そのデータをlibvpxというライブラリに渡してYUVというデータに変換してもらいます。次にYUVデータをRGBというデータに変換します。このRGBデータをQtに渡してQImageというオブジェクトを作ってデスクトップ画像を描画してもらいます。
VP8データ
↓ libvpxが計算してくれる
YUVデータ
↓ 自前で計算する(*)
RGBデータ
↓ Qtが変換してくれる
QImageオブジェクト
ですので、QtBrynhildrはひたすらYUVデータからRGBデータへの変換をやればいいのですが、1920x1080のデスクトップで、ある時点のデスクトップを描画する場合、このYUVデータからRGBデータへの変換を207万3600回(1920*1080回)やらなくてはなりません。最終的にはR,G,Bの3つを計算するため同じような計算をするのでトータル622万800回行うことになります。これによりようやく1フレーム分の画像データが得られます。
2.0.11までQt Brynhildrは馬鹿正直に全ピクセル分をフレーム毎に再計算していたのです…(;д;)
一般的にデスクトップ画像は大きく変化することはそんなにありません。動画を表示しているウィンドウは当然変化しますが、それ以外の部分(例えば壁紙の部分とか)は画像的に変化がない部分も多いです。
前のフレームで計算した結果(RGBデータ)が残っているなら、次のフレームの計算でYUVデータの変化のない場合は計算自体を省略できます。Ver.2.0.12以降ではYUVデータで変更のあった部分だけ再計算してRGBデータの更新を行い、これをQtに渡して表示します。
YUVデータは前回のフレーム分と今回のフレーム分の2つが必要なので、2つ分のバッファを用意しておいて交互に役割だけを入れ替えて使うようにします。(不要なデータコピーを行わないようにするため)
YUVバッファ 1 YUVバッファ 2
前回のYUVデータ 最新のYUVデータ
↓ 次のフレーム
最新のYUVデータ 前回のYUVデータ
↓次のフレーム
前回のYUVデータ 最新のYUVデータ
極端に動きの早い画像を全画面で表示するような場合には性能がやや落ちる可能性がありますが、大抵の場合必要な計算量をかなり抑えることができると思います。
この改善の結果、2.0.10 リリース記事のコメントで書いた古いCore i3 ノートPCでのダメダメな動作は普通に使える程度には改善されました。しかし、CPU負荷は30%程度と高いので少し調べてみると、どうやらデスクトップ画像の縮小処理が原因でCPUの負荷が高いことが分かりました。そこで設定ダイアログで「スケーリング処理をサーバーで行う」オプションを指定するとCPU負荷は数%にまで落ち、ようやく普通に使える状態に落ち着きました。
開発者である私でさえ、このオプションの使用に行き着くまで試行錯誤が必要だったことを考えるとオプションの選択肢を増やすだけでなく最善のオプションの組み合わせをある程度自動的に選択するような機能が必要だという結論に辿り着きました…(;ω;)
(追記)
SIMD(SSE)での改善についてもイントリンシックではありますが実装してみました。Cygwin x64のgcc-6.4では25%程度の向上がみられるのですが、Qtに付属しているMinGW(gcc-5.3ベース)でコンパイルすると逆に遅くなります。生成されたコードをみるとやはりgcc-6.4の方が洗練されたコードとなっているようですが、とりあえずここで止めておこうかと思います。どうしてもこれ以上必要になった時は手動でコーディングするということで…
« Ver.2.0.13 リリース | トップページ | ストリーミング型ゲームをMacにストリーミングしてみる »
コメント