UIImageView vs Metal | try! Swift Tokyo 2018 Day2-13

MetalはGPUへのアクセスを提供するAPIで、OpenGLより10倍速いという謳い文句で登場しました。本セッションではMetalの基礎を解説しつつ、そのグラフィックス描画性能をUIImageViewと比較してみます。

MetalのAPIを直接利用する機会がなくても、Metalはあなたのアプリの裏で暗躍しています。身近なクラスとの比較を通じて、普段我々が意識することのないGPUのレイヤで何が起きているのか、目を向けてみるきっかけになればと思います。

UIImageView vs Metal

f:id:niwatako:20180302164005j:plain

f:id:niwatako:20180302164424j:plain

Fusion社で働きつつフリーランスとして働いています。

Metalとタイトルにあるが、実際使っている人、予定のある人は少ないと思う

f:id:niwatako:20180302164507j:plain

使い方より、それを通じてGPUレイヤーに目をつける話をしたい

f:id:niwatako:20180302164535j:plain

f:id:niwatako:20180302164531j:plain

なにをするコードかわかりますね

f:id:niwatako:20180302164553j:plain

f:id:niwatako:20180302164615j:plain

f:id:niwatako:20180302164622j:plain

最終的に表示するピクセルバッファが入っている

f:id:niwatako:20180302164624j:plain

f:id:niwatako:20180302164643j:plain

フレームバッファという通り、1フレーム分入っている。

f:id:niwatako:20180302164704j:plain

60フレームなら1秒に60書き込むことになる。

それをやるのが左のプロセッサーである。

2種類あって、CPUとGPUがある

f:id:niwatako:20180302164729j:plain

CPUは早いが一度に運ぶのは苦手、GPUは早くないが、同時に処理できる

f:id:niwatako:20180302164806j:plain

CPUは早くてなんでもできるので汎用プロセッサと言われる。

容易に使用率100%になってしまうので、GPUが得意なことはGPUにまかせていく

f:id:niwatako:20180302164844j:plain

右のサンプル映像はモザイク処理を1秒間に60フレームやっている

f:id:niwatako:20180302164945j:plain

GPUの一つの使われ方でした。

ではメタルはなにか

アプリからGPUを叩きたい時にAPIを提供する

f:id:niwatako:20180302165018j:plain

昔から似たようなものにOpenGLがあるがどう違うのか

いろんな会社のプラットフォームに対応しているし、いろんなベンダーのGPUに対応している

f:id:niwatako:20180302165050j:plain

MetalはApple最適化で早い

f:id:niwatako:20180302165107j:plain

f:id:niwatako:20180302165127j:plain

f:id:niwatako:20180302165124j:plain

f:id:niwatako:20180302165120j:plain

描画だけですごいコード量

f:id:niwatako:20180302165139j:plain

ラッパー作ったらいいかな?

つくった

f:id:niwatako:20180302165245j:plain

比較

f:id:niwatako:20180302165250j:plain

TableViewに並べて

f:id:niwatako:20180302165254j:plain

性能差がでかいように大きな画像を使う

計測コードです

f:id:niwatako:20180302165321j:plain

f:id:niwatako:20180302165334j:plain

f:id:niwatako:20180302165338j:plain

f:id:niwatako:20180302165348j:plain

f:id:niwatako:20180302165414j:plain

しかし勘違いに気づいた

メタルのほうがスクロールが固まる

f:id:niwatako:20180302165432j:plain

f:id:niwatako:20180302165437j:plain

f:id:niwatako:20180302165443j:plain

これは間違っていた

f:id:niwatako:20180302165457j:plain

f:id:niwatako:20180302165502j:plain

f:id:niwatako:20180302165514j:plain

GPUとCPU両方からアクセスできるメモリ領域

f:id:niwatako:20180302165522j:plain

コマンドバッファ作る

f:id:niwatako:20180302165539j:plain

GPUが処理する。それがさっきのコード

f:id:niwatako:20180302165606j:plain

これはあくまでCPU側のコード

f:id:niwatako:20180302165626j:plain

GPUコードも測るようにする

f:id:niwatako:20180302165629j:plain

f:id:niwatako:20180302165709j:plain

コマンドバッファに入れてから終わるまで待つ

f:id:niwatako:20180302165725j:plain

f:id:niwatako:20180302165746j:plain

僕の実装が悪いのか?

UIImageViewはそもそも早いぞ?

f:id:niwatako:20180302165808j:plain

f:id:niwatako:20180302165823j:plain

f:id:niwatako:20180302165826j:plain

既にUIKitは内部にMetalを使っている

f:id:niwatako:20180302165858j:plain

既に最新技術を使って最適化さている

f:id:niwatako:20180302165903j:plain

自作したほうが早いというイメージを昔からやっていた人は持っているかもしれませんがもうそうではない

f:id:niwatako:20180302165942j:plain

f:id:niwatako:20180302165949j:plain

私のラッパーは何が悪かったでしょう

f:id:niwatako:20180302170005j:plain

f:id:niwatako:20180302170025j:plain

f:id:niwatako:20180302170033j:plain

CPU、1段目がコマンドバッファを作る、2段めがそれをGPUに送る

f:id:niwatako:20180302170112j:plain

3段目がGPU処理

f:id:niwatako:20180302170126j:plain

時系列で

f:id:niwatako:20180302170131j:plain

明るい色はユーザーが書いたコードの可視化、薄いのは暗黙的に行われている処理

f:id:niwatako:20180302170212j:plain

大きい画像を読み込んでリサイズしてて

f:id:niwatako:20180302170231j:plain

表示するテクスチャにコピー

f:id:niwatako:20180302170248j:plain

間に時間が

f:id:niwatako:20180302170300j:plain

フローを見直す

f:id:niwatako:20180302170322j:plain

GPU処理完了をプロセッサがせっかく別れてるのに、待ってる。

f:id:niwatako:20180302170347j:plain

f:id:niwatako:20180302170352j:plain

リサイズのあとCPUに戻ってもう一回レンダリングしている

f:id:niwatako:20180302170421j:plain

f:id:niwatako:20180302170432j:plain

f:id:niwatako:20180302170436j:plain

一つのコマンドバッファにまとめると

f:id:niwatako:20180302170443j:plain

f:id:niwatako:20180302170504j:plain

短縮できた

CPU・GPU間で余計なやり取りが発生していないか注意する必要がある。

f:id:niwatako:20180302170519j:plain

f:id:niwatako:20180302170557j:plain

f:id:niwatako:20180302170600j:plain

f:id:niwatako:20180302170614j:plain

f:id:niwatako:20180302170630j:plain

テクスチャをキャッシュするとどうか

f:id:niwatako:20180302170640j:plain

キャッシュはどこにおいているか意識する

f:id:niwatako:20180302170706j:plain

こうするとCPUとGPUの共有領域にあるリソースを指す。

これはいいが、どういうのがダメかというと、

f:id:niwatako:20180302170741j:plain

UIImageにしてしまうとCPUの領域にしてしまう。

OpenCVに渡すためにUIImageいしてたりとか、リソースを考慮しないコードはけっこううある

f:id:niwatako:20180302170845j:plain

f:id:niwatako:20180302170857j:plain

メタルでもスムーズになりました

f:id:niwatako:20180302170907j:plain

f:id:niwatako:20180302170910j:plain

f:id:niwatako:20180302170925j:plain

UIKitは最適化されている、パフォーマンスを測る時の注意、無駄な処理はないか、リソースはどこにあるのか

f:id:niwatako:20180302171009j:plain

そうした視点を共有させていただきました。

f:id:niwatako:20180302171022j:plain

[広告]面白かったら、ためになったら

  • はてなブックマークSwift タグをつけてブックマーク!
  • 「インターネットで生活を楽しく豊かにしたい」仲間を募集しています
  • Bitcoin: 3KGqXtR1ZaGVdkvcw8CCNrkDxDhdbZBYHL