よくわかるWindowsの表示システム(本当に?)
バツ
Direct ×
by Suginohara-meijin
- 連載第1回 -

 WindowsというOSにDirect Xが登場して久しくなります。その昔、Windowsではグラフィカルな高速ゲームを動かすことは不可能だと言われていましたが、それではマズいとビルが考えたわけですね。そのこと自体は正解だったと思います。私も当時のGDI(Graphic Device Interface = Windowsにおけるグラフィックを扱う関数群および仕様)では、書き替え面積の広いリアルタイムゲームは無理だったと思います。ビットマップデータをまともに扱う気があるのか?とさえ思いました。意識が完全にビジネスソフトにあったことは明白です。ラインや矩形、文字などに比べ、とにかくビットマップの表示が低速だったのです。

 焦ったMicrosoftが採った行動はWinG(ウィン・ジー)の配布でした。これは拡張GDIのようなもので、実際の表示画面とメモリ上の仮想画面を等価なものにして、“仮想画面から仮想および実画面への転送を高速化する”ことが柱になっていました。Windowsでは画面(仮想画面も含む)に何かを表示するとき、表示するデータを表示される画面に合わせて色情報などを変換しながら転送するためです(色数が下がると自動的にディザをかけたりして・・・セーフモードで起動すると分かりますよね)。これは意外と(?)功を奏し、WinGを利用した高速ゲームが数多く発売されました。風雅システムの「覇皇雀戦鬼 for Windows」もその中の一本です。ちなみにそのときのWinG担当が筆者です(WinGサンプルプログログラムのいい加減さには言葉を失ったものです)。

コラム1 グラフィックカードとV-RAMとディスプレイの関係
 通常、パソコンが画面を表示する仕組みは上図のようになっています。
 AGPあるいはPCIソケットに挿されたグラフィックカードの中にはV-RAMと呼ばれる高速メモリが載っています。ボード上のグラフィックコントローラチップはこのV-RAMの一部を常時読み出してビデオ出力に送り出しています。ディスプレイはこの信号を目に見えるように表示しているわけです。
 このような仕組みのため、V-RAMの常にビデオ出力に送られているいる部分のメモリ(実画面と呼びます)にデータを書き込むことによって、任意の色や形を表示できるのです。
 最近はマザーボード上のチップセット内部にビデオ回路を内蔵し、V-RAMもCPUと同じメモリの一部を流用するタイプが増えてきました。これも仕組みはほぼ同じで、グラフィックカードがチップセットに入っただけと考えて差し支えありません。メモリの共有に伴ってV-RAMのアクセス速度が低くなりますが、専用のキャッシュを持つなどして実用的な速度を実現しています。

 しかし、WinGといえどゲーム専用機に比べれば低速です。それもそのはず、実際のV-RAM(Video RAM = その内容が直接画面に表示されるメモリ)を制御するビデオチップを、Windowsではアプリケーションが直接制御することができないからです。何をするにもグラフィックデバイスドライバという、そのビデオチップ専用のインタフェース関数群を介さねばなりません。おまけに、GDIが必要とする機能さえサポートしていればよいわけですから、スプライトのような付加機能を持っていても、それを生かすことができません。つまりはこういうことです。

 シューティングゲームにおいて、画面からはみ出すデカキャラが登場しました。プログラムは背景を描画し、自機や弾丸、そしてデカキャラを合成表示しようとします。通常のビデオチップはV-RAM内の矩形領域のコピー機能を持っています。もちろん指定色を抜いて合成コピーする機能もありますから、V-RAM内の画面に表示されない部分にマスク色の付いたビットマップパターンがあれば、簡単にスプライト機能を実現できます。また、このメモリ転送処理はビデオチップ内のハードウェアやマイクロコードで実行されますし、CPUにも一切負荷をかけない(V-RAMが独立している場合)ので非常に高速です。多くのゲーム専用機は実際にこのような手法で画面を描画しています。

コラム2 高速キャラクタ合成表示(疑似スプライト)
 ビデオチップ(グラフィックコントローラ)を直接制御してキャラクタの合成表示を行う場合、例えば上図のような方法があります。ビデオチップに直接接続されているV-RAMの中に実画面(実際に表示される画面)と同じサイズのメモリ領域をいくつか確保します(画面1~3)。例えば画面2を実画面に設定して表示させている間に、画面1に同じV-RAMの空きスペースに登録したキャラクタデータ(上の例では女の子)を転送します。この処理はほとんどのビデオチップがハードウェア的に実装している機能で実行できるため非常に高速です。そして転送が終了した後にタイミング良く(通常はV-BLANKING発生時)画面1を実画面に設定すれば瞬間的に表示が切り替わるため、チラツキも発生しません。そして同様の処理を今度は画面2に対して行っていくわけです。この実画面とその等価画面の2枚を交互に使って表示する手法を「フリップ」と呼びます。
 合成するデータに透明色を持たせておけば、擬似的にスプライト(移動画面)を実現することができます。現在はV-RAMもビデオチップも超高速ですから、複雑な回路でハード的なスプライトを実現するメリットはなくなっています。事実、プレイステーションなどのゲーム機もこれと同じ手法でプログラムすることが前提になっています。

 Windowsの場合はどうなるでしょう。メインメモリ上のビットマップパターンを表示されている画面(V-RAM)に直接転送していく方法もあるのですが、これだとチラツキが激しくなってしまって実用的でありません。そこで一般的にはメインメモリ上に仮想画面を確保し、そこへ一通り描画してから仮想画面を丸ごと表示画面へ転送する方法が採られます。早い話が、前者ではV-RAM上でやっていたことをメインメモリ上で行うわけです。そしてメインメモリからV-RAMへ一画面分を転送するのです。この処理が増えた分、まず遅くなることはすぐにわかると思います。さらにビデオチップが行っていた合成処理などもメインCPUが処理せねばなりませんから、CPUの負担が増えて遅くなります。現在でこそほとんどのCPUにMMX機能が搭載され合成処理も軽くなりましたが、それ以前のCPUにはかなりの負担となっていました。

 このようにWinGを使用してもゲーム専用機並みの性能を発揮させることはできなかったのです。CPU性能やメモリ容量では優っていたのに・・・・。

 ちなみにここまでの話はWindowsの16ビット時代、つまりWindows3.1での話です。そしてだいぶん32ビットっぽくなったOS、Windows95が登場します。ところが、Windows95のGDIにはかなり16ビットコードが残っていましたし、WinGの機能を標準として取り込んだ程度(CreateDIBSectionというAPI関数がそれに相当します)で、ほとんど従来のままの状態でした。ビットマップの合成表示をするには、BitBlt(ビットブリット)という矩形パターンの転送API関数を1パターンにつき7回も呼び出す必要があり、非常に低速でした。Windows98になってTransparentBltというAPI関数が追加され、256色までであれば1回の呼び出しで指定色を透過合成することができるようになるハズでした。が、これにはバグがあり、結局Windows2000/XPでやっと使えるようになりました。(ただ、WindowsNT系列(NT4,2000,XP)にはMaskBltというAPI関数があり、モノクロのマスクプレーンを用意しておけば1回で合成表示は可能でした。)詰まるところ、Windows95で高速ゲームを作ろうとすると、CreateDIBSection(旧・WinG)関数を利用し、自前の合成表示ルーチンをアセンブラ等で作り、仮想画面上に描画するという方式を採るしかありませんでした。事実、私もそうしていました。

 ここでやっとDirectXの登場となります。Windows95/98/Me/NT4/2000/XPで、ゲーム専用機並みの機能を提供するものです。クラスライブラリ型拡張GDIとでも言えば良いでしょうか。nVidia(ヌビディア)やATIなど、ビデオチップメーカー各社と連携し、グラフィックデバイスドライバを拡張して、画面のフリップや疑似スプライト、スクロールなどを提供できるようにしたのです。Windowsであるがゆえに、機能の呼び出しに若干のオーバーヘッドは生じますが、十分にゲーム専用機と張り合うだけの能力を身につけました。DirectX3になると3D表示もサポートし、ビデオチップがポリゴン描画機能やテクスチャ張り込み、Zバッファなどの機能を持っていれば、それを直接利用可能になりました。現在はDirectX9となり、さまざまな3D効果をサポートしています。

 長々と書きましたが、以上がWindowsにおける高速描画実現の概略した歴史です。が、実は本題はこれからなのです。さて、お待ちかねの本題は・・・・・次回に持ち越すことにいたしましょう。ちょっと長くなったので一息つきますね。Direct×(バツ)という表題の意味は次回、明らかになります。

コラム3 PCIバスとAGP
 ほとんどのグラフィックカードはPCIバスまたはAGPに挿して使用します。昨今はPCIバス用のものはめっきり少なくなり、ほとんどがAGP専用です。それもそのはずで、AGPは“Accelerated Graphics Port”の略ですから、グラフィックカード専用のインタフェースだからです。ところで、そもそもPCIバスとAGPは具体的にどのようなものなのでしょうか。
 PCI
(“Peripheral Component Interconnect)は言わずと知れた今や標準のパソコンインタフェース規格です。LANカードやサウンドカード、RAIDカード、IEEE1394インタフェースカードなど、市販のものはほぼすべてPCIバス用です。最も一般的なPCIバスは、32ビット幅・33MHzでデータ転送するため毎秒133Mバイトのデータ転送能力があります。ところが、実際にはこれだけの速度が出ることは決してありません。なぜなら、PCIはプロトコル制御のバスだからです。「バス」というからには「乗り合い」の意味があり、複数のカードが同一のバスに接続されます。つまり、1系統のバスをいくつもの(最大10)カードで共有する必要があるのです。このため、複数のカードから使用要求があった場合、調停しなければなりません。また、ビデオカードなどが大量のデータを一気に通そうとした場合も、長時間占有させるとマズいことになるため(例えばLANカードの受信データバッファが溢れるなど)、一定のデータサイズで区切らねばなりません。そこでPCIプロトコルでは、32ビットのアドレス(拡張で64ビット)に続けて32ビット単位のデータを送る(受ける)ことになっています。ですから、カード上のメモリの飛び飛びのアドレスにデータを送る場合などは、1回の転送ごとにアドレスデータやウエイトサイクルが入るために、効率がかなり悪くなります。
 これに対してAGPはグラフィックカード専用ですから、独占してラインを使用することができます。つまり調停が不要です。また、バス幅こそPCIと同じ32ビットですが、クロックが最低でも66MHzあり、クロックの立ち上がりと立ち下がりの両方で転送が可能です。最近は×8仕様が一般化しつつありますが、これだと毎秒2.1Gバイトと、PCIの16倍以上の能力があります。さらに、AGPで接続されたカード上のメモリはCPUからリニアなメモリ空間として見えます。この空間のサイズは通常マザーボードBIOSで64MB~256MBの間で設定できます。PCIのようにアドレスとデータを時分割する必要がないので、その分高速になります。
 今後はPCI expressという新規格でPCIバスもAGPも統一されていくようですが、以上の点は憶えておいても良いと思います。