既報の通り、AMDは3月26日にバーチャルリアリティ(VR)向けの技術「LiquidVR」について説明を行ったが、この際に公開された「Asynchronous Shaders」に関する詳細についてもう少し説明したいと思う。

TimeWarpとは何か

まず前回はさらっと流したTime Warpについてもう少しきちんと説明しておく。Time Warpという用語そのものはOculus VRの用語であるが、AMDなども同じ意味でこの用語を使っており、すでに一般的な用語になっているかと思う。

Oculus VR自身もこのTime Warpingの働きを詳細に説明した動画を公開しているが、さすがにちょっと長いのでかいつまんで要点を説明したい。

Photo01は前回の記事でも紹介したLatest Data Latchのスライドだが、操作者が右に向かって振り向く場合を考えてみると、頭の回転を検知して、表示している画面を空から水面の方向に順次切り替えてゆくことになる。

Photo01:当初は空を見ているのが、振り向き終わると水面と陸の境目に視点が合うことになる

ただ、処理の流れが「回転検知」→「次描画位置の確定」→「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は本当にこれを並行して実施できる。

Photo02:GCN以前では、そもそもGraphicとCompute、Copyの3つの処理を同時に実施することはできなかったし、NVIDIAのGPUは現在も同時に行うことはできない

Photo03:ただし、これが必ずしも有利かどうかは微妙なところ。4K Displayなどにフルに表示するのであれば、こんな風に処理に応じてシェーダをそれぞれ個別に動かすよりも、すべてのシェーダで一気に例えば描画処理を行ったほうが効率が上がる場合もあるからだ。ただOculus VRの場合は初期版で1280×800pixel、第2版でも1920×1080pixelなので、全シェーダで一気に描画処理をするにはやや描画サイズが小さい気はする

これをサポートするため、GCNでは複数のCommand Streamをサポートしており、それがどう実施されるのかはGPUに任せることができる(Photo04)。実際にこのAsynchronous Shaderを利用する事で、大幅に性能を改善できるケースがあることが示されている(Photo05)。

Photo04:もちろんGPUに全部任せると間に合わないというケースもあるので、プライオリティ付けや優先実行などもサポートしている

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の形で提供しているとのことだ。

Photo06:Time Warp以外もImage WarpとかGlobal Illuminationなどがサポートされているとする

加えて、現在のDirectX 11は基本的にCommand Streamが1つを想定したAPIであるが(Photo07)、DirectX12やMantle、ChronousのVulkanなどは、いずれもMulti-Thread対応のAPIになっており、複数のCommand Streamをサポートする。GCNのACEは、こうしたケースでより効率よく動作する、というのがAMDのメッセージであった。

Photo07:これはまぁご存知の通り

Photo08:ちなみにNVIDIA GPUの場合、High-Priority Contextと呼ばれる機能を実装しており、一応複数の処理を並行して実施できるが、このイラストほどの自由度は流石にない