2

フレームバッファベースのコンソールで文字をレンダリングする最速の方法は何でしょうか?XNUディストリビューションのiso_font.hフォントを使用しています。

現在、このコードを使用して文字をレンダリングしていますが、あまり効率的ではないようです。

px = px* ISO_CHAR_WIDTH;
py = py* (ISO_CHAR_HEIGHT-1);

for (int i = 0; i < 15; i += 1) 
{
    int sym = iso_font[c*16+i];

    int x = px;
    int y = py + i;

    for (int ii =0; ii < 8; ii++) 
    {
        x+=1;
        if ((sym & (1 << ii)))
        {
            fb_set_px(x,y,fg);
        }
        else 
        {
            fb_set_px(x,y,bg);
        }

    }   
}

また、このコードを簡略化できるかどうかも疑問に思っています。

void fb_set_px(x,y,hex){
    void*ptr = ((_base + (_bpr*y) + (_bpe*x)));
    unsigned int *p = (unsigned int *) ptr;
    *p=hex;
}

行が多すぎるところまではまともで、コンソール全体を(スクロールするために)再描画する必要があります。その時点で、かなりの遅延が発生します。

4

2 に答える 2

4

頭に浮かぶいくつかのこと(これは私を昔のDOSの時代に戻します!):-

1)ピクセルの書き込みにインクリメンタルアドレス指定を使用します。

  p = calculate address of x,y
    for line = 0 to 15
      for column = 0 to 7
        write to p
        increment p
      end
      p += stride - 8 (stride = distance in memory between vertically adjacent pixels)
    end

2)内側のループのifを削除します。

 draw pixel (fg + (bg - fg) & (((sym >> column) & 1) - 1)

3)OSのヘルプを使用します。これは、たとえばハードウェアアクセラレーションである可能性があります。

4)スクロールするときは、すべての文字を再描画するのではなく、画面の残りの部分を削除するだけです。たとえば、1行目から0行目までの行数-1のメモを作成します。次に、露出領域をクリアします。

|-------|                             |-------|                      |-------|
|.......|                             |@@@@@@@|                      |@@@@@@@|
|@@@@@@@| scroll up a line => memmove |#######| then clear => memset |#######|
|#######|                             |#######|                      |       |
|-------|                             |-------|                      |-------|
于 2011-07-12T12:55:16.667 に答える
2

通常、VGAフレームバッファなどのほとんどのハードウェアフレームバッファには、ハードウェアスクロール機能があります。それだけでなく、一部のフレームバッファ(残念ながらVGA文字コンソールではありません)は「ラップアラウンド」します。つまり、フレームバッファの最後のバイト(またはビット)に書き込んだ後、最初のバイトに再度書き込む場合です。フレームバッファのバイト(またはビット)。これらのバイトは、画面の次の行としてハードウェアに表示されます。したがって、実行できることがいくつかあります。

  1. フレームバッファのハードウェアスクロール機能を使用して、完了したら次の行にスクロールします。つまり、最初にフレームバッファの次の行をクリアし、その行に必要な文字を書き込んでから、フレームバッファの開始行ポインタを1つインクリメントします。これにより、フレームバッファが1行下にスクロールしたかのように「表示」されます。フレームバッファのメモリの最後に到達したら、同じプロセスを続行しますが、クリアする次の行は、フレームバッファのメモリの最初の行になります。次に、フレームバッファの開始アドレスをインクリメントし続けます(これはまだフレームバッファのメモリの終わり近くを指しています)。それもフレームバッファのメモリ内の最後の行を指しています。その時点で君'
  2. フレームバッファがまだマルチページであるが、ラップアラウンド機能がない場合(VGA文字コンソールなど)、フレームバッファの先頭へのポインタを保持し、最後の「ページ」に到達したときに"メモリ内で、memcpy()メモリ内の最後のページをメモリ内のフレームバッファの最初のページにコピーするために使用します...その手順を実行したら、次の行をクリアするのと同じページスクロールルーチンを続けます。次に、フレームバッファの開始行ポインタをインクリメントして、1行上にスクロールしているように見せます。ページコピーは、それまでに使用された他のすべてのハードウェアページスクロールよりも少し遅くなりますが、特に、ではなくmemcpy()などのより大きなメモリタイプを使用して一度に複数のバイトをコピーする場合は、非常に効率的です。longchar

次に、アクセス関数fb_set_pxに関しては、1)inlineヘッダーファイル内に作成して、スタックを使用してアクティベーションフレームをセットアップする必要がある実際の関数呼び出しのオーバーヘッドを回避し、2)ファクトを使用できるようにします。フレームバッファは、ポインタの配列を、文字ごとのデータレイアウトを表すタイプに実際にマップするための単なるメモリ配列structです(つまり、一部のフレームバッファには、文字用のバイトと一部用の別のバイトがあります)キャラクターに適用される色などの属性のタイプ)。したがって、たとえば、次のようにすることができます。

typedef struct frame_buffer_t
{
    unsigned char character;
    unsigned char attributes;
    //add or omit any fields that describe your frame-buffer data-layout
} __attribute__((packed)) frame_buffer_t;

//define as global variable
//make volatile to avoid any compiler re-ordering
unsigned volatile frame_buffer_t* framebuffer[MAX_ROWS_IN_FRAMEBUFFER];

int main()
{
    unsigned volatile frame_buffer_t* temp = global_frame_buffer_start_ptr;

    for (int i=0; i < MAX_ROWS_IN_FRAMEBUFFER; i++)
    {
        framebuffer[i] = temp;
        temp += NUM_COLUMNS;
    }

    //... more code
}

これで、フレームバッファ内のax、y位置を次のように簡単にアドレス指定できます。

framebuffer[Y_POS][X_POS].character = SOME_VALUE;
于 2011-07-12T13:38:37.013 に答える