オススメ機能
Twitter
お気に入り
記事履歴
ランキング
お気に入りタイトル/ワード

タイトル/ワード名(記事数)

最近記事を読んだタイトル/ワード

タイトル/ワード名(記事数)

LINEで4Gamerアカウントを登録
NVIDIAの新機軸を理解する(2):DirectXの進化が止まったいま,ゲームグラフィックスはもうGPGPUに頼るしかない!?
特集記事一覧
注目のレビュー
注目のムービー

メディアパートナー

印刷2012/09/28 00:00

ニュース

NVIDIAの新機軸を理解する(2):DirectXの進化が止まったいま,ゲームグラフィックスはもうGPGPUに頼るしかない!?

 Keplerアーキテクチャを採用するGPUの市場投入に合わせて,NVIDIAが打ち出した新基軸の内容を細かくチェックするシリーズ第2回。今回は,CUDA対応GPUの歴史を振り返りつつ,来たる「GK110」,そしてその先に控えるGPUの姿を占ってみたい。

 当たり前の話だが,GPUという概念はもともと,3Dグラフィックスをレンダリングするためのものとして誕生した。
 ここでいう「3D」は立体視という意味ではなく,x,y,z座標からなる三次元の仮想空間上で管理されるオブジェクトを描画することで作り上げられる映像のことを指す。

 3Dグラフィックスの描画は,視線(=カメラ)の向き,描画対象の面(=ポリゴン)あるいはピクセルの向き,これを照らす光源の向きなどを基に計算される。向きはx,y,zの3要素からなる「単位ベクトル」で表すことができ,3Dグラフィックスを実現するための計算はベクトルの同士の内積と外積,あるいは加減算によって行われる。

3Dグラフィックスの描画はベクトル計算によって成り立っている
CUDA

 グラフィックス描画の最小単位はピクセルになるが,ピクセルごとのライティング計算には基本的に依存関係がないため,並列に実行できる。よって,グラフィックスレンダリングの性能を上げるためには,たくさんの演算器を搭載すればよいことになる。

 GPUにおける演算器には,グラフィックス描画にある程度特化した機能が与えられたため,「陰影(shade)処理を行うユニット」という意味の「シェーダユニット」(Shader Unit)という呼び名が与えられた。NVIDIAに限らず,黎明期におけるGPUの進化史は,とにかく,このシェーダユニットの増設の歴史に等しかったのだ。
 以降,CPUとGPUの対比はよく行われ,「スレッド」という言葉が登場した。「CPUは少ないスレッドを処理するのに適し,GPUは大量のスレッドを処理するのに適する」というのはよく用いられるフレーズである。ただ,これは少々誤解を生みやすい。

 CPUで取り扱うスレッドとは,プログラムの流れ(=実行)そのもののことであり,プログラムそのものの並列実行には,物理コアか論理コアかはさておき,基本的にコアの増設で対応する。
 一方,GPUで取り扱うスレッドとはデータ処理のことを指す。GPUでは,あるプログラムを複数のデータに適用していく考え方になるためだ。複数のプログラムを実行させるには,GPUでも,ひとかたまりのベクトル演算器を集めたプロセッサコアを増やすことで対応する。NVIDIAのGPUで言えば,「Streaming Multiprocessor」(以下,SM)が「ひとかたまりのベクトル演算器を集めたプロセッサコア」である。

CPUは数スレッド,GPUは膨大なスレッド数を処理するが,「スレッド」そのものの意味がCPUとGPUでは異なる点に注意したい
CUDA

馬路 徹氏(Sr.Solution Architect, NVIDIA)
 NVIDIAの馬路 徹氏は,2012年7月下旬開催のイベント「GTC Japan 2012」において,GPUのシェーダユニット数増加を縦軸,時間を横軸にとったグラフを下のとおり示した。
 一見しただけだと,時間経過に合わせた線形な増加傾向にある雰囲気だが,縦軸が対数になっていることには注意が必要だ。つまり,GPUのシェーダユニット数は指数関数的に増加してきたのである。

NVIDIA製GPUにおけるシェーダユニット数の変遷
CUDA


GPGPUプラットフォームとして誕生したCUDAとは何か


 こうして指数関数的に増加するGPUのシェーダユニットを,グラフィックスレンダリング用途以外で活用しようとする動きが生まれる。これがGPGPU(General Purpose GPU)の概念だ。

 前述したように,GPUの演算の最小単位はベクトル演算器である。これが大量にあるGPUは,いわばスーパーコンピュータと呼ぶに相応しいのではないか……。このように「実はすごいんじゃないか?」という期待のまなざしを向けられて,GPGPUは誕生した次第である。

 ただ,最初期のGPGPUは,汎用演算のプログラムを,グラフィックスレンダリングに見立ててGPUに実行させるアプローチを取っていた。
 GPUとしては普段通りグラフィックスをレンダリングしているだけのつもりだが,フレームバッファには映像ではなく,「欲しい演算結果」が書き込まれるように仕向けたレンダリングプログラムを動かすという手法だ。GPUをある意味,無理矢理にGPGPUとして使おうとしたわけである。

NVIDIA製GPUにおける倍精度演算性能の推移。CUDAの導入以降,飛躍的に向上しているのが分かる
CUDA
 これはハック手法としては面白かったが,GPGPUを万人に利用してもらうためのうまいやり方とはとても言えない。そこで次に期待されたのが,グラフィックスレンダリング以外に利用が可能なGPUアーキテクチャと,これを簡単に利用できるようにするためのプラットフォームだ。
 NVIDIAは,そうした声に応える形で,新しいGPUアーキテクチャ「Tesla」(テスラ)を開発した。4Gamer読者になじみ深いGPU名でいえばGeForce 8000シリーズである。そして,Teslaアーキテクチャとほぼ同じタイミングでリリースされたGPGPUプラットフォームが,「CUDA」(Compute Unified Device Architecture,クーダ)となる。

 CUDAの根幹となるプログラミング言語は,一般的なC言語をベースに,ベクトル拡張してC++のエッセンスを導入した「CUDA C」である。下のスライドは,CとCUDA Cの間にある言語体系の違いを示したものだ。

CコードとCUDA Cコードの違い
CUDA

 計算対象のデータを参照するためのインデックス変数を増加させつつ,プログラムをループで回すことによって処理するC言語に対し,CUDA Cでは,「計算対象のデータに対してどんな計算をするのか」を「カーネル」として定義するような概念になっている。上のスライドでいえば,修飾子「__global__」がGPUで実行するためのカーネルの宣言に相当する。
 CUDAでは,「データ処理を行う流れ」である「スレッド」を32個まとめて「Warp」と呼ぶ。CUDAの概念だと,Warpは,定義したカーネルが一度に並列実行されるときの最小単位となっている。

 またCUDAでは,この32スレッド=1 Warpを複数集めた単位を「Block」として定義している。Compute Capability() 1.x(以下,CC1.x)では1 Blockあたり16 Warp(=512スレッド)まで,Compute Capability 2.x(以下,CC2.x)以上では32 Warp(=1024スレッド)をひとまとまりのBlockとすることができる。

 なお,Blockサイズ以上のスレッドを並列処理させたい場合には,複数のBlockをひとまとまりにした「Grid」という概念を用いることになる。
 CC1.xだとGridに与えられる最大次元数は2(=x,y),CC2.x以上では3(x,y,z)。各Gridに与えられる次元長は,CC1.xだとx,yに対して65535(216-1)のところが,CC2.x以上ではx,y,zに対して2147483647(231-1)へと拡張されている。

WarpとBlock,Gridによる階層構造の例
CUDA

 GPUに対する「実際の計算」の発注はGrid単位で行われ,GPU内では,この中に含まれる複数BlockのそれぞれをGPU内のSMに割り当てて実行していく。
 Blockの数がSMの数を大きく超える場合,各SMは,複数Blockの実行も担当する。要するに,メモリアクセス時などといった大きなストール時における実行対象の切り替えは,Warp単位だけでなく,Block単位でも起こりうるということである。
 なので,実行順序はWarp単位だけでなく,Block単位においても順不同の並列処理となる。一方,異なるBlock間の同期処理はサポート対象外だ。これは最新のKepler世代のCompute Capability(以下,CC3.x)になっても変わらない。

※Compute Capabilityとは何か
 CUDAは定期的にバージョンアップされている。2012年9月時点における最新版はCUDA 5.0(※βリリース)だ。
 ただこれとは別にNVIDIAは,新しいアーキテクチャのGPUを発表するごとに,そのGPUが対応できるGPGPUポテンシャルのバージョン番号をCompute Capability(計算能力)バージョンとして提示している。

 ここがややこしいのだが,CUDAとCompute Capabilityのバージョン番号は同期していない。本文でも触れたとおり,Kepler世代のGPUにおけるCompute Capabilityバージョンは3.0だ。
 DirectX(=Direct3D)にたとえると,CUDAバージョンがDirectXバージョン,Compute Capabilityバージョンがプログラマブルシェーダ仕様(=Shader Model)バージョンのようなイメージといったところか。


並列処理に条件分岐を持ち込んだ「SIMT」


 CUDAに限らず,GPGPUでは,CPUのように「1つ1つの処理を正確に進めていく」というよりむしろ,「大量の計算を一度にやって,不要な計算結果は後で捨てる」という思想がベースにある。
 そうはいっても,各計算処理(=カーネル)において,最低限の論理処理は行っておきたいが,同一カーネルを複数スレッドで動かして,異なるデータに処理を適用していくGPGPUの概念において,論理処理の導入は難しいテーマでもある。

 「論理処理」というのは何か。グラフィックスレンダリングで喩えて簡単に説明すると,「異なる座標のピクセルごとに,1つのピクセルシェーダプログラムが陰影処理のやり方を微妙に変えていく」ような処理に相当する。
 この実現には条件分岐の処理系が欠かせないのだが,ここで,「条件分岐なら,Shader Model 2.0でも頂点シェーダに対して限定的に,3.0なら頂点シェーダででもピクセルシェーダででも処理できたはずでは?」と疑問を持った読者もいるのではないだろうか。

 実はそのとおりだ。だがCUDA対応のGPU(=Shader Model 4.0以降に対応したGPU)からは,こうした条件分岐実行の仕組みを一般拡張化してきたという違いがある。
 それが「Predication」(プレディケーション,断定・賓述)という概念だ。

 Predicationでは命令実行にあたって「実行するか否か」の判断が常になされる。
 一般に条件分岐(=ジャンプ)では,条件成立時,あるいは不成立時にプログラムの実行アドレスを変更する。それに対してPredicationでは,条件分岐が起きてもプログラムの実行アドレスは変更されない。条件判断だけを行って,その結果を基に,それ以降の命令実行時に逐一「実行するか否か」の判断を行っていくのだ。

 Predicationの利点は並列処理の流れ(=パイプライン)を乱さずに条件分岐が実現できること。一方で,たとえ条件分岐による分岐が成立しても,全スレッドで条件分岐成立時/不成立時,両方の命令を実行する(というか「なぞる」)ことになるため,処理時間が長くなってしまう弱点がある。
 プログラムの実行アドレスを変更する条件分岐の実行形態では,分岐成立時に処理を早く終えることができるが,Predicationではこれができない。今日(こんにち)のGPUが,グラフィックスレンダリングにおけるプログラマブルシェーダで「条件分岐を使うと遅くなる」というのはこの理由からだ。

 もっとも,大規模な並列処理を行うことが目的となるGPGPUの世界においては,デメリットを補って余りあるほど,CPUで行うよりも圧倒的に高速な処理が行えるので,この仕様は歓迎されている。
 そしてNVIDIAは,こうした「条件分岐に対応した並列命令実行形態」を「SIMT」(Single Instruction Multiple Threads) 処理と位置づけている。

条件分岐に対応したNVIDIAの並列処理,SIMT
CUDA
 ところでまったくの余談だが,プロセッサの分岐処理技術関連用語に「Prediction」(プレディクション)というものもある。Predicationの「c」と「t」の間にある「a」がなくなった英単語だが,こちらは意味が一転して「予測」の意となり,投機実行などの分岐予測に関連する技術解説によく登場する。PredictionとPredicationは,見た目こそよく似ているものの,意味はまったく異なるので注意したい。


CUDAは中間言語「PTX」への変換後に実行される


 CUDAの実行は,実は二段階のプロセスを経ている。実際にCUDAプログラミングを行っている人にとっては当たり前の話だが,一般ユーザーにはあまり知られていないかもしれないので,お伝えしておこう。

 CUDAプログラムは,コンパイルによって「PTX」(Parallel Thread eXecution)と呼ばれる中間言語へと変換される。実際のGPUが実行するときは,ドライバでPTXをさらにネイティブなGPUコードへ変換するという流れだ。

CUDAプログラムはPTXに変換される。GPUはそのPTXをさらにネイティブコードに変換してから実行しているのだ
CUDA

 CUDAの互換性はPTX上で取られており,GPUネイティブコードはGPU製品ごとに異なっているため,互換性がない。こうした手法は珍しくなく,身近なところではJavaがそうだし,Intelのx86系CPUもいまや実行ファイルに含まれているx86コードを直接実行しているのではなく,x86系CPU世代ごとに異なるRISC風のマイクロコード(μOp)へとCPU内部で変換してから実行している。CUDAだけが特殊というわけではないのである

SMにおけるPTXの実行を概念的に表した図
CUDA


CUDA対応GPUの進化


Teslaアーキテクチャを採用するGeForce 8000シリーズから,NVIDIA製GPUは統合型シェーダアーキテクチャへ
CUDA
 前述のとおり,NVIDIAのCUDA対応は,Teslaコア世代から始まった。
 このタイミングでDirectXはDirectX 10となり,GPUは統合型シェーダ(Unified Shader)アーキテクチャへと変革のときを迎えた。それまでのGPUは,頂点処理用の頂点シェーダとピクセル処理用のピクセルシェーダという,「用途限定のシェーダユニット」で構成されていたが,統合型シェーダアーキテクチャでは,汎用シェーダユニットを多数揃え,適宜それらを頂点シェーダやピクセルシェーダなどとして起用するようになったのだ。

 もちろん,用途を限定しない「汎用シェーダユニット」の形態にしたことと,GPGPUへの対応化は無関係ではない。なお,Tesla世代のCompute CapabilityバージョンはCC1.xとなる。

CUDA
汎用シェーダユニットを複数ひとまとまりとしたSMという概念が確立したのもこのタイミングだ
CUDA
SMが単位時間あたりに処理できるのは1 Warpだが,複数のBlockを処理していく能力がある

GPGPUにフォーカスした設計となったFermiコア
CUDA
 続くFermiコア世代では,GPGPUへより一層フォーカスした設計となった。筆者などは,Fermiアーキテクチャが登場したとき,GPGPU用途に重きを置きすぎているのではないかと感じたほどだ。

 なにしろ,リアルタイムグラフィックスレンダリング用途ではもてあまし気味な倍精度浮動小数点演算性能がTeslaコア比で8倍に高められており,メモリシステムはECC(Error Check and Correction,誤り検出訂正)に対応(※GeForceでは利用不可)。アドレス空間は1TBにまで広げられたのである。結果的に,このアーキテクチャ方針が,NVIDIAにスパコン分野での成功をもたらすと同時に,GeForceでは「DirectX 9アプリケーションを前にすると,競合製品より性能面で不利」という結果を生んだので,確かにFermiはGPGPU寄りのGPUコアだったといえるだろう。

TeslaとFermiのスペック比較
CUDA

 なお,Fermiコアは主にGeForce 400〜500で採用されたものだ。GeForce 400の時点でDirectX 11対応を果たし,Compute CapabilityもCC2.xへとバージョンアップしている。

FermiコアではSMあたりの汎用シェーダユニット(=CUDA Core)量が増強された
CUDA
 Fermiコアの大きな拡張仕様としては,各SMで限定条件付きながらも複数カーネルの実行を可能にする機能「Concurrent Kernel Execution」(以下,CKE)が挙げられる。
 Teslaコアにおいて,各SMは1つのカーネルに対して複数スレッドを処理できたが,FermiコアではSMごとに異なるカーネルを実行しつつの複数スレッド処理ができるようになったのだ。これはCC2.xからの機能であり,同時実行カーネル数は最大16となっている(※もちろん実際には,GPUの搭載するSM数によって上限は異なる)。

複数Kernalの同時実行に対応したFermi世代
CUDA
 このCKEにより,たとえばCUDAベースの物理シミュレーションエンジンであるPhysXで,流体物理と剛体物理を同時に処理することができるようになった。
 しかし,グラフィックスレンダリングとCUDA実行は同時処理できない。動作モードを切り替えねばならないからだ。
 モード切り替えを行うコンテキストスイッチの性能はFermiでTesla比約10倍高速化されて,その所要時間は25ms以下となっているが,この値は依然として,リアルタイムアプリケーションにとっては相応に長い時間である。


Kepler「GK110」はさらにGPGPU方向へ進む


 そして現行世代,Keplerコア世代では,DirectX 11.1に対応し,Compute CapabilityバージョンもCC3.xとなった。
 SMのデザインはさらに拡張され,SMあたりのCUDA Core数はFermi世代比で4〜6倍の192基となった。Fermi世代の複数SMを統合して1基の大きなSMにしたようなものになったことから,NVIDIAはKeplerから,SMを「Streaming Multiprocessor eXtreme」(以下,SMX)と改称している。

SMのデザインが一新されSMXとなった。従来のSMを複数まとめて1つの大きなSMにしたような構成
CUDA

GK110のブロック図。13〜15のSMXを搭載するとされるので,CUDA Core数は最大2880基に達する計算だ
CUDA
 さて,4GamerではKepler世代のGPUが3D性能に振った製品であることを繰り返してきたが,実のところNVIDIAは「GPGPU向けKepler」というものも用意している。それが,第2世代Keplerのフラグシップモデルとして開発中の「GK110」(開発コードネーム)だ。
 最大で15基のSMX,CUDA Coreにして2880基を統合するため,かなりのビッグチップになると予測されるGK110。NVIDIAはそんなGK110において,GPGPU用途向けの二大機能,「Dynamic Parallelism」「Hyper-Q」を導入する計画になっている。

 まずDynamic Parallelism(ダイナミックパラレリズム)は,実行中のスレッドが,子Grid・Block・Warpを再構成して実行できる仕組みのことである。
 Dynamic Parallelismを利用すると,現在処理中のスレッドが,処理対象データに適した別の演算粒度の子スレッドを立ち上げて精度の高い処理結果を得たり,再帰的な解析処理などを実現できたりするようになる。ちょっと強引な喩えかもしれないが,GPU内で自在にジオメトリを消滅・生成することが可能なジオメトリシェーダのようなイメージかもしれない。

Dynamic Parallelismにより,GK110ではスレッドが子スレッド(=Grid)を立ち上げることが可能になった
CUDA

 Dynamic Parallelismでは,CPU側のプログラムに判断を仰ぐために処理系を戻したり,データのコピーをしたりする必要がなくなることから,従来比で性能向上をもたらす効果も期待できる。

格子分割して行う流体シミュレーションの場合,従来は,その格子密度をあらかじめ決めておく必要があった。それに対し,Dynamic Parallelismを用いれば,処理対象データの密度に応じて格子密度を切り直しつつのシミュレーションを,GPU内におけるカーネルの判断だけで実行できる
CUDA

左が従来の処理形態。右がGK110の処理形態。CPUに判断を仰ぐことなく,GPU側カーネルの判断で適宜処理を行えるようにできるという図だ
CUDA

LU分解のプログラムを従来のGPU(左)とGK110(右)とで実行させたイメージ。GK110では処理のほとんどをGPU内で帰結できる
CUDA

Hyper-Qの概要
CUDA
CUDA
 二大機能のもう1つ,Hyper-Q(ハイパーQ)は,一言でまとめるなら,Fermi世代におけるCKEの進化版,あるいは拡張機能といったイメージだ。
 「異なるカーネルをSMごとに実行できる」という基本機能はFermi世代のCKEと同じだが,Fermi世代のCKEだと,CPU側からGPUにたくさんの処理を発注した場合,GPUは発行順に処理するので,その処理の群れに依存関係があったりすると,後ろに控えている別カーネル用の処理がいつになっても始まってくれなかった。
 異なるカーネルを同時に動かせるのは,発注された処理系のうち,依存関係が途切れるときに限定されたのだ。

 その点,Hyper-Qを搭載するGK110では,CPUから処理が発注されたときに,依存関係がないことを明確にできるようになった。これにより,CKE動作がさらに効率よくなるというわけなのである。

Fermi世代のCKE(左)と,GK110におけるHyper-Q(右)の違い
CUDA

 この「複数の同時発注された処理系を溜め込んでおくところ」を「キュー」(queue)と呼ぶが,これがGK110では32ある。つまり,ベストケースでは32ストリームを同時に動かせるということになる。

Hyoer-QによってGPUコアの利用効率が高まる。言い換えると,GK110になってやっとCKEがまともに使えるようになったイメージだ
CUDA


ゲームグラフィックスはGPGPUを前提とした進化の道へ?


GTC Japan 2012で馬路氏がまとめに使っていたスライド
CUDA
 こうしてあらためて見てくると,NVIDIAが,Tesla時代にCUDAを導入してからというもの,相当な情熱を持ってGPGPUに特化した新機能を詰め込んできたことがよく分かる。正確を期すと,第1世代Keplerではいったん後退しているわけだが,GK110が「GPGPU特化型新機能を詰め込んきている」のは間違いない。

 スーパーコンピュータの最大性能ランキングである「TOP500や,1WあたりのFLOPS値をランキングした「Green500」などを見ても,上位にNVIDIAのGPUを搭載したスーパーコンピュータが登場し始めており,NVIDIAのGPGPU重視戦略は徐々に結果を出しつつある印象である。
 さらに,先の記事でお伝えした,GPUの仮想化技術を応用する「GeForce GRID」などのようなクラウドシステム向けGPUソリューションなどが台頭してきていることも考えると,GPUの「グラフィックス以外の機能の拡張」はさらに広がっていきそうだ。

最近になって2014年になるという話も聞こえだしたが,NVIDIAはKeplerの次に,Maxwellアーキテクチャの導入を控えている。ちなみにグラフィックスAPI的にはDirectX 11.1に留まる可能性が濃厚
CUDA
 グラフィックスに関して言えば,2009年のDirectX 11以降,進化は停滞している。10月下旬に発売予定のWindows 8ではDirectX 11.1が標準搭載される一方で,たとえば“DirectX 12”や新しいShader Modelといったメジャーバージョンアップは,少なくとも今のところは予定されていない。
 一方のNVIDIAは,GPUの進化をやめるどころか,増えつつあるGPGPUユーザーのため,近未来に登場するGPUの性能指標を盛り込んだロードマップまで公開している。GPUの進化をさらに推し進めていく姿勢を明確に打ち出しているのである。

 となると,グラフィックスは進化せず,GPUはだんだんとGPGPU的な,言うなればCPU的なものになっていくのだろうか。

 実は,それがそうでもない。むしろグラフィックスは,GPGPU的な機能を利用し,取り込みつつ,進化していこうという流れが出てきているのだ。
 2011年に売されたElectronic Artsの「Battlefield 3」PC版では,GPGPUを活用したディファードシェーディング(Deferred Shading)レンダラーや,GPGPUベースのカリングシステムを実装して注目を集めた。また,E3 2012で公開されたEpic Gamesの「Unreal Engine 4」におけるリアルタイムのグローバルイルミネーション(Global Illumination,大局照明)を実現するために採用されたスパースボクセルオクツリー(Sparse Voxel Octree,関連記事)は,シーンのジオメトリ構造を解析して八分木(octree)化する処理をGPGPU的に行っている。
 今後は,GPGPUの機能進化が,新しいゲームグラフィックスの表現までをもたらしてくれるようになるかもしれないのだ。

Unreal Engine 4におけるリアルタイムグローバルイルミネーションエンジンのベースとなった論文「Interactive Indirect Illumination Using Voxel Cone Tracing: An Insight」より。ムービー後半に出てくる空間を,異なる大きさの箱で分割する処理系をGPGPU的に実装。ちなみにムービーでは,この箱単位で各方向からの光の情報を管理し,ライティングに応用している

NVIDIAの新機軸を理解する(1):GeForce GRIDが描く「ゲームスタジオが独自のゲームプラットフォームを描く時代」

  • 関連タイトル:

    CUDA

  • この記事のURL:
4Gamer.net最新情報
プラットフォーム別新着記事
総合新着記事
企画記事
トピックス
スペシャルコンテンツ
注目記事ランキング
集計:09月18日〜09月19日
タイトル評価ランキング
81
KENGOHAZARD2 (PC)
76
鬼ノ哭ク邦 (PC)
76
Days Gone (PS4)
74
2019年03月〜2019年09月