                        フレームバッファデバイス
                        ------------------------
Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
Last revised: November 7, 1998

Translated by FUJIWARA Teruyoshi (fujiwara@linux.or.jp)
Last revised: March 17, 1999

0. はじめに
-----------

フレームバッファデバイスは、グラフィックスハードウェアの抽象化を行いま
す。このデバイスが何らかのビデオハードウェアのフレームバッファを表すこ
とによって、きちんと定義されたインタフェースを通してアプリケーションが
グラフィックスハードウェアにアクセスできるようにします。したがって、ソ
フトウェアは低レベル(ハードウェアレジスタ)の事象に関して何も知る必要は
ありません。

デバイスへのアクセスは特殊デバイスノードを通して行います。デバイスノー
ドは通常 /dev ディレクトリに置かれ、フレームバッファデバイスに対応する
ものは /dev/fb* などとなります。


1. ユーザから見た /dev/fb*
--------------------------
ユーザの視点から見ると、フレームバッファデバイスは /dev にある他のデバ
イスとほとんど同じに見えます。これはメジャー番号 29 を使うキャラクタ型
デバイスで、マイナー番号でフレームバッファの番号を指定します。

慣習により、以下のデバイスノードが使われます(数字はデバイスのマイナー
番号を示します):

      0 = /dev/fb0	最初のフレームバッファ
     32 = /dev/fb1	2番目のフレームバッファ
	  ...
    224 = /dev/fb7	8番目のフレームバッファ

後方互換性のため、/dev/fb0current から以下のシンボリックリンクを作るこ
とになるかもしれません:

    /dev/fb0current -> fb0
    /dev/fb1current -> fb1

など…。
フレームバッファデバイスは「通常の」メモリデバイスでもあります。つまり、
内容を読み書きすることができます。例えば、以下のコマンドで画面のスナッ
プショットを取ることができます:

   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 番目のフレームバッファを使うようにな
ります。


2. プログラマから見た /dev/fb*
------------------------------

既に説明したように、フレームバッファデバイスは /dev/mem のようなメモリ
デバイスであり、これと同じ機能を持っています。読み書きや、どこかの位置
をシークすること、mmap() すること(これが主な使用方法)ができます。唯一
の違いは、特殊ファイルに現われるメモリは，全てのメモリを表しているので
はなく、何らかのビデオハードウェアのフレームバッファを意味していること
です。

/dev/fb* に対して使うことができる ioctl がいくつかあります。これを使っ
て、ハードウェアに関する情報をたくさん問い合わせることや設定することが
できます。カラーマップ処理も ioctl 経由で行います。ヘッダ <linux/fb.h> 
を見れば、どんな ioctl があって、どんな構造体が使われるのかという詳細
がわかります。そこで、ここでは概要だけを簡単に説明することにします:

     - ハードウェアに関する変更不可能な情報をリクエストすることができ
       ます。このような情報としては、名前やスクリーンメモリの構成(プレー
       ン、packed 形式ピクセル、...)、スクリーンメモリのアドレスや長さ
       などがあります。

     - ハードウェアに関する変更可能な情報をリクエストおよび変更することが
       できます。このような情報としては、可視ジオメトリや仮想ジオメト
       リ、色の深さ、カラーマップのフォーマット、タイミング値などがあ
       ります。このような情報を変更しようとした場合、ドライバはたぶん
       ハードウェアの機能に合わせて値をいくらか丸めるでしょう(それが不
       可能ならば EINVAL を返します)。

     - カラーマップの一部を取得・設定することができます。存在する全て
       のハードウェアをサポートするため、演算は色の各部分(赤、緑、青、
       透明度)について 16 ビットで行われます。ドライバはこれをハードウェ
       アに与えるために全ての通信を行います(ビットを減らすために丸めが
       行われ、おそらく透明度は破棄されます)。

以上のような抽象化のおかげで、アプリケーションプログラムを実装するの
も移植するのも楽になるわけです。例えば、X サーバは /dev/fb* を使って完
全に動作するので、具体的なハードウェアの色レジスタがどのように構成され
ているか等を知る必要がありません。XF68_FBDev はビットマップを使用し、
アクセラレーションの無いビデオハードウェア用の汎用の X サーバです。ア
プリケーションプログラムに組み込まなければならないのは、画面の構成(ビッ
トプレーン、まとまったピクセル等)だけです。なぜなら、アプリケーション
は直接フレームバッファのイメージデータを操作するからです。

将来的には、グラフィックスカード等のフレームバッファドライバをカーネル
モジュールとして実装し、実行時にロードすることが考えられています。この
ようなドライバは、ただ register_framebuffer() を呼び出し、何らかの機能
を提供するだけでよくなります。このようなドライバを独立に作成・配布すれ
ば、カーネルがトラブルに巻き込まれることも少ないでしょう…。


3. フレームバッファの解像度の管理
---------------------------------

フレームバッファの解像度は fbset というユーティリティを使って管理しま
す。このユーティリティを使ってフレームバッファデバイスのビデオモードの
プロパティを変更することができます。その主な使い方は、例えば起動時に 
/etc/rc.* や /etc/init.d/* 等のファイル中で、現在のビデオモードを変更
することです。

fbset は、設定ファイル中に格納されているビデオモードのデータベースを使
います。したがって、独自のモードを簡単に追加することや、モードを簡単な
識別子で参照することができます。


4. X サーバ
-----------

X サーバ(XF68_FBDev)は、フレームバッファデバイス用の最も有名なアプリケー
ションプログラムです。XFree86 リリース 3.2 以降、この X サーバは 
XFree86 の一部であり、2 つのモード値を持っています。

     - /etc/XF86Config ファイル内の `fbdev/' ドライバに対する 
       `Display/' サブセクションが


       という内容である場合、X サーバは前述の方法を使います。つまり、
       /dev/fb0 (設定されていれば $FRAMEBUFFER)によって決められた解像
       度で起動します。その場合でも、色の深さ(Depth キーワードを使いま
       す)と仮想解像度(Virtual を使います)は指定しなければなりません。
       これは XFree86 が用意している設定ファイルのデフォルトです。これ
       は最も簡単な設定ですが、制限がいくつかあります。

     - したがって、/etc/XF86Config ファイル内で解像度を指定することも
       できます。これにより、仮想デスクトップの大きさを同じに保ったまま、
       実行中に解像度の切り替えを行うことができます。この場合も使われ
       るフレームバッファデバイスは /dev/fb0 (または $FRAMEBUFFER)のま
       まですが、この場合は利用できる解像度は /etc/XF86Config で定義さ
       れています。欠点としては、異なるフォーマットでタイミング値を指
       定しなければならないことが挙げられます(しかし、`fbset -x' が参
       考になるでしょう)。

ビデオモードをチューンするために fbset や xvidtune が利用できます。 
xvidtune は XF68_FBDev では 100% 動作しない点に注意してください。報告
されるクロック値は必ず間違っています。


5. ビデオモードタイミング値
---------------------------

モニタは電子線を用いてイメージを画面に描画します(カラーモデルなら電子
線 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)の合計です。

  +----------+---------------------------------------------+----------+-------+
  |          |                ^                            |          |       |
  |          |                |upper_margin                |          |       |
  |          |                ・                            |          |       |
  +----------###############################################----------+-------+
  |          #                ^                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |   left   #                |                            #  right   | hsync |
  |  margin  #                |       xres                 #  margin  |  len  |
  |<-------->#<---------------+--------------------------->#<-------->|<----->|
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |yres                        #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                |                            #          |       |
  |          #                ・                            #          |       |
  +----------###############################################----------+-------+
  |          |                ^                            |          |       |
  |          |                |lower_margin                |          |       |
  |          |                ・                            |          |       |
  +----------+---------------------------------------------+----------+-------+
  |          |                ^                            |          |       |
  |          |                |vsync_len                   |          |       |
  |          |                ・                            |          |       |
  +----------+---------------------------------------------+----------+-------+

フレームバッファデバイスは、全ての水平タイミング値がドットクロック(ピ
コ秒(1E-12 秒)単位)の数であることと、全ての垂直タイミング値がスキャン
ラインの数であることを期待します。


6. 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: 垂直同期の長さ

1) Pixelclock:
   xfree: MHz 単位
   fb: ピコ秒(ps)単位 

   pixclock = 1000000 / DCF

2) 水平タイミング値:
   left_margin = HFL - SH2
   right_margin = SH1 - HR
   hsync_len = SH2 - SH1

3) 垂直タイミング値:
   upper_margin = VFL - SV2
   lower_margin = SV1 - VR
   vsync_len = SV2 - SV1

VESA タイミング値の良い例は、XFree86 のソースツリーの
xc/programs/Xserver/hw/xfree86/doc/modeDB.txt にあります。


7. 参考文献
-----------

フレームバッファデバイスと、その応用に関するより詳しい情報については、
以下の文書を参照してください:

  - fbset のオンラインマニュアル: fbset(8), fb.modes(5)
  - XFree86 のオンラインマニュアル: XF68_FBDev(1), XF86Config(4/5)
  - 万能のカーネルソース:
      o linux/drivers/video/
      o linux/include/linux/fb.h
      o linux/include/video/


8. ダウンロード
---------------

必要なファイル全ては

    ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/

とそのミラーサイトにあります。


9. クレジット
------------

この README 文書は Geert Uytterhoeven が書きました。内容の一部は、
Roman Hodek さんと Martin Schaller さんが書かれたオリジナルの
`X-framebuffer.README' に基づいています。第 6 章は Frank Neumann さん
に提供していただきました。

フレームバッファデバイスによる抽象化層を設計したのは Martin Schaller 
さんです。
