既報の通り、AMDは3月26日にバーチャルリアリティ(VR)向けの技術「LiquidVR」について説明を行ったが、この際に公開された「Asynchronous Shaders」に関する詳細についてもう少し説明したいと思う。
TimeWarpとは何か
まず前回はさらっと流したTime Warpについてもう少しきちんと説明しておく。Time Warpという用語そのものはOculus VRの用語であるが、AMDなども同じ意味でこの用語を使っており、すでに一般的な用語になっているかと思う。
Oculus VR自身もこのTime Warpingの働きを詳細に説明した動画を公開しているが、さすがにちょっと長いのでかいつまんで要点を説明したい。
Photo01は前回の記事でも紹介したLatest Data Latchのスライドだが、操作者が右に向かって振り向く場合を考えてみると、頭の回転を検知して、表示している画面を空から水面の方向に順次切り替えてゆくことになる。
ただ、処理の流れが「回転検知」→「次描画位置の確定」→「CPUが描画コマンドの発行」→「GPUがレンダリング」→「出力」となるから、どうしても時間が掛かる。仮に描画が60fpsで行われているとすると、CPUが十分早いとしても回転検知→出力に1フレーム分の遅れが出る。フレームレートが60fpsであるとすれば16.67msほどで、これは人間が「ずれている」と感知できるには十分な時間である。
これを解消するためには、CPU/GPUの処理能力を引き上げ、表示のフレームレートを思いっきりあげてやればいい。例えば1,000fpsとかで表示していれば、1フレームといっても遅延は1msでしかない。人間の目の認識速度は、神経の伝達速度がボトルネックになっておおむね1ms程度とされるので、よほど激しい動きでなければほとんど気にならないレベルだろう。
さらにフレームレートを10,000fpsまで引き上げれば遅延は0.1msで、もうこうなると人間では遅れが認識できない。ただし、残念ながらそこまでの高速化はまだ当分の間は夢でしかないので、もう少し現実的な方法でだます必要がある。
そこで、まずPost-Renderingの段階で実装されるのがTime Warpである。例えばPhoto01の頭の動きだと、目の前の画像は右から左に流れてゆく(正確に言えば左上に流れてゆく)ことになる。そこで、レンダリングが終わった映像を本来よりもやや左上に表示することで、人間の違和感をやや抑えることができる。
映像そのものは正しくないのだが、ただ動きに追従して映像の表示位置が変わることで、「頭の動きに画面が追従していない」という感覚を最小限に抑えることができる。
ちなみにこの技法がTime-Warpingと呼ばれているのは、ノースカロライナ大のLeonard McMillan氏/Gary Bishop氏が1995年に出した"Head-tracked stereoscopic display using image warping"や1997年の"Post-Rendering 3D Warping"といった論文が元になっているのではないかと思われる。
TimeWarpで解決できない問題に対処する「Asynchronous Time Warp」
さて、これでレンダリングが十分に高速なら、動きそのもののずれは最小限に抑えられるのだが、複雑な映像になるとレンダリングが間に合わない可能性が発生する。この場合、Time Warpだけでは解決できないわけだ。
例えばPhoto01のシーンでは、夕日(朝日?)から水辺の風景になるわけで、もしレンダリングが間に合わないと、頭を振っても夕日が見え続ける(というか、1フレーム遅れて水辺に切り替わる)ことになり、やはり違和感が生じてしまう。そこで、次なるアイディアとして出てきたのが「Asynchronous Time Warp」(ATW)である。
これは何か? というとOculus VRのSoftware Architectを勤めるMichael Antonov氏が自身のblogで説明しているが、要するにTime Warpの後で画面を差し替える技術である。
ATWを使う場合、とりあえずレンダリングが間に合わなかったら前フレームの画面にTime Warpを施して表示するが、さらににその後、レンダリングが完了した時点でVsyncを待たずに画面を差し替える形になる。もちろん映像が激しく動いているケースではそれでも遅れは目立つのだが、部分的な画面更新であればそれほど違和感がない、という仕組みである。
Asynchronous Shaders
話の前提となる部分に触れた後で、話を今回のメインであるAsynchronous Shadersに移す。Asynchronous ShadersはLiquidVRに実装されている機能だが、これは先ほど説明したATWを効率的に行えるようにするための仕組みである。
GCNではGPUに3種類の処理を同時に渡し、これを別々に並行して実施できる仕組みとなっている(Photo02)。実際のゲームのシーンでは、Photo03のように複数の処理が同時に動く形だが、GCNは本当にこれを並行して実施できる。
これをサポートするため、GCNでは複数のCommand Streamをサポートしており、それがどう実施されるのかはGPUに任せることができる(Photo04)。実際にこのAsynchronous Shaderを利用する事で、大幅に性能を改善できるケースがあることが示されている(Photo05)。
Photo05:この場合、メインの描画とPost Processingの映像効果を非同期に実行させることで、Post Processingなし(左)とほとんど遜色ない性能(右)を実現できている。同期にすると、どうしてもコマンドの切り替えなどでオーバーヘッドが大きくなるので性能が下がる(真中)という訳だ |
このAsynchronous ShadersがATWとどう関係してくるかであるが、まずレンダリングが間に合わないケースでは、次のシーンのレンダリングを引き続き行いながら、現フレームのTime Warp処理を並行してGPUで行うことができる。
この場合は、Time Warpを優先実行させる必要はあるだろうが、「いまのレンダリング処理を中断してTime Warpを実施し、その後でレンダリングを再開」するよりもオーバーヘッドは少ないし、「いまのレンダリングが終わってからTime Warp処理をする」よりも表示は自然になるだろう。
また、これはAsynchronous Shadersとは直接関係無いが。前回紹介したDirect-to-Displayの機能を使うと、まずはTime Warpでごまかし、あとで画面を更新する際に直接フレームを更新できるので、これもATWには有益な機能となる。
実際にはAMDはこの機能をACE(Asyncronous Compute Engines)と呼んでおり(Photo06)、Asynchronous Shader以外にもいくつつかの機能をまとめてGPU側で実装し、APIの形で提供しているとのことだ。
加えて、現在のDirectX 11は基本的にCommand Streamが1つを想定したAPIであるが(Photo07)、DirectX12やMantle、ChronousのVulkanなどは、いずれもMulti-Thread対応のAPIになっており、複数のCommand Streamをサポートする。GCNのACEは、こうしたケースでより効率よく動作する、というのがAMDのメッセージであった。