Skip to main content
そう、UE4ならね。
あなたのモバイルゲームをより快適にする
沢山の冴えたやり方について Part2
Epic Games Japan
Support Engineer 岡田和也
本スライド、300ページ超えだったせいなのか
Slideshareへのアップに失敗しました /(^o^)\
そのため、Part1, 2に分割しています
Part 1のURLに関しましては
Slideshareの説明文をご確認ください
本日のお品書き
ヒッチ対策 編
● そもそもヒッチってなに?
● 一般的なヒッチ対策について
● モバイル特有のヒッチ対策について
メモリ管理 編
● なぜモバイル開発において問題になるのか
● メモリに関するプロファイル方法について
最新情報 編
● UE4.23 で入った
モバイル関連の便利機能・最適化について
モバイル特有のヒッチ対策について
● Shader Compile 問題
● メモリ転送速度 問題
Mannequinのテクスチャが描画されるまでの流れ
Storage Memory GPU
モバイル端末におけるメモリ
端末の発熱・電力消費を抑えるため
低電圧・低消費電力版である LPDDR (Low Power DDR) メモリを採用
メインメモリからGPUに
データを送る速度・量が制限されている
● 転送速度、帯域幅
モバイルの場合…
大量 または サイズが大きい テクスチャを使った場合
メインメモリからGPUへの送信に時間がかかり、ヒッチの原因に
モバイル SoCPC環境
Memory GPU
一般的な対策について
(モバイル以外の環境でも有効)
…の前に
UE4でTextureを語る際に避けては通れない
Texture Streaming機能に関して軽く紹介
Texture Streamingについて
Textureの MipMap の読み込みと破棄を動的に行い、
MemoryのTexture使用量を一定以下に保つ機能
Storage Memory GPU
Texture Streaming のメリットの一つ
4K などの巨大なテクスチャであっても
Mipが生成されているなら、適切(と判断された)サイズのみをロード
つまり…
Mipがない 場合や Texture Streamingを無効 にした場合、
ヒッチ、ロード時間増加、メモリ使用量などの問題が発生
4K! 4K! 4K!
Texture Streamingと
どれだけ仲良くできるかが勝利の鍵です!
テクスチャの
サイズ、圧縮設定は適切に
テクスチャのサイズは…
圧縮のために 4の倍数に
Mipmap ( Texture Streaming ) のために 2のべき乗に
● パッケージサイズを考慮すると、必要十分なサイズであることも重要
1999 x 1999
無圧縮:
15.6MB
2048 x 2048
ASTC:
1.82MB
イカロスMにおけるロードイメージの最適化Tips
2のべき乗に変換した Texture を Material で復元
● 14.2MB から 2MB にサイズ削減 (86%削減)
ソース 2738 x 1332 変形 2048 x 2048 復元 2738 x 1332
● https://replay.unrealsummit.co.kr/data2019/USM20190515_2_1.html
テクスチャの圧縮フォーマット ( for モバイル )
Android ゲームの開発のリファレンス
https://api.unrealengine.com/JPN/Platforms/Android/Reference/index.html
できるだけ
Texture Streamingは使いましょう
Never Stream は 可能な限り避ける
ロードが間に合わずテクスチャがボケることを回避するために
Never Streamを有効( = Texture Streaming を無効 )にすると…
Never Stream は 可能な限り避ける
テクスチャの初回使用時に
全Mipのロードが開始 & 完了待ちするため、ヒッチ・ロード時間増加の原因に
(できるだけ)ボケたテクスチャが見えないように
公式ドキュメント
● https://docs.unrealengine.com/ja/Engine/Content/Types/Textures/Streami
ng/index.html
Qiita
● [UE4] Texture GroupがTexture Streamingに与える影響
● [UE4] StreamingされないTextureはStreaming Texture Poolに入るのか??
● [UE4] Texture Streaming Pool Over Budgetの意味
Slideshare
● UE4のシーケンサーをもっともっと使いこなそう!最新情報・Tipsをご紹介!
(p113~)
Mipmap設定
UIなどMipmap( TextureStreaming )がNGなテクスチャの場合
必ずNoMipmaps設定に
Mipmap設定
Resource Size : 5461 Kb
Number of Mips : 12
Resource Size : 4096 Kb
Number of Mips : 1
UIなどMipmap( TextureStreaming )がNGなテクスチャの場合
必ずNoMipmaps設定に
これらはどのプラットフォームでも
有効なTipsです!是非活用してきましょう!
ほぼモバイル特有のTips
1フレーム間に
メインメモリ から GPUに送信する
テクスチャ数を制限することでヒッチを回避
????????
????????
レベルをロードしたときなど
メモリからGPUに大量のテクスチャが転送されるとヒッチが起きる
ActionRPG タイトルからメインレベルに遷移したとき
検証端末:Xperia Z5 ( 2015年10月発売 )
ActionRPG タイトルからメインレベルに遷移したとき
検証端末:Xperia Z5 ( 2015年10月発売 )
FTexture2DStreamIn_IO_
AsyncReallocate::
AsyncReallocate
約5フレーム(30fpsの場合)
157.9 ms
Calls : 68
:
1フレーム間にメインメモリからGPUに送信する
テクスチャ数を制限する設定
r.Streaming.AmortizeCPUToGPUCopy
● 0:無効 ( デフォルト )
● 1:有効
r.Streaming.MaxNumTexturesToStreamPerFrame
● テクスチャの最大送信数
● デフォルト:0
比較結果
デフォルト
● 158.3 ms ( Calls : 68 )
r.Streaming.MaxNumTexturesToStreamPerFrame:5
● 9.7 ms ( Calls : 5 )
1フレームにおける負荷を 約150ms節約!
図で流れを説明!
(説明の都合で簡略化してる部分あります)
2枚のテクスチャをロードする場合
まずは、最も低解像度の Mip をブロッキング (同期) ロード
ストレージからGPU まで一気に送信
優先度の高いTexture から順に各 Mip をメインメモリへ
優先度の高いTexture から順に各 Mip をメインメモリへ
メインメモリに送られたテクスチャは
次はGPUに送られますが…
メインメモリに送られたテクスチャは
次はGPUに送られますが…
モバイルの場合
メインメモリからGPUへの転送速度が遅いので、CPU負荷が上がり…
モバイルの場合
メインメモリからGPUへの転送速度が遅いので、CPU負荷が上がり…
\ヒッチ発生 /
r.Streaming.
MaxNumTexturesToStreamPerFrame を 1に設定すると…
1フレームにつき
メインメモリ から GPU に送るテクスチャが 1枚だけになるので
CPU負荷が下がりヒッチを回避!
そして、次のフレームでは
残りのテクスチャがメインメモリからGPUに
ざっくりまとめると
メインメモリからGPUに 一度に 大量の テクスチャを送ると
CPU負荷が一気に増えるので、送る枚数を制限しましょう
という機能
注意!
低解像度のテクスチャが
ユーザに見えてしまう可能性が増えます!
制限によってGPUに送信されなかったテクスチャは
最も低解像度のMipが描画に使われる
ロード対象のテクスチャの枚数、制限の値によっては
各MipがGPUに送信されるのが数フレーム以上後になる場合が…
r.Streaming.MaxNumTexturesToStreamPerFrame の設定は慎重に
ハイエンドな端末では 高めの数値 又は 制限OFFに
ローエンドな端末では 低めの数値に
カットシーンなどボケて欲しくない場面は
動的に 制限OFF にする手も
設定例
[TextureQuality@0]
r.Streaming.AmortizeCPUToGPUCopy=1
r.Streaming.MaxNumTexturesToStreamPerFrame=5
[TextureQuality@1]
r.Streaming.AmortizeCPUToGPUCopy=1
r.Streaming.MaxNumTexturesToStreamPerFrame=10
[TextureQuality@2]
r.Streaming.AmortizeCPUToGPUCopy=1
r.Streaming.MaxNumTexturesToStreamPerFrame=15
[TextureQuality@3]
r.Streaming.AmortizeCPUToGPUCopy=1
r.Streaming.MaxNumTexturesToStreamPerFrame=20
おまけ
ストレージからメモリへの送信数を制限することも可能
r.Streaming.FramesForFullUpdate
● IOネックの場合はこちらの設定を要調整
r.Streaming.FramesForFullUpdate r.Streaming.AmortizeCPUToGPUCopy
ここまでのまとめ
モバイル端末のメインメモリからGPUへの転送速度は遅いため、
大量 又は 大容量のテクスチャをロードするとヒッチの原因になる
Texture Streamingを考慮した設定にすることで
転送するテクスチャの量・サイズを調整することが大事
モバイルの場合、
1フレーム間でのテクスチャ転送数を制限することも検討
モバイル特有のヒッチ対策について
● Shader Compile 問題
● メモリ転送速度 問題
ながいたたかいでした
その成果がこちら
Before After
https://youtu.be/tETCfRlxH5Q
初回起動時の負荷を比較 ( 左:未対策 右:対策導入済 )
初回起動時の負荷を比較 ( 左:未対策 右:対策導入済 )
Open Levelでレベルを開いた際の負荷
ローディング画面中なのでセーフ
初回起動時の負荷を比較 ( 左:未対策 右:対策導入済 )
PSOキャッシュの効果により
シェーダコンパイル負荷がなくなった
初回起動時の負荷を比較 ( 左:未対策 右:対策導入済 )
メインメモリからGPUへのテクスチャ送信数を制限した効果
ヒッチは改善したが、数フレームに渡って少し速度が不安定に
改善の余地はまだまだありますが…
今回の目標である
ヒッチの回避は実現できました!
やってやりました
こうして実際の動作を見てみると
違いは一目瞭然!
事前準備や各調整コストはありますが
ゲームの完成度を一気に上げることができます!
本日のお品書き
ヒッチ対策 編
● そもそもヒッチってなに?
● 一般的なヒッチ対策について
● モバイル特有のヒッチ対策について
メモリ管理 編
● なぜモバイル開発において問題になるのか
● メモリに関するプロファイル方法について
最新情報 編
● UE4.23 で入った
モバイル関連の便利機能・最適化について
Shader Compile や テクスチャ から
急にメモリの話になります
ごめんなさい
(でも、実は関連してるんです)
どんなプラットフォームでも
メモリ使用量が上限値を超えると
クラッシュ
わかる
モバイルの場合、
端末ごとにメモリ容量が異なるため
上限値も端末によって異なる
…わかる
上限値 ≠ 端末のメモリ容量
端末毎に使用できる割合が異なるが
そのルールが不明
わからん
つらい…
とあるプロジェクトにおける計測結果
Galaxy S8
3.0GB / 4.0GB
(75%)
Pixel 2
1.8GB / 3.6GB
(50%)
そもそも、メモリ使用量という概念が曖昧
最終的にクラッシュの判定で使われる値は
様々な要素が絡み合った結果の値
もう
だめぽ
GDC2018のEpic講演で共有されたメモリに関する情報
iOS
● < 1.4 GB for 2 GB device ( 6, 7, 8 )
● < 2.1 GB for 3 GB device ( Plus, X, XR )
● < 2.8 GB for 4 GB device ( XS, 11 )
● Xcode の Memory Usage Gauge による計測値
Android
● 0.5 GB for 2 GB device
● 1.4 GB for 3 GB device
● adb shell dumpsys meminfo による計測値
GDC2018のEpic講演で共有されたメモリに関する情報
iOS
● < 1.4 GB for 2 GB device ( 6, 7, 8 )
● < 2.1 GB for 3 GB device ( Plus, X, XR )
● < 2.8 GB for 4 GB device ( XS, 11 )
Android
● 0.5 GB for 2 GB device
● 1.4 GB for 3 GB device
これらの値をそのまま使うのは非推奨です
ゲーム内容 や シェーダの使い方などで目標値は大きく変化します!
とはいえ…
開発する上で、
レギュレーション(Budget)は
決める必要があります…
また、普段の開発でも
定期的な計測は必須…
ターゲットとする端末毎に
必ず計測・検証しましょう!
各メモリプロファイラの
特性を把握した上で計測しましょう!
ターゲットとする端末毎に
実機での計測・検証することが大事
● どのプロファイラの
● どの値が
● どの程度の値になったらクラッシュするか
各メモリプロファイラについて
UE4標準のメモリプロファイラについて
(モバイル以外のプラットフォームでは挙動が異なる部分あります)
stat unit
UE4が計測した値ではなく、
OS から取得した 物理メモリ使用量 の値を表示 (簡易版なので精度は低い)
● FPlatformMemory::GetMemoryUsedFast();
stat LLM / LLMFULL / LLMPlatform
UE4が用意しているメモリ使用量を追跡するシステム
カテゴリ毎にTag付け(独自Tag追加可能)
● LLM, LLMFULL : UE4 によって割り当てられたメモリ
● LLMPlatform : OSによって割り当てられたメモリ
ちなみに
Total ( LLM Platform )
= Total ( LLMFULL ) + Overhead ( LLM Platform )
= stat unit の Mem
597.63 = 584.72 + 12.91
みんな大好き csv形式 でも出力できるよ!
使い方・Tips・注意点について
公式ドキュメント
● Low-Level Memory Tracker
Qiita
● [UE4] LLM (Low Level Memory Tracker)を使用したメモリトラッキング
OS標準のメモリプロファイラについて
Android 編
adb shell dumpsys meminfo
<PACKAGE_NAME>
Google公式ドキュメント
https://developer.android.com/
studio/command-line/
dumpsys#meminfo
adb shell dumpsys meminfo
<PACKAGE_NAME>
Google公式ドキュメント
https://developer.android.com/
studio/command-line/
dumpsys#meminfo
No LRU cache – 2.22 GB RAM used LRU cache – 2.05 GB RAM used
iOS 編
Xcode / memory gauge
Instruments / Activity Monitor
Instruments / Activity Monitor
Instruments / Activity Monitor
Instruments / Allocations / VM Tracker
Instruments / Allocations / VM Tracker
iOS標準の
メモリプロファイラの使い分けについて
Xcode, Activity Monitor
● 非常にシンプルで分かりやすい
● Activity Monitor は プロセスにAttachしなくてもいいので楽
● 表示している値がどういう値なのか不明
Allocations
● メモリに関する詳細な情報を確認できる
● iOSのメモリ管理に関する深い知識が必要
● 各項目がどのように作用してクラッシュの閾値になるかは不明
iOSのメモリ管理・使用量に関する挙動は
端末だけでなくプロジェクト毎に変化
Epicでも自信を持って
公開できる詳細なルール・方針がまだないほど
非常に複雑な問題
個人的考え
● Allocationsを駆使するのがベストですが…
Xcode, Activity Monitor で妥協するのも悪くない選択肢
メモリプロファイラに関するまとめ