こんにちは。技術部平山です。
今日は、
adb shell wm size 360x640
で、usbでつながったAndroid機の解像度を360x640にできる、というだけの話題です。
この記事の残りは、「なんでそんなことがうれしいか」という話であり、 情報自体は「ADB 解像度」で検索して出てくるサイトの方が有益かと思います。
動機
最近、カジュアルゲームで遊ぶことが結構あるのですが、 カジュアルと言いつつも、要求する性能はかなり高いケースが多いのです。
私の京セラS2は、2017年製でそう古くもなく、OSもAndroid9なのですが、 GPU性能はなかなかに絶望的です。Unityの標準シェーダで全画面描画(1280x720)されると、 確定で30fpsを下回ります。 しかしながらカジュアルゲームはフレームレートが低いと遊びにくいものが多く、 普通にやったのではまるで遊べないのです。
しかし、ここで解像度を下げられれば、事態は改善するはずです。 その方法は、調べたらあっさり出てきました。上のコマンドです。 モノによっては、解像度を縦横半分にすると、理論値通りフレームレートが4倍になったりもします。
さて、カジュアルゲームの話は私の個人的な事情ですが、もちろんのことこれは開発にも使えるのです。
重い時にまず調べるべきは「塗り」
ゲームのフレームレートが出ない、となった時に、真っ先に調べるべきは、 「それが塗り(=フラグメントシェーダ処理)によるのか、そうでないのか」 です。 プロファイリングなんて後でいいから、とにかく「塗り」です(異論ありそうですけど)。何故か。
CPUの性能差なんかよりも、GPUの性能差の方がずっと大きいからです。
以前ベンチマークの記事で数字を示した通り、 安物と高級機の CPUの性能差はたかだか5倍程度ですが、GPUでは数十倍にもなります。 5万円の機械が3万円の機械の5倍速い、10万円の機械は5万円の機械の5倍速い、 みたいなことが現実に起こっており、それでもう25倍の性能差、ということになるわけです。
プロファイリングして重い所を見つけて直しても、倍速にまでなることは稀ですし、 GPUが遅い機械ではCPUをいくらいじっても改善しません。 どちらかと言えば、CPU側のプロファイリングは、「このフレームだけガツンと重い」 という「負荷スパイク」を見つけることが主目的になると考えています。 フレームレートを上げたければ、断然GPUが優先です。
塗りかどうか調べる簡単な方法
さて、では「処理落ちが塗りのせいかどうか」を知るにはどうすればいいでしょうか?
解像度を下げましょう。 それでフレームレートが上がったら、塗りのせいだとわかります。 adbを使って解像度を下げれば、これを数十秒で試せます。最高の手段です。
Screen.SetResolution() を仕込んでビルドを作る、となれば10分では無理ですし、 いろいろな解像度を試すとなればデバグ機能を仕込んだりビルドし直したりせねばなりません。
エディタ上で解像度を変えるのはゲームビューの設定を変えるだけなので楽ですが、 エディタはPC上で動いており、スマホとは性能が異なります。
ADBなら実機ですぐに見られるのです。
しかも、自分で開発してないアプリであっても試すことができます。 普通にインストールしたアプリを、いくつかの解像度で遊んでみればいいのです。 フレームレートの表示がなくても、フレームレートが60なのか30なのか20なのかは、だいたいわかります。 いくつかのゲームで試してみましたが、多くのゲームは解像度を下げることでかなりフレームレートが上がりました。 つまり、それらのゲームはGPU性能が足りなくてフレームレートが落ちていたわけです。 フラグメントシェーダの処理を軽くできればフレームレートが上がるはずだ、 ということが、コードを見るまでもなくわかります。
塗りであるとわかった場合
さて、このテストで、「塗りのせいでフレームレートが落ちていた」とわかった場合、 どうすればいいでしょうか。
一つは「製品の解像度を落としてしまう」ことです。 以前FixedDPI設定の記事 に書いたように、解像度に制限をかけてしまうのは乱暴ですが低コストな手段です。 もっと真面目にやるなら、Screen.SetResolution()を使って、 お客さんが設定できるようにするのが良いでしょう。
もちろん「真面目に最適化する」という道もあります。 シェーダを軽くし、重ね描きを削減し、場合によっては機械の性能を見て機能のOn/Offを実装する、 という地味で高コストな道です。 この場合は、解像度を変えてみることで「何倍速くしたらいいのか」の目安もすぐに得られます。 解像度をどこまで落とした所で目標FPSに達するか、を見ればいいのです。 1280x720で足りず、960x540で60fpsに達したのであれば、だいたい1.8倍くらい 高速化すれば元の解像度のままでも60fps出せる、ということが想像できます。 その時点で「あ、そりゃ無理だ」となったら、解像度を落とすなり、 フレームレートの目標を落とすなりすることになります。
また、「いくら解像度を下げても目標に達しない」場合は、 塗り以外に問題があることがわかります。例えばDrawCallが多すぎてCPUで引っかかっていれば、 いくら解像度を下げても、一定以上には速くなりません。 その場合も、「今のCPU負荷なら、解像度はこれ以上下げても無駄」 「今のCPU負荷なら、x倍以上ピクセル処理を高速化しても無駄」 というラインがわかり、それはそれで有益です。
塗りでなくなった場合の指針
ついでなので、「問題が塗りじゃなかった」という場合に疑うべき所をリストにしてみます。
- GPU
- 頂点処理。頂点数が多すぎていないか?
- CPU
- DrawCallやらSetPassやら
- スクリプト
- 物理
頂点をムチャクチャ出している覚えがなければ、ほぼCPUでしょう。 その時はプロファイラの出番です。 すぐに直せる、あからさまなミスが見つかることを祈るのみです。
関連コマンドまとめ
他の記事を見ればわかることですが、便宜のために関連コマンドをまとめておきます。
adb shell wm size
デフォルトのサイズと、今の設定を表示します。
adb shell wm size 360x640
解像度を設定します。ちなみに360x640は私のお気に入りで、絵が視認できる範囲で 一番低い解像度かな、という印象です。twitterやslackもおおよそ使えます。
adb shell wm density
デフォルトと現在の画素密度を表示します。例えば私の機械だと、デフォルトが320です。 解像度を360x640にした時には、これを次のコマンドで160に落とすと、 ホーム画面のレイアウトが元と同一になります。
adb shell wm density 160
画素密度を設定します。解像度を落としたらこれも変えておかないと、 ホーム画面等でレイアウトが変わってしまいます。
終わりに
私のスマホは元の解像度が720x1280なのですが、もう1週間以上360x640にしたままにして使っています。 そうしないとゲームがまともに動かないのです。 大手が作る豪華なゲームよりもカジュアルゲームの方が圧倒的に辛いのが面白い所ですね。 slackもtwitterも、汚ないですが慣れました。 ゲームの絵も汚ないのですが、フレームレートが低いよりはマシです。
さて、おそらく次に機械を買い換えると、解像度は1920x1080を超えてくるはずです。 最近は細長いのが流行ってますから、2160x1080とかになるかもしれません。 現在の1280x720に比して、ピクセル数が2倍以上になるわけですが、 機械の性能は2倍どころか1.5倍になるかどうかすら怪しいのが現状です。 よって、おそらくは機械を買い換えたことでフレームレートが落ちることになります。
ゲーム開発者の皆様には 世の中には最新なのにADBで解像度を下げないとゲームできない機械が普通に売られているんだよ ということを知っていただけると幸いです。 OSのバージョンやメモリの量と性能はほとんど関係ない、 ということも広く知られると良いなあと思います。 Android9でメモリ3GB積んでいても、GPUが貧弱なマシンはいくらでもあり、 そのくせ解像度だけは高いのです。 そういった事情については、トライエースさんのサイトにある、 2019年のCEDECでの講演(PPTXファイル直リンク) が参考になるかと思います(slideshareに置いていただけたらうれしいな!)。
ところで、「おまえ、なんでそんな安い機械にこだわってんの?」 と思われる方もいらっしゃるのではないでしょうか。
高い機械を買いたくない、というような話ではありません。 高級機を買ったら最適化に興味を失うと100%断言できる からです。そして、周囲の大半がiPhoneを使っていて、 日常的に低性能Androidを使っている人がほとんどいないからです。
もしチーム全員が高級機だったら、絶対感覚が狂います。 頭ではわかってても、感覚としては低性能機のことがわかりません。 実感としてストレスを感じていないと、 「これは直さないとダメだよ!遊べないよ!」という切実さは出てこないのです。
確かに、もうちょっと上の性能のものを使ってもいい気はします。 このレベルの機械を使っている人はたぶんゲームをしないでしょう。 なにしろADBを使わないと遊べないのですから。
しかし逆に言えば、このレベルでも快適に動くようにできれば、 もっと多くのお客さんに遊んでもらえるかもしれない、ということでもありますし、 それはそれほど難しいことでもないと思うのです。 とりわけカジュアルゲームにおいては。
ちなみに、京セラS2は実に頑丈で、風呂に沈んでもなんともなく、熱も出ず、 私は非常に気にいっております。 考えてみたら、PHSの時代からずっと京セラ使ってますね、私。