NVDA情報局(フラグ)

投資家目線でNVDAを買い煽るためのメモです

GPUのお勉強

【4Gamer.net】[連載]西川善司の3Dゲームエクスタシー:GeForceの父,David Kirk氏に聞く「GeForce 8800」

 

 

2006年11月9日に発表された「GeForce 8800」(開発コードネーム「G80」)は「統合型シェーダアーキテクチャ」(Unified Shader Architecture)によるものだった。

 

約2年半続いたGeForce 6800アーキテクチャからの決別だったともいえる「GeForceの父」として知られるNVIDIAのチーフサイエンティスト,David Kirk(デビッド・カーク)氏に話を聞いてみた。


GeForce 8800統合シェーダアーキテクチャが採用された理由

 「GeForce 8800のプロジェクトは4年前にスタートしています」と切り出したKirk氏は,「統合型シェーダアーキテクチャの採用に踏み切るまでには,かなりの数の実験を経ています。統合型シェーダアーキテクチャを採用しない計画も検討されていたのは事実です」と述べる。

 

f:id:booniebichon:20061203110751j:plain

GeForce 8800 GTXのパイプライン・ブロックダイアグラム

 

 

 DirectX 10世代のプログラマブルシェーダ4.0(Shader Model 4.0,以下SM4.0)では,シェーダの命令セットがほぼ共通化され,さらには「ジオメトリシェーダ」までも追加される。

 DirectX 9世代のプログラマブルシェーダ3.0(以下SM3.0)では,「○○シェーダ何基」という固定的な設計が必要で,プロセッサの本質的な部分は同じなのに「シェーダユニットはそれぞれ別物」として実装しなければならなかった。

 

そのため,例えば頂点シェーダに負荷がかかっていてボトルネックが発生している場合でも,ピクセルシェーダユニットは,“自分の仕事ではない”から,見て見ぬふりをするほかなかったわけで,これは無駄だ。

 

「頂点シェーダユニットからテクスチャアクセスを行う,頂点テクスチャリング(VTF:Vertex Texture Fetching)を実現しようとしたとしましょう。この場合,固定機能のシェーダアーキテクチャでは,『頂点シェーダユニットにテクスチャアクセス機能を付ける』という設計をしなくてはなりませんから,トランジスタコストがかかりますし,せっかく実装してもこれが活用されなければ無駄になります」(Kirk氏)。
 この点,統合型シェーダアーキテクチャであれば,汎用シェーダニットと汎用テクスチャユニットを用意して,前者に「後者にアクセスできる機能を持たせる」だけでいい。こうしておけば,汎用シェーダユニットが頂点シェーダとして起用されたとき,自動的にVTF機能がサポートされるようになる。逆に,VTFが活用されないプログラムが実行されているときは,汎用テクスチャユニットが呼び出されないだけなので,“VTF専用機能ロジックがヒマになる”わけではない。

 「DirectX 10の先,次期DirectXや次世代Shader Modelでは,プログラマブルシェーダとしてのテッセレータ実装も計画されています。このとき,テッセレータを役割固定式のプログラマブルシェーダアーキテクチャで実装するには面倒が増えます。それに,種類の増えた各シェーダが万が一活用されない局面が出てくれば,その非効率性はさらに増してしまうのです」と,統合型アーキテクチャを採用しなかった場合のデメリットを指摘したKirk氏。統合型シェーダを採用するメリットについては,将来を見据えつつ,次のようにまとめてみせた。

 「統合型シェーダアーキテクチャはスケーラビリティも持ち合わせていますから,(プロセスルールの進化に従っての)性能強化が容易です。汎用シェーダユニットの数を増やせばトータル性能を上げられるので,(“GeForce 8900”的な)G80の上位モデルも簡単に作り出せるでしょうし,逆に数を減らせば,ミドルレンジ以下やモバイル版のラインナップも比較的楽に作り出せるでしょう」

 


 かつてフルアーキテクチャ変更をしてパフォーマンス的に苦しかった「GeForce FX」(開発コードネーム「NV30」世代)の悪夢は記憶に新しい。革新的すぎるともいえる今回の新アーキテクチャ採用が,悪夢の再来を招く可能性はなかったのかという,いささか意地の悪い質問をしてみると,「今回は何千というシェーダを実行し,何百というアプリケーションをシミュレーションにかけました」と,万全であることをアピールする答えが返ってきた。そしてKirk氏はこうも続ける。

「今回のGeForce 8800は,アーキテクチャそのものも素晴らしいと自負していますけども,それ以上に,あらゆる状況下においてパフォーマンスが高いのが素晴らしいんです。これは,長らくGPU開発に携わってきたNVIDIAの歴史上,本当に初めての体験で,開発している我々ですら少し驚いたほどです」

 GeForce 8800は,とくにGeForce 8800への最適化が行われていないアプリケーションでも,本当に高速だ。統合型シェーダアーキテクチャは,発生しうるボトルネックを動的に潰せるという,いわばレンダリングパイプラインの自己再構成能力を身につけた点が革新的なわけだが,その効果は4Gamerで行ったベンチマークテストの結果からも十分窺い知れる。 


 このあたりはGeForce 8800 GTXが持つ128基のストリーミングプロセッサ(Streaming Processor)の威力もあるだろうが,それよりはストレスに強い統合型シェーダアーキテクチャの真価が発揮されている証だと思われる。

 

 

 

(参考)Xbox 360-GPUのブロックダイアグラム

f:id:booniebichon:20050831164303j:plain

 


 さて,統合型シェーダアーキテクチャではGPU内部の負荷を検知して,何基の汎用シェーダユニットをどのシェーダ機能に割り当てるかをリアルタイムで判断している。車のトランスミッションでいえば,オートマティック(AT)に相当するといったところだ。
 クルマの話を続けると,競技用車両では,パフォーマンスを最大限引き出すため,ほとんどの場合,ユーザー側でトランスミッションを切り替えられるマニュアル(MT)が採用されている。そして,PC用ではないが,世界初の統合型シェーダアーキテクチャ採用GPUである「Xbox 360-GPU」では,2006年12月時点の最新SDK(ソフトウェア開発キット)で,シェーダユニット単位でレジスタファイルの割り当てを行うことにより,汎用シェーダユニットのシェーダ機能割り振りをコントロールできる仕組みが提供されている事実もあるのだ。GeForce 8800シリーズに,こうした手動のシェーダ負荷バランス制御は提供されないのだろうか。

 「『最適解を求めるのではなく,コンスタントによい解を出し続けるられる』のが,オートマティックのよいところです。最適に近い負荷バランスが取れればそれでOKだと思いますし,GeForce 8800にはその能力があります。Xbox 360-GPUに関していうと,家庭用ゲーム機向けのゲーム開発という文化的背景が,そういった細かい制御まで行えるAPIを提供させたのでしょう。ハードウェア仕様が固定されたゲーム機では,ハードウェアを極限まで叩くというのが当たり前ですから」(Kirk氏)


GIGA Threadの秘密~GPUのマルチスレッディングって何だ?

 GeForce 8800シリーズでは「GIGA Thread」,AMDATI Radeon X1000シリーズでは「Ultra Threading」と,最近になって,GPU内部でのマルチスレッディング処理がアピールされるようになってきている。

 ただ,ここで注意したいのは,CPUでいうプログラムタスクのマルチスレッディングと,GPUのそれはちょっと違うことだ。
 CPUの場合,処理能力を細かな時間単位に分割(時分割)して,あたかも複数のプログラムが同時実行されているかのように見せる。これに対してGPUでは,1ピクセル(※頂点シェーダにおいては頂点データということになるが,ここでは話を分かりやすくするために題材をピクセルに限定する)を1スレッドとして扱い,時分割で各ピクセルに対するシェーダプログラム実行を行っていくのである。CPUではプログラム基準で時分割されるのに対して,GPUではピクセルというデータ基準で時分割されるのが,最大の違いだ。このあたりは,図1と図2に示してみたので,参考にしてほしい。

図1 CPUにおけるマルチスレッディングの概念

f:id:booniebichon:20061226130521j:plain

 

複数のプログラムを時分割実行するのがCPUにおけるマルチスレッディング

図2 GPUにおけるマルチ

f:id:booniebichon:20061222212935j:plain

スレッディングの概念

 

 

一つのプログラムを複数のデータ(ここでは頭の上に浮かんでいる各ピクセル)に適用するのがGPUにおけるマルチスレッディングだ。 CPUのマルチスレッディングでは,CPU全体で図1のような処理が行われるのに対し,GPUでは,図2で示したような処理が,複数セット,同時に進行していく

 どうしてこのような仕組みになっているのか? これは,ピクセルの数とシェーダプログラムの数を比較すると,イメージが湧くと思う。

 1シーンにおけるピクセルの数は数百万という膨大なものになるが,実行すべきシェーダプログラムは多くても1シーンあたり数百程度。つまり,一つのシェーダプログラムが複数のピクセルにおいて実行されることが多いのだ。同時に,ピクセルが映像を構成するものであることを踏まえると,隣接するピクセルに同じシェーダプログラムが実行される可能性が極めて高い。
 そこでGPUでは,一つのシェーダプログラムを複数のピクセルに対して実行する。一つのシェーダプログラムにある一つの命令は,データ基準で時分割され,複数のピクセルに対して実行されるのである。

 これを命令の「カスケード実行」というが,カスケード実行のメリットは,メモリに格納されているシェーダプログラムの命令フェッチやデコードの回数を少なくできるという点にある。メモリアクセスが非常に遅い処理系であるというのは周知の事実だが,そんな遅い処理系から苦労して取ってきて解釈した命令は,まとめて複数のピクセルに対して実行したほうが効率はいい,というわけだ。

 このあたりは,ピクセルA,B,C,Dという4ピクセルに対してシェーブプログラムが実行される,というイメージで,図3に示してみた。「何個のピクセル単位に対して一度にシェーダプログラムを実行するか」を説明する単語として「バッチ」が用意されており,この図だとA,B,C,Dの4個で1バッチという感覚だ。
 では,この図でシェーダユニットはどこかという話になると,(ちょっと分かりにくいかもしれず,申し訳ないのだが)ベルトコンベアと,実際に作業するスタッフの頭脳とか,そういったイメージになる。

図3 ピクセル陰影処理における内部処理の概念

f:id:booniebichon:20061222213029j:plain

ベルトコンベアの上を流しながら,順に命令を実行していくイメージ。特定のピクセルに対して条件分岐が発生した場合は,そのピクセルに対してのみ特殊工程を行うイメージになる。だから手間が掛かってスループットが落ちるのだ

 


 この点,GeForce 8800ではどうなっているのだろうか。Kirk氏は「一般論として,バッチのサイズを大きくすると,テクスチャアクセス(メモリアクセス)の際のレイテンシを隠蔽しやすくなります」と述べる。
 バッチに遅延が生じたら,その間にほかのピクセルの処理を行って時間稼ぎをすればいいし,そこにもメモリアクセスでレイテンシが発生するなら,別のバッチの処理に切り換えればいい(スレッド切り換え)。バッチサイズが大きいということは,処理すべき仕事をたくさん用意できるので,レイテンシを隠蔽できる確率が増えるのだ。

 「しかし」とKirk氏。「GeForce 8800では,このバッチサイズをGeForce 7900より小さくしました。理由は分岐時の遅延を小さくするためです」。
 例えば図3においてピクセルAに対して分岐が発生すると,ピクセルB,C,Dとは異なる命令が実行されることになる。バッチサイズが大きいと,分岐したときの各ピクセルに対して実行される命令に違いが出てくるので,せっかくのカスケード実行による命令フェッチの効率化の工夫が台なしになる――Kirk氏はこう指摘しているわけである。
 メモリレイテンシの隠蔽を重視したのがGeForce 7900以前,より複雑なプログラムが実行されることを想定して,汎用ベクトルプロセッサとしてのニュアンスを色濃く出したのがGeForce 8800ということになるだろうか。


 いずれにせよ,GeForce 8800では,CPUとまったく異なるマルチスレッディングが行われているわけだが,そのカスケード実行やスレッド切り換えの状態保持というのはどのように行われているのだろうか。Kirk氏は「ブロックダイアグラムには記載されていませんが」と笑いながら,次のように説明する。

 「スレッド状態保持を行うレジスタファイルはシェーダプロセッサ(=Streaming Processor)に組み込まれています。このレジスタファイルサイズは有限で固定的ですが,これで何スレッドが処理できるかということは固定的ではないんです。そのスレッドの状態を保持する情報量が少なければ,より多くのスレッドをシェーダプロセッサ側で処理できますし,スレッドがたくさん実行できればメモリレイテンシを隠蔽できる確率が高まります。スレッドが少なければ1スレッドに使えるリソースは増えるんですね。これはトレードオフといえるでしょう」

 こうした複雑なスレッド数の制御そのものもハードウェアで実現されているという。 「ここまでの複雑な制御をプログラマにやらせるわけにはいきませんからね(笑)」(Kirk氏)。


シェーダユニットから分離されたテクスチャユニット

 GeForce 7シリーズでは,ハイエンド向けの製品で,頂点シェーダユニットがピクセルシェーダユニットよりもやや高速で動作するというアーキテクチャが採用されていた。GeForce 8800ではこうしたマルチクロックドメインの考え方がより推し進められており,GeForce 8800 GTXの場合,シェーダユニットそのものがなんと1.35GHzで駆動されるという設計となっている。
 「テクスチャフィルタリングユニットは575MHzで動作しています。1.35GHzで動作するのは演算関係のみです。GeForce 8800ではテクスチャフィルタリング(=テクスチャユニット)を分離しています」(Kirk氏)とのことだ。テクスチャユニットは,いわばメモリ読み出し係。こうした部分を高速化してもあまり意味がないということなのだろう。

 

f:id:booniebichon:20061107142633j:plain

 

前出のGeForce 8800ブロックダイアグラムから,ストリーミングプロセッサ(SP)とテクスチャフィルタ(TF)部を拡大。ご覧のとおり,SPからTFは分離している

 

氏は続ける。「GeForce 7以前では,テクスチャユニットをシェーダユニットと一体化していました。これは,読み出したテクスチャを使った計算を効率よく行うのには最適なアーキテクチャだったという,当時の判断によるものです。
 この点GeForce 8800では,テクスチャユニットを分離して共有リソース化し,そして計算はシェーダユニット側のみで行えるようにしました。GeForce 8800のような統合型シェーダアーキテクチャでは,シェーダユニットがどういう用途で使われるか分かりませんから。なので,テクスチャユニットがシェーダユニットにくっついていてもあまり意味がないんです」

 シェーダとテクスチャユニットがペアであるGeForce 7までは,この特性を理解してシェーダプログラムを構成する必要があった。例えばテクスチャアクセス命令は連続させないで間に計算命令を挟んだほうがいいとか,テクスチャアクセス命令の直後には特定の命令を持ってきたほうが高速化できるとかなどだ。しかし,GeForce 8800ではテクスチャユニットを複数のシェーダユニットから必要に応じて利用できる共通リソースとして分離しているため,そうした命令の順序の依存関係によるパフォーマンスインパクトも低減できているというわけである。

 「シェーダプログラムが長く,そして複雑化してきている現在では,GPU側にもそれなりの進化と対応が要求されてきているんですね。GeForce 7時代のシェーダプログラムは“テクスチャアクセスと計算”の組み合わせで書かれることが多かったのですが,これからはスカラ計算があってベクトル計算があってテクスチャアクセスがあって……と,パターン化できないほど多様になっていくでしょう。これに対応するのがGeForce 8800というわけです。
 例えば我々の『エイドリアン・デモ』のスキンシェーダプログラムは,1000近い命令で構成されていますが,テクスチャアクセス関連の命令は確か20~30程度。一方であのカスケードというプロシージャル地形生成デモではテクスチャアクセスが多いんです」(Kirk氏)



 シェーダユニットとテクスチャユニットの分離は統合型シェーダアーキテクチャ実現のための必然だった。そしてそれは,DirectX 10/SM4.0時代におけるシェーダプログラム実行効率の側面からも意味があることなのだ。


スカラシェーダの“謎”が解明

 

f:id:booniebichon:20061216195745j:plain

GeForce 8800 GTXが持つ128基のシェーダユニットであるStreaming Processorは,単体だとベクトル計算を行えないスカラプロセッサである

 

 

個人的にはGeForce 8800の最大の謎とも思える,シェーダユニットがスカラプロセッサとなっている点について聞いてみた。

 「GeForce 8800のシェーダユニット,Streaming Processorはスカラです。ベクタユニットではありません。各スレッドはスカラタスクに分解されて実行されることになります」(Kirk氏)。
 ホワイトペーパーにも,「ベクトルから分解されたスカラタスクは,必要に応じて複数のスカラシェーダ(Streaming Processor)を起用して実行される」と書かれている。処理の単位を最小のスカラ単位に分けることで,常にシェーダユニットを稼働させられるというわけである。

 

 

f:id:booniebichon:20061216195902j:plain

GeForce 6/7やATI Radeon X1000シリーズではベクトル計算とスカラ計算の組み合わせによって命令の実行効率が変わってしまっていた

 

 

 

 DirectX 10のSM4.0では二進論理計算などの整数関係の命令が増え,結果,ますますGPUはCPU的になっている。CPUとGPUの境目が,それこそなくなってきているようにも思えるが,Kirk氏は両者の違いを次のように定義づけする。

 「1スレッドを究極的に高速化すること。これに技術力を集中させるのがCPUですね。はっきりいって我々NVIDIAは,そういったアプローチについてお手上げ状態です。なので,あそことあそこの会社にそういうのは任せてしまって(笑),我々は大量のタスクを同時に高速に実行する最適なアプローチを研究しています。それがGPUなんですね。
 2~4スレッドの高速化がCPUのテーマですが,我々のテーマは数千,いや数百万,数千万スレッドの同時処理です」

 しかし,そうはいっても,ここ数年のGPUは明らかにCPU的な進化を盛り込んでいる。動的分岐命令のサポートなどはまさにそうだし,構造化プログラミングに適した命令がどんどん追加されている事実もある。CPU的な命令実行効率向上の技術を取り入れていくような計画はないのだろうか。

 「シンプルなプログラムはとにかく速く,複雑なプログラムはそれほど実行効率が上がらなくてもまあいいかな……という方針でGPUを設計しています。例えば,CPUで採用されている分岐予測,命令順序入れ替え,レジスタリネーミングなどのCPU高速化技術をシェーダに適用したとすると,シェーダユニットの大きさや複雑さは現在の10倍近くなってしまうでしょうね。その結果として性能が2倍になるかもしれませんが,それは,我々にとって正しくないトレードオフなんです。そんな選択をするくらいなら,10分の1の大きさで,性能はそのままのほうがいい。
 GPUのタスクではたくさんのスレッドがあるので,一つのスレッドで行き詰まりがあったら,別のスレッドをやれば,その行き詰まりをある程度隠蔽できます。しかし,CPUの場合は少ないスレッドを究極的に速くしなければなりません。だから彼らには,そこに高いコストをかける意味があるんですよ」(Kirk氏)

 なるほど。今の最新CPUの高速化技術を貪欲に取り入れていこうという発想は,今のところないと見てよさそうだ。


次世代GPUの進化の方針について聞く


 基礎技術についてはかなり研究されているにもかかわらず,未だに標準仕様としては実装されていない,自動ポリゴン分割ユニットであるテッセレータ。DirectX 10/SM4.0の初期案では採用も検討されていたはずなのだが,今回も最終仕様では延期されてしまった。この事情についてKirk氏は,次のように述べる。

 「MicrosoftDirectXアーキテクト,David Blythe(デビッド・ブライス)氏も言ってましたよ。『テッセレータは我々が考えるよりも実装が難しかった』と。
 テッセレータについては,“使いやすいか”と“実装しやすいか”という,二つの側面で議論があります。開発者が望むテッセレータのスペックはGPUメーカーがうんざりする仕様でした。そして逆に,GPUメーカーが提案したテッセレータの仕様には開発者がうんざりしていましたよ(笑)。……今は,どこに落としどころを見つけるか,議論が交わされているところです」

 ゲームのようなリアルタイム3Dグラフィックスにはちょっと荷が重いが,マルチパスとストリーミングアウトプットを活用すれば,ジオメトリシェーダでテッセレータと同等のことは行える。これでしばらくはしのいでくれということなのだろう。
 サンプル点を自在に設定できる「プログラマブルアンチエイリアシング」についてはどうだろうか?

 「『エッジのジャギーを減らしたい』というのは開発者達の共通の願望ですが,私の知る限り,それをプログラマブルでやりたいと主張している開発者がいないんですよ。誰かそんな人知ってますか?(笑)
 プログラマブルアンチエイリアシング機能を短期的に実装しようという計画はあまりないように思えます。一方,エッジのジャギーを高効率に低減するという意味では,今回,GeForce 8800で実装されたCoverage Sampled Anti-Aliasingが有効だと思いますね」(Kirk氏)


 このほか,3Dグラフィックスに残された課題といえば,やはり半透明の処理だろう。半透明描画は描画順序にシビアであり,これがキモになるが,Kirk氏は,次のステップとして,「A-Buffer」的なアプローチが導入される可能性を指摘する。

 「A-Buffer的なアプローチ。よりフラグメントベースな考え方ですね。A-Bufferはそのまま実装しようとすると無限大の複雑性が絡んでくるのでリアルタイム実装は難しいですが,アンチエイリアスと透明なものの重ね描き順序の問題から解放されたいというのは皆が言っていることですからね。いずれ解決されなければならないでしょう」

 A-Bufferとは,Lucas Filmが考案したメソッドで,レンダリング時にシェーダで算出されたカラーや輪郭のマスク情報を,Z位置情報などと一緒に記憶していくもの。最終描画後にはつじつまが合うように映像を合成する(再構成する)必要があるものの,レンダリング時には描画順序を無視できるというメリットがある(メモリを膨大に消費するという弱点もあるが)。数世代先のGPUでは,これに近い仕組みの導入が必要かもしれないとKirk氏は予見しているわけである。