この記事はFrontrend Advent Calendar 2013の6日目の記事です。昨日は谷さんでWeb Components/Polymerを軽く触ってみるでした。(これ今後数年で大流行りしそうに思うので、未読なら是非!)

さて、最近はHTML5だCSS 3だFlashやめてJS制御でアニメーションだーってんで盛り上がってるわけですが(周回遅れ)、いざアニメーションを実装してみても、なかなかスムーズに動いてくれなかったりしますね。

どうやったらスムーズに動くかってのを解説したいと思います。

なおこの辺りの情報は、概ね斎藤さんを中心としたFrontrend絡みの方々に教えて頂きました。感謝感謝。

先に結論

概念的なの

  • GPU合成レイヤーを適切に使うと早い
    • いわゆるハードウェアアクセラレーション
  • 何がCPUで、何がGPUで描画されるか知っておくべき

実際的なの

  • transformやopacityはイケてる
    • 他のアニメーションはコスト高いっぽい、特に色
  • 合成レイヤーの内容を変更しない
  • パラパラアニメは全コマ読み込み可視性の制御で
  • アニメの「コマ」が少なければ少ないほどハードウェアアクセラレーションの効果が出る

ぬるぬるアニメ、ざらざらアニメ

まずは実例からご覧頂きましょう。

四種類の方法で、左から右へ移動させています。

  • transform:translateX()を使ったCSSアニメーション
  • transform:translateX()を使ったJSアニメーション
  • leftを使ったCSSアニメーション
  • leftを使ったJSアニメーション

最初のが一番綺麗で、他はなんかちょっとひっかかる感じがありませんか。これは、Flashの代わりにとCSSでアニメーションしたのにガクガクになってしまう現象の顕著な例です。

(と言いつつ、手元の環境だとIE 11は全部綺麗に動いてしまった……。Chromeが一番顕著でした。) 

では、何が明暗を分けたのでしょうか。

JS vs CSS

JS制御とCSS制御であれば、CSS制御の方が高速です。HTML5やCSS 3をエミュレートするJSがいまいち低速なのはご存知でしょう。

細かい数値を設定する場合はJSが必須となります。しかしその場合でも出来るだけCSS側へ処理を置き、出来るだけJSからは「動かす」のではなく「(CSSでの)動きを切り替える」ようにするとより高速に動く事でしょう。

この話題はこれくらいにします。

CPU vs GPU

transformのtranslateX()とleftはいずれもCSSで、要素を左右に動かすという同じような機能を持っています。

ですが実はtransformはGPU、leftはCPUにより描画処理が行われます。

CPU

そもそもGPUて何?という人もいると思うので、ざっと説明します。

まずこっちは有名コンピューターの頭脳。

CPU: Central Prosessing Unit、つまり中央演算処理装置です。コンピューターのあらゆる動きの中核となります。「コンピューターの五大要素」なんてのもあるのですが、その筆頭です。

ちなみになんとかヘルツ (Hz) で強さが測れますが、違う種類のCPUはHzの数値だけ見ても測れません。(学校の試験で合計点が同じでも、国語が得意な人も数学で点を稼ぐ人もいますよね。)

CPUは、例えて言うなら「あなた」です。そう、立派な脳みそを持っていて、色々なお仕事をする事が出来る「あなた」です。

画面の描き換えも基本的に「あなた」の仕事です。

「CPUです。何でもやります。」

GPU

CPUのニセモノ、ではありません。

GPU: Graphcs Prosessing Unit、描画演算処理装置とでも呼びましょうか。画像の処理が得意です。

GPUを例えるなら「外注さん」で、画像映像の処理の専門家です。「あなた」が様々な描画処理を自前でやるよりも高速です。が、仕事のたびに依頼したり成果物を受け取ったりする手間が増えます。

「GPUです。グラフィクスのお仕事ください。」

マルチコアCPU(おまけ)

ついでなんですが、CPUがたくさんある状態というのは、「あなた」が仲間と一緒に仕事をしている状態です。

仕事の速度は上がりますが、やはり仲間内でやり取りが発生しまう。コアが二倍になったからといって速度が二倍になるとは限らないのは、そういうわけです。

「チーム『クアッド・コア』です。」

で、CPUとGPU

「あなた」と「外注さん」の関係です。既に述べましたが、画像映像のお仕事を専門家に任せる事で高速化を図る事が出来ますが、ちゃんと管理しないといけません。

「あなた」たるCPUが仕事の中心で、画像系のものを切り出して「外注さん」たるGPUにお願いします。

「この画像を使って画面作ってください」

アニメーションを行っている最中も、CPUは様々な雑務も平行してこなしています。マウスやキーボードの入力を受付たり、ネットワーク越しにファイルを受信したり、またバックグラウンドでメモリを管理し最適化し、ハードディスクにアクセスします。アニメーションだけが仕事ではないのです。

CPUで出来る仕事は人間でも出来る

この感覚を大切にして欲しいんですが、computerなんてものは所詮計算機です。処理速度が超高速ではありますが、やってる内容は人間にだって出来ます。(機器のUIがあればね!)

コンピューターの「重い処理」というのは、人間がやっても「辛い仕事」になるわけです。よって、コンピューターの処理の内容を想像する事で、高速化のヒントを得られる場合が多々あります。

CPUのお仕事

というわけでございましてですね、はい、はい。

CPUやGPUがどういう「お仕事」をしているのかを、「あなた」と「外注さん」として見てみたいと思います。

CPUはペイントで画面を作る

「外注さん」と契約している「あなた」ですが、自分でも画像処理を実施する事が出来ます。

その際の手順は、こんな感じ。

「あなた」の手元にはファイルが二つあります。

  • 背景.bmp
  • キャラクター.bmp

この二つを合成して背景の上をキャラクターが動くパラパラアニメを作り、各コマの画像を「クライアント」に送信するというお仕事をしています。

一枚目の画像

さて、ペイントで背景.bmpを開きました。また別ウィンドウでキャラクター.bmpを開きました。

さらにまた新しいペイントを開き、背景.bmpからコピーしてきます。続いて、指定の場所にキャラクター.bmpを上書きして貼り付けます。(幸い、キャラクターの背景色は透過になっています。)

これでパラパラアニメの一枚目が完成です。これを「クライアント」に送信して、続いて二枚目を作ります。

二枚目の画像

先程作成した一枚目を上書き編集する事にします。

改めて同じ手順を繰り返せば二枚目は完成なのですが、ここには先ほどのキャラクターが既にいます。二枚目を作り始める前に背景画像で上書きして、それを消すという作業が必要になります。

なお、このとき背景画像全体(大きい)をコピペすると処理に時間がかかってしまいますので、さっきキャラクターがいた部分だけ、元画像からコピーして上書きする事で「元に戻す」事にします。(幸いあなたはコンピューターのような正確な頭脳を持っているので、該当箇所の座標は瞬時に判断する事ができます。)

元に戻ったところで、改めてキャラクター画像を貼り付けます。さっきより少しずらした場所に。

これで二枚目も完成したので、「クライアント」に送信します。

あとはこの作業を繰り返す事で、「クライアント」側がパラパラとアニメーションをしてくれるという仕組みです。

GPUのお仕事

一方、同じ作業を専門の「外注さん」に発注した場合はどうなるでしょうか。専門家の彼は、素晴らしいツールを持っていて、それを使いこなして仕事してくれる事でしょう。

CPUからGPUへ仕事を依頼する

まず最初はの状況は同じです。「あなた」の手元に、先程と同じ二つのファイルがあり、二枚を合成してパラパラアニメを作ります。

  • 背景.bmp
  • キャラクター.bmp

先程はそれぞれの画像をペイントで開きましたが、今度はこれを、指示書を付けて「外注さん」に送ります。

ここから「外注さん」のターン。

GPUはPhotoshopで画面をつくる

「外注さん」は受け取った画像を、ペイントではなくPhotoshopで開きます。

そして新しいキャンバスに背景画像を貼り付けます。次はキャラクターですが、それを貼り付ける前にレイヤーを作成し、そちらに貼り付けます。ここがポイント。

これで一枚目が出来たので、この状態で「クライアント」に送信します。(画面バッファの送信はGPUから直接行うと思ってるのですが、ここちょっと自信ないです。)

続いて二枚目を作るのですが、これは非常に簡単なお仕事です。なんせレイヤーに分かれているのだから、それを動かすだけですから。

ほんの数秒で二枚目が完成しました。すごいぞ「外注さん」!

ポイントはレイヤー

「外注さん」の仕事が早い最大の要因は、レイヤー機能を使った事でした。この機能のため、画像を描き直す事なしに「クライアント」に送る事が出来ます。

またこのレイヤーごとに各種の視覚効果を与える事が簡単に出来ます。先程のように位置を動かすのは朝飯前、他にも回転や拡大縮小、ぼかしたりくっきりさせたり、立体的な表現も可能です。これはレイヤーがないと行えません。行えない事はないのですが、現実的な速度は出ない事でしょう。

指示が悪いとかえって遅く

レイヤーを使った事で高速に「次のコマ」を作成する事が出来ましたが、ところで「あなた」の指示が悪いと「外注さん」のお仕事効率はがくっと下がってしまう場合があります。

レイヤー内の画像をコマごとに描き直す必要がある場合がそれです。

「この画像を使って画面作ってください。あ、あとこれもお願いします。すみません、これ追加です。修正入りました。また修正入りました。この修正でデザインフィックスです。あ、ごめんなさい軽微な修正入りました」
「やめて」

例えばよくあるセル画のアニメーションは、コマごとにキャラクターの画像を差し替える必要があります。これは面倒なお仕事です。

また意外と思われるかもしれませんが、形が変わらなくても色を変える場合は「あなた」が元絵を作り直して「外注さん」に送りなおす必要があります。すると「あなた」がたくさん絵を造るコストと、それをいちいち送信するコストがかさんでしまいます。これも悪い指示の典型です。

元絵を減らして効率化

フェードで色を変える場合は全ての中間の状態を用意するのではなく、最初と最後の二枚のみを用意、「外注さん」に送り、「外注さん」には透明度の変更で切り替えてもらうようにすると高速です。

パラパラアニメにしても、絵を都度送っていると大変です。数が決まっているのなら一度全ての絵を先方に送っておいて、表示する、しないで表示だけ切り替えてもらうのが良いでしょう。

高速化施策

具体的に何をどうしたらGPUが利用されるかが気になるところだと思いますが、残念ながら特に仕様はなくブラウザーの実装次第です。また同じブラウザーでもバージョンによって違います。地道に調査、検証してゆくしかなさそうです。

かつて「とりあえずtransform:translate3d(0,0,0)を付けてみる」というアヤシイ系技術が流行りました。これは3D表現の指定をする事でハードウェアアクセラレーションの対象となり、レイヤーが作成される事を利用した高速化でした。しかしその後iOS(のMobile Safari)のバージョンが上がると、えーと何でしたっけ、何か他のに変わりましたね。

ハードウェアアクセラレーションが利きそうなプロパティ

HTML5 Rocksの2011年の記事(英語のみ)によると、こんな感じだそうです。

These aspects of your document can be accelerated by the GPU:

  • General layout compositing
  • CSS3 transitions
  • CSS3 3D transforms
  • Canvas Drawing
  • WebGL 3D Drawing

やはりtransform系でしょうか。

あとopacityもGPUで処理される場合があります。(出典を控えたメモを紛失しました……。)

Chromeで確認

Chromeの場合、対象になっている部分を可視化する設定があります。これを大いに活用すると良いでしょう。

開発者ツールの設定から、「General>Rendering」の「Show paint rectangles」と、「Force accelerated compositing」及びその下の「Show composited layer borders」にチェックを入れてください。GPUが管理、合成するレイヤーが橙色の枠で、また画面が再描画された部分が赤色の領域で表現されるようになります。

Chrome開発者ツールの設定。バージョンによって内容がよく変わるので注意。

枠線を表示した状態。赤色の領域が頻繁に表示されない方が良い。

iPhoneシミュレーターで確認

またiPhoneシミュレーターも、メニューバーから「ツール>ブレンドレイヤー(カラー)」をオンにしておくと、ハードウェアアクセラレーションがかかっている部分が赤色で表示されます。

長時間見つめていると心を悪くしそうな配色……。

Mac Safariも設定が色々と

あったんですがちょっとメモを紛失してしまったので、各自探してください。コマンドラインから設定して、(「開発」より高度な)開発者用のメニューを表示させたり出来ます。

他は……

よくわかりません。ご存じでしたらお教え頂けると助かります。

とりあえずこのあたり……?

まとめ

あらゆる処理は一般にCPUで行われますが、描画に関する処理をGPUに委譲する事で高速化を図る事が出来ます。

CPU、中央演算処理装置は「中央」という名の通り、コンピューターのあらゆる処理の中央に位置します。

一方GPUはグラフィックに特化しており、GPUから指示を受けて高度な作業を高速に行います。GPUはグラフィックに特化しているので、多種多様な処理を行う能力はありません。その分、自分が専門とする描画まわりの処理は飛び抜けて優秀です。

CPUはアニメーションという高度な描画処理を別のハードウェアのひとつであるGPUに依頼する事でスムーズに処理します。ただしGPUは画像を加工する作業は得意ですが、画像を作成する作業は出来ません。次々と新しい「元絵」が必要になるような作業では、真価を発揮する事は難しいでしょう。

必要な部分をGPUに任せる一方、不必要な部分をGPUにさせないよう注意を図る必要がありそうです。具体的にはtransform, opacityを使ってアニメーションを実装し、かつその領域を更新しない事が肝要です。

優秀な外注さんを活かすも頃すも、あなた次第です。

<body>にtranslate3dは、だめ、ぜったい。

参考、謝辞

このあたりの話題は、国内ではCyberAgentのFrontrend関係の方々が特に知識を持っておられるのではないかと思います。

ちょくちょくセミナーが開催されるので、興味をお持ちでしたら参加してはいかがでしょう。私もいつも教わっています。ありがとうございます。はいステマ終わり。

明日のFrontrend Advent Calendar 2013は、あほむさんです。前述の参考リンクにも三つ載せてますが、凄腕の人です。

ちなみにこのブログはハードウェアアクセラレーションとか考えないで作られてます。