VESA VBEによるグラフィック操作

内容

この文書では、とりあえずディスプレイ上に何らかの図形を表示するまでを 解説しています。「とりあえず」とあるようにあんまり詳しく書いているわけでは ありませんが、必要な情報はそろっているはずです。動作確認はbochsで行っていますが ここに書いてあることがすべて正しいかどうかは保障できません。

SVGAとVESAとVBE

そもそも、ビデオカードに関する規格にはIBMが定めたVGAというものがありました。 これは最大で640*480ドットの画面表示を行い、Windowsではセーフモードで起動したとき このモードで画面が表示されます(Win XPは違います)。セーフモードの画面を見れば わかりますが、VGAによる表示は使い物にならないくらい画質が荒いです。そこで、 ビデオカードの各メーカーはVGAを拡張してVGAより高い画質の画面が表示できるように なりました。このようにVGAより高い画質を表示するための規格をSVGA(Super VGA)と いいます。

高い画質の画面が表示できるようになったのはいいことですが、 それぞれのメーカーが独自にVGAを拡張したため各メーカー間で 互換性がなくなってしまい、画面を表示するためにはそのメーカーのビデオカード専用の ドライバを使い、そのドライバでビデオカードを操作させて画面を表示しなければ ならなくなりました。このような状況の中でVESAが生まれました。VESAはビデオカードの 基本的な処理のインターフェイスを共通化を図る団体です。基本的な手続きというのは、 たとえばビデオカードのメーカー名を得る手続きや、VRAM領域のはじめのアドレスを得る 手続きなどのことで、実際の描画に関する手続きなどは関知していません。このような 手続きをBIOSのファンクションで実行できるようにしたものがVBE(VESA BIOS Extension) という規格でまとめられています。

VBEはその名のとおりBIOSにアクセスすることになりますが、CPUがプロテクトモードに 移行しても手続きを実行することができます。そして、VBEが出現したことによる 最大の利益はビデオカードのドライバなしで高解像度の画面を出力できることです。 Windows XPではビデオカードのドライバがない場合、VBEで画面を設定し、VRAMアドレスを 得て画面を出力しているようです。かく言う私もWinXPを再インストールしたとき ビデオカードのドライバをインストールしていないのに高解像度の画面が出てきたのには 驚きました。また、先に書いたようにWinXPではセーフモードで起動してもVGAの画面 出力にならないということは、この理由のためです。

ところで、VBEさえあればそれぞれのビデオカードのドライバが要らないように書いていますが、 ハードウエアのアクセラレーションは使えません。正直私もどこがどうなるのかは 詳しくは知りませんが、要は遅いんです。しかし、このことを差し引いても手軽に (ドライバを組むことを考えれば)高解像度の画面を出力できることは大きいので VBEを使用して画面を出力する価値はあると思います。

画面表示までの大まかな流れ

コンピュータを起動してから画面を表示するまでの流れはおおよそ次のようになっています。

  1. ディスプレイの描画モードの設定
  2. 描画モードの情報の取得
  3. フレームバッファーへ描画して画面表示

まず描画モードの設定ですが、ここではディスプレイの横・縦の大きさ、表現する色の数 を決めます。ディスプレイの大きさおよび色の数に応じて番号が決まっており、この番号の ことをモード番号といいます。たとえば、800*600の大きさで24ビットカラーで表示するなら モード番号は0x0115となっています。ディスプレイの描画モードはこのモード番号でもって 設定することができます。

次に描画モードの情報を取得します。描画モードの情報というのは、例えば、1ラインあたりの バイト数はどれくらいか、1ピクセルあたりのビット数はどれくらいか、赤・緑・青の情報は 何ビット目から何ビット目までに入るか、そして、フレームバッファのメモリアドレスは どこにあるか、というような情報を得ます。これらの情報はメモリ上に格納されるので プロテクトモードに入った後も参照することができます。

描画モードの情報があれば、フレームバッファーに画面の内容を書き込んで画面を出力 することができます。

VBEを使用するに当たって

VBEの機能は割り込みの0x10で使用することができます。この割り込みは通常VGAの ファンクションを実行していますが、AHレジスタに0x4Fという値を入れることにより VBEのファンクションを実行することができます。VBEのファンクションが実行された 場合、AHレジスタの値はALレジスタにコピーされます。つまり、実行後のALレジスタの 値が0x4Fであればファンクションが実行されたことになるし、そうでなければファンクションが なかったということになります。そして、AHレジスタには実行後のリザルトコードが 入り、実行に成功すれば0x00が入ります。まとめると次のようになります。

実行後のAHおよびALレジスタの値
AL == 0x4F ファンクションが有る
AL != 0x4F ファンクションが無い
AH == 0x00 正常に終了した
AH == 0x01 失敗した
AH == 0x02 現在のハードウエアでは実行できない
AH == 0x03 現在のモードでは実行できない

つまり、実行後のAXレジスタの値が0x004Fじゃ無かったら失敗したと見ていい。

モードの設定

モードの設定はファンクションの0x02で行います。つまりAX=0x4F02にします。そして、 モード番号はBXレジスタに格納しておきます。このとき BXレジスタの14ビット目を立てて おくことを忘れないでください。このビットはリニアフレームバッファーを使用することを 表していて、メモリ上の連続した領域にフレームバッファーを割り当てることができます。 ビットを立てなかった場合はバンクフレームバッファーを使用することになりますが この形式のフレームバッファーは扱いが面倒です。 モード番号とディスプレイの大きさ・色の数は次のように関連付けられています。

モード番号とディスプレイの大きさ・色の数
モード番号 大きさ 色の数
0x0100 640x400 256
0x0101 640x480 256
0x0102 800x600 16
0x0103 800x600 256
0x0104 1024x768 16
0x0105 1024x768 256
0x0106 1280x1024 16
0x0107 1280x1024 256
0x010D 320x200 約32000色(1:5:5:5)
0x010E 320x200 約65000色(5:6:5)
0x010F 320x200 約1678万色(8:8:8)
0x0110 640x480 約32000色(1:5:5:5)
0x0111 640x480 約65000色(5:6:5)
0x0112 640x480 約1678万色(8:8:8)
0x0113 800x600 約32000色(1:5:5:5)
0x0114 800x600 約65000色(5:6:5)
0x0115 800x600 約1678万色(8:8:8)
0x0116 1024x768 約32000色(1:5:5:5)
0x0117 1024x768 約65000色(5:6:5)
0x0118 1024x768 約1678万色(8:8:8)
0x0119 1280x1024 約32000色(1:5:5:5)
0x011A 1280x1024 約65000色(5:6:5)
0x011B 1280x1024 約1678万色(8:8:8)

色の数が16色や256色の場合はインデックスカラーでそれ以上の数になるとダイレクトカラーに なっていて、約32000色や約65000色の場合は16ビット、約1678万色の場合は24ビットの 大きさになっています。また、RGBのどの成分が何ビットずつ割り振られているかは (a:r:g:b)で表されており、(5:6:5)の場合は赤が5ビット、緑が6ビット、青が5ビット、と なっています。また、(1:5:5:5)の場合はMSBは使用されず、残りの15ビットを3つの成分で 分けています。

モード情報の取得

モード情報の取得はファンクション0x01を使用します。得られたモード情報はES:DIから 始まるメモリに格納されていて、次のようになっています。

ModeAttributes dw モード属性
WinAAttributes db ウインドウAの属性
WinBAttributes db ウインドウBの属性
WinGranularity dw ウインドウグラニュアリティ
WinSize dw ウインドウサイズ
WinASegment dw ウインドウAの開始セグメント
WinBSegment dw ウインドウBの開始セグメント
WinFuncPtr dd ウインドウ関数へのポインタ
BytesPerScanLine dw スキャンラインのバイト数
XResolution dw ディスプレイの横の大きさ
YResolution dw ディスプレイの縦の大きさ
XCharSize db 文字1つ分の横の大きさ
YCharSize db 文字1つ分の縦の大きさ
NumberOfPlanes db メモリプレーンの数
BitsPerPixel db 1ピクセルあたりのビット数
NumberOfBanks db バンクの数
MemoryModel db メモリモデル
BankSize db キロバイト単位でのバンクの大きさ
NumberOfImagePages db イメージページの数
Reserved db 予約、常に1
RedMaskSize db 赤成分のビット数
RedFieldPosition db 赤成分のLSBの位置
GreenMaskSize db 緑成分のビット数
GreenFieldPosition db 緑成分のLSBの位置
BlueMaskSize db 青成分のビット数
BlueFieldPosition db 青成分のLSBの位置
RsvdMaskSize db 使用されないビットの数
RsvdFieldPosition db 使用されないビットのLSBの位置
DirectColorModeInfo db ダイレクトカラーの属性
PhysBasePtr dd リニアフレームバッファーの開始アドレス

いろいろと並んでいますが、必要な情報はXResolution, YResolution, BitsPerPixel, BytesPerScanLine, PhysBasePtrくらいです。特にPhysBasePtrはフレームバッファーの 先頭アドレスを表していて、かなり重要な情報です。ただ、注意しなければならないことは この先頭アドレスは物理アドレスであるということです。したがって、プロテクトモードに 移行した後このフレームバッファーにアクセスするときはアドレスの変換を行わなければ なりません。

リニアフレームバッファーへの描画

フレームバッファーのアドレスが得られれば後はそこに画面の内容を書いていくだけです。 VBEのファンクションは一切使用しません。画面の座標は左上が原点になっていて、 (x, y)のピクセルはy * BytesPerScanLine + x * BitsPerPixel/8のアドレスでアクセス できます。これで次のような図がかけます。

円の描画

バンクフレームバッファーへの描画

工事中です

参考資料

この文書を作成するに当たり以下の資料を参考にさせていただきました。

inserted by FC2 system
戻る