Linux/m68k のフレームバッファデバイスについて Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) 7 November 1998 The X Japanese Documentation Project 16 March 1999 ____________________________________________________________ 目次 1. はじめに 2. ユーザから見た /dev/fb* 3. プログラマから見た /dev/fb* 4. フレームバッファの解像度の管理 5. X サーバ 6. ビデオモードタイミング値 7. XFree86 のタイミング値のフレームバッファデバイスのタイミング値への変換 8. 参考文献 9. ダウンロード 10. クレジット ______________________________________________________________________ 1. はじめに フレームバッファデバイスは、グラフィックスハードウェアの抽象化を行いま す。このデバイスが何らかのビデオハードウェアのフレームバッファを表すこ とによって、きちんと定義されたインタフェースを通してアプリケーションが グラフィックスハードウェアにアクセスできるようにします。したがって、ソ フトウェアは低レベル(ハードウェアレジスタ)の事象に関して何も知る必要は ありません。 デバイスへのアクセスは特殊デバイスノードを通して行います。デバイスノー ドは通常 /dev ディレクトリに置かれ、フレームバッファデバイスに対応する ものは /dev/fb* などとなります。 2. ユーザから見た /dev/fb* ユーザの視点から見ると、フレームバッファデバイスは /dev にある他のデバ イスとほとんど同じに見えます。これはメジャー番号 29 を使うキャラクタ型 デバイスで、マイナー番号でフレームバッファの番号を指定します。 慣習により、以下のデバイスノードが使われます(数字はデバイスのマイナー 番号を示します): 0 = /dev/fb0 最初のフレームバッファ 32 = /dev/fb1 2番目のフレームバッファ ... 224 = /dev/fb7 8番目のフレームバッファ 後方互換性のため、/dev/fb0current から fb0 にシンボリックリンクを作る ことになるかもしれません。 フレームバッファデバイスは「通常の」メモリデバイスでもあります。つま り、内容を読み書きすることができます。例えば、以下のコマンドで画面のス ナップショットを取ることができます: cp /dev/fb0 myfile 同時に複数のフレームバッファを持つこともできます。例えば、組込みのハー ドウェア以外に追加のグラフィックスカードを持っている場合です。それぞれ に対応するフレームバッファ(/dev/fb0、/dev/fb1 など) は独立して動作しま す。 フレームバッファデバイスを使うアプリケーションソフトウェア(例: X サー バ)は、デフォルトで /dev/fb0 を使います(古いソフトウェアは /dev/fb0current を使います)。環境変数 $FRAMEBUFFER にフレームバッファ デバイスのパス名を設定することにより、別のフレームバッファデバイスを指 定することができます。例(sh/bash ユーザの場合): export FRAMEBUFFER=/dev/fb1 または(csh ユーザの場合): setenv FRAMEBUFFER /dev/fb1 これを設定した後は、X サーバは 2 番目のフレームバッファを使うようにな ります。 3. プログラマから見た /dev/fb* 既に説明したように、フレームバッファデバイスは /dev/mem のようなメモリ デバイスであり、これと同じ機能を持っています。読み書きや、どこかの位置 をシークすること、mmap() すること(これが主な使用方法)ができます。唯一 の違いは、特殊ファイルに現われるメモリは,全てのメモリを表しているので はなく、何らかのビデオハードウェアのフレームバッファを意味していること です。 /dev/fb* に対して使うことができる ioctl がいくつかあります。これを使っ て、ハードウェアに関する情報をたくさん問い合わせることや設定することが できます。カラーマップ処理も ioctl 経由で行います。ヘッダ を見れば、どんな ioctl があって、どんな構造体が使われるのかという詳細 がわかります。そこで、ここでは概要だけを簡単に説明することにします: o ハードウェアに関する変更不可能な情報をリクエストすることができま す。このような情報としては、名前やスクリーンメモリの構成(プレーン、 packed 形式ピクセル、...)、スクリーンメモリのアドレスや長さなどがあ ります。 o ハードウェアに関する変更可能な情報をリクエストおよび変更することが できます。このような情報としては、可視ジオメトリや仮想ジオメトリ、 色の深さ、カラーマップのフォーマット、タイミング値などがあります。 このような情報を変更しようとした場合、ドライバはたぶんハードウェア の機能に合わせて値をいくらか丸めるでしょう(それが不可能ならば EINVAL を返します)。 o カラーマップの一部を取得・設定することができます。存在する全てのハ ードウェアをサポートするため、演算は色の各部分(赤、緑、青、透明 度)について 16 ビットで行われます。ドライバはこれをハードウェアに与 えるために全ての通信を行います(ビットを減らすために丸めが行われ、お そらく透明度は破棄されます)。 以上のような抽象化のおかげで、アプリケーションプログラムを実装するのも 移植するのも楽になるわけです。例えば、X サーバは /dev/fb* を使って完全 に動作するので、具体的なハードウェアの色レジスタがどのように構成されて いるか等を知る必要がありません。XF68_FBDev はビットマップを使用し、ア クセラレーションの無いビデオハードウェア用の汎用の X サーバです。アプ リケーションプログラムに組み込まなければならないのは、画面の構成(ビッ トプレーン、まとまったピクセル等)だけです。なぜなら、アプリケーション は直接フレームバッファのイメージデータを操作するからです。 将来的には、グラフィックスカード等のフレームバッファドライバをカーネル モジュールとして実装し、実行時にロードすることが考えられています。この ようなドライバは、ただ register_framebuffer() を呼び出し、何らかの機能 を提供するだけでよくなります。このようなドライバを独立に作成・配布すれ ば、カーネルがトラブルに巻き込まれることも少ないでしょう…。 4. フレームバッファの解像度の管理 フレームバッファの解像度は fbset というユーティリティを使って管理しま す。このユーティリティを使ってフレームバッファデバイスのビデオモードの プロパティを変更することができます。その主な使い方は、例えば起動時に /etc/rc.* や /etc/init.d/* 等のファイル中で、現在のビデオモードを変更 することです。 fbset は、設定ファイル中に格納されているビデオモードのデータベースを使 います。したがって、独自のモードを簡単に追加することや、モードを簡単な 識別子で参照することができます。 5. X サーバ X サーバ(XF68_FBDev)は、フレームバッファデバイス用の最も有名なアプリケ ーションプログラムです。XFree86 リリース 3.2 以降、この X サーバは XFree86 の一部であり、2 つのモード値を持っています。 o /etc/XF86Configファイル内の fbdev ドライバに対する Display サブセク ションが Modes "default" という内容である場合、X サーバは前述の方法を使います。つまり、 /dev/fb0 (設定されていれば $FRAMEBUFFER)によって決められた解像度で起動 します。その場合でも、色の深さ(Depth キーワードを使います)と仮想解像 度(Virtual を使います)は指定しなければなりません。これは XFree86 が用 意している設定ファイルのデフォルトです。これは最も簡単な設定ですが、制 限がいくつかあります。 o したがって、/etc/XF86Config ファイル内で解像度を指定することもでき ます。これにより、仮想デスクトップの大きさを同じに保ったまま、実行 中に解像度の切り替えを行うことができます。この場合も使われるフレー ムバッファデバイスは /dev/fb0 (または $FRAMEBUFFER)のままですが、こ の場合は利用できる解像度は /etc/XF86Config で定義されています。欠点 としては、異なるフォーマットでタイミング値を指定しなければならない ことが挙げられます(しかし、 fbset -x が参考になるでしょう)。 ビデオモードをチューンするために fbset や xvidtune が利用できます。 xvidtune は XF68_FBDev では 100% 動作しない点に注意してください。報告 されるクロック値は必ず間違っています。 6. ビデオモードタイミング値 モニタは電子線を用いてイメージを画面に描画します(カラーモデルなら電子 線 3 つで、モノクロモニタなら電子線 1 つです)。スクリーンの前面は色付 きの蛍光体(ピクセル)のパターンで覆われています。蛍光体に電子が当たると 光子が出て、見えるようになります。 電子線は水平な線(スキャンライン)を画面の左から右、上から下に向かって描 画します。電子線の強度を変えることにより、様々な色や明るさのピクセルを 描画することができます。 各スキャンラインの後には、電子線は画面の左側に戻り、次の行に移動しなけ ればなりません。これは水平復帰(horizontal retrace)と呼ばれます。画面 (フレーム)全体を描いた後には、電子線は画面の左上隅に戻ります。これは垂 直復帰(vertical retrace)と呼ばれます。水平復帰や垂直復帰の間には、電子 線は止まります(ブランク状態になります)。 電子線がピクセルを描画する速度は、グラフィックスボードのドットクロック 値によって決まります。例えばドットクロック値が 28.37516 MHz(一秒あたり 数百万サイクル)の場合には、それぞれのピクセルあたりの長さは 35242 ps (ピコ秒)です: 1/(28.37516E6 Hz) = 35.242E-9 s 画面の解像度が 640x480 ならば、1 スキャンライン分の 640(xres)ピクセル を描画するのにかかる時間は 640*35.242E-9 s = 22.555E-6 s となります。ですが、水平復帰にも時間がかかる(例えば 272 「ピクセル」) ので、1 スキャンライン全体でかかる時間は (640+272)*35.242E-9 s = 32.141E-6 s となります。ですから水平スキャンレートは約 31 kHz と言えます: 1/(32.141E-6 s) = 31.113E3 Hz 画面全体では 480(yres)行ありますが、垂直復帰(例えば 49 「ピクセル」)も 考えなければなりません。ですから、画面全体では (480+49)*32.141E-6 s = 17.002E-3 s かかります。垂直スキャンレートは約 50 Hz になります: 1/(17.002E-3 s) = 58.815 Hz つまり、画面のデータは 1 秒あたり約 59 回書き直されるということです。 目に見えるようなちらつきを起こさずに安定したピクセルを得るために VESA が推奨している垂直スキャンレートは最低 72 Hz です。しかし、我慢できる ちらつきというのは人それぞれです。50Hz で使っても全く問題ないという人 もいれば、筆者のように 80 Hz より小さいと気付いてしまうという人もいま す。 新しいスキャンラインがいつ始まるかはモニタには分からないので、グラ フィックスボードはスキャンラインごとに同期信号(水平同期または hsync)を 出します。同様に、新しいフレームごとにも同期信号(垂直同期または vsync)を出します。画面における画像の位置は、同期信号が発生するタイミン グの影響を受けます。 全てのタイミングを以下の図にまとめました。水平復帰時間は左マージン (left margin)、右マージン(right margin)、水平同期の長さ(hsync len)の合 計です。垂直復帰時間は上部マージン(upper_margin)、下部マージン (lower_margin)、垂直同期の長さ(vsync_len)の合計です。 +----------+---------------------------------------------+----------+-------+ | | x | | | | | |upper_margin | | | | | x | | | +----------###############################################----------+-------+ | # x # | | | # | # | | | # | # | | | # | # | | | left # | # right | hsync | | margin # | xres # margin | len | |<-------->#<---------------+--------------------------->#<-------->|<----->| | # | # | | | # | # | | | # | # | | | # |yres # | | | # | # | | | # | # | | | # | # | | | # | # | | | # | # | | | # | # | | | # | # | | | # | # | | | # x # | | +----------###############################################----------+-------+ | | x | | | | | |lower_margin | | | | | x | | | +----------+---------------------------------------------+----------+-------+ | | x | | | | | |vsync_len | | | | | x | | | +----------+---------------------------------------------+----------+-------+ フレームバッファデバイスは、全ての水平タイミング値がドットクロック(ピ コ秒(1E-12 秒)単位)の数であることと、全ての垂直タイミング値がスキャン ラインの数であることを期待します。 7. XFree86 のタイミング値のフレームバッファデバイスのタイミング値への 変換 XFree86 のモードラインは以下のフィールドから構成されています: "800x600" 50 800 856 976 1040 600 637 643 666 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL フレームバッファデバイスは以下のフィールドを使用します: pixclock ps (ピコ秒)単位のピクセルクロック値 left_margin 同期から描画までの時間 right_margin 描画から同期までの時間 upper_margin 同期から描画までの時間 lower_margin 描画から同期までの時間 hsync_len 水平同期の長さ vsync_len 垂直同期の長さ Pixelclock o xfree: MHz 単位 o fb: ピコ秒(ps)単位 o pixclock = 1000000 / DCF 水平タイミング値 o left_margin = HFL - SH2 o right_margin = SH1 - HR o hsync_len = SH2 - SH1 垂直タイミング値 o upper_margin = VFL - SV2 o lower_margin = SV1 - VR o vsync_len = SV2 - SV1 VESA タイミング値の良い例は、XFree86 のソースツリーの xc/programs/Xserver/hw/xfree86/doc/modeDB.txt にあります。 8. 参考文献 フレームバッファデバイスと、その応用に関するより詳しい情報については、 以下の文書を参照してください: o fbset のオンラインマニュアル: fbset(8), fb.modes(5) o XFree86 のオンラインマニュアル: XF68_FBDev(1), XF86Config(4/5) o 万能のカーネルソース: o linux/drivers/video/ o linux/include/linux/fb.h o linux/include/video/ 9. ダウンロード 必要なファイル全ては ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/ またはそのミラーサイトにあります。 10. クレジット この README 文書は Geert Uytterhoeven が書きました。内容の一部は、 Roman Hodek さんと Martin Schaller さんが書かれたオリジナルの X- framebuffer.README に基づいています。「XFree86 のタイミング値のフレー ムバッファデバイスのタイミング値への変換」セクションは Frank Neumann さんに提供していただきました。 フレームバッファデバイスによる抽象化層を設計したのは Martin Schaller さんです。 $XFree86: xc/programs/Xserver/hw/xfree86/doc/Japanese/README.fbdev,v 1.1.2.2 1999/11/26 15:23:18 hohndel Exp $