Linux FrameBufferを介してスクリーンにピクセルをペイントする

c framebuffer linux
Linux FrameBufferを介してスクリーンにピクセルをペイントする

最近、/ dev / urandomから入力を取得し、関連する文字をランダムな整数に変換し、それらの整数をピクセルのrgb / x-y値として使用して画面にペイントするという奇妙なアイデアに驚きました。

私はいくつかの調査を行いました(ここではStackOverflowなど)。多くの人は、デバイスのファイル表現であるため、/ dev / fb0に直接書き込むことができると示唆しています。 残念ながら、これは視覚的に明らかな結果を生成しないようです。

バッファへの書き込みにmmapを使用したQTチュートリアル(もう利用できません)からのサンプルCプログラムを見つけました。 プログラムは正常に実行されますが、画面には何も出力されません。 おもしろいことに、ラップトップをサスペンドに入れて後で復元すると、かなり前にフレームバッファに書き込まれた画像の瞬間的なフラッシュ(赤い正方形)が見えました。 Linuxで画面にペイントするためのフレームバッファーへの書き込みはもう機能しますか? 理想的には、(ba)shスクリプトを作成したいのですが、Cなども同様に機能します。 ありがとうございます。

編集:これはサンプルプログラムです…​獣医になじみがあるかもしれません。

#include
#include
#include
#include
#include
#include
#include

int main()
{
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char *fbp = 0;
    int x = 0, y = 0;
    long int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) {
        perror("Error: cannot open framebuffer device");
        exit(1);
    }
    printf("The framebuffer device was opened successfully.\n");

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        exit(3);
    }

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) {
        perror("Error: failed to map framebuffer device to memory");
        exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.\n");

    x = 100; y = 100;       // Where we are going to put the pixel

    // Figure out where in memory to put the pixel
    for (y = 100; y < 300; y++)
        for (x = 100; x < 300; x++) {

            location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                       (y+vinfo.yoffset) * finfo.line_length;

            if (vinfo.bits_per_pixel == 32) {
                *(fbp + location) = 100;        // Some blue
                *(fbp + location + 1) = 15+(x-100)/2;     // A little green
                *(fbp + location + 2) = 200-(y-100)/5;    // A lot of red
                *(fbp + location + 3) = 0;      // No transparency
        //location += 4;
            } else  { //assume 16bpp
                int b = 10;
                int g = (x-100)/6;     // A little green
                int r = 31-(y-100)/16;    // A lot of red
                unsigned short int t = r<<11 | g << 5 | b;
                *((unsigned short int*)(fbp + location)) = t;
            }

        }
    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}

  34  17


ベストアンサー

次のいくつかの実験で成功しました。

まず、Xが32ビットに埋め込まれたTrueColor RGBを使用しているかどうかを調べます(または、これが当てはまると仮定します)。 次に、fb0への書き込み許可があるかどうか(およびそれが存在するかどうか)を調べます。 これらが当てはまる場合(そして、多くの最新のツールキット/デスクトップ/ PCがこれらをデフォルトとして使用するかもしれないと思う)、あなたは以下を行うことができるはずです(そしてこれらのデフォルトが保持されない場合、おそらくいくつかの成功をまだ持つことができるでしょう詳細は異なる場合がありますが、次のテスト):

テスト1:仮想端末(X)を開き、次を入力します:$ echo “ddd …​ ddd “> / dev / fb0ここで…​ 実際にはdのいくつかの画面いっぱいです。 結果は、エコー文字列の長さと有効にしたピクセル解像度に応じて、画面の上部に1つ以上の(部分的な)灰色の線が表示されます。 任意の文字を選択することもできます(ASCII値はすべて0x80未満なので、生成される色は濃い灰色になります。) グレー以外のものが必要な場合は文字を変更します)。 明らかに、これをシェルループに一般化するか、大きなファイルをcatして効果をより明確に確認できます。例:$ cat /lib/libc.so.6> / dev / fb0 fsfサポーター;-P

画面の大部分が上書きされても心配する必要はありません。 Xはまだマウスポインターを制御し、ウィンドウがどこにマップされるかという考えを持っています。 あなたがしなければならないのは、任意のウィンドウをつかみ、それを少しドラッグしてノイズを消すことです。

テスト2:cat / dev / fb0> xxxを実行し、デスクトップの外観を変更します(たとえば、新しいウィンドウを開いて他のウィンドウを閉じます)。 最後に、逆を実行します。catxxx> / dev / fb0を使用して、古いデスクトップを復元します。

ハ、まあ、そうでもない。 古いデスクトップのイメージは幻想であり、ウィンドウをフルスクリーンで開くとすぐにそれを省くことができます。

テスト3:/ dev / fb0の以前のダンプを取得し、ピクセルの色を変更する小さなアプリを作成します。たとえば、赤のコンポーネントを削除したり、青を増強したり、赤と緑を反転したりします。 次に、これらのピクセルを新しいファイルに書き戻します。後で、テスト2の単純なシェルアプローチを使用して確認できます。 また、ピクセルごとに4バイトのB-G-R-Aを扱うことになります。 これは、4バイトごとに無視し、各セットの最初のバイトを青のコンポーネントとして扱うことを意味します。 「ARGB」はビッグエンディアンです。したがって、C配列のインデックスを増やしてこれらのバイトにアクセスすると、最初に青、次に緑、赤の順になります。 すなわち、B-G-R-A(A-R-G-Bではありません)。

テスト4:ビデオの速度でループする任意の言語でアプリを作成し、画面の一部に非正方形の画像(xeyesと考えてください)を送信して、ウィンドウの境界なしでアニメーションを作成します。 余分なポイントについては、アニメーションを画面全体に移動させます。 小さい行に相当するピクセルを描画した後は、大きなスペースをスキップする必要があります(おそらく、アニメーション化される画像よりもはるかに広い画面幅を補うためです)。

テスト5:友達にトリックをかけます。たとえば、テスト4を拡張して、アニメーションの人物の写真がデスクトップにポップアップ表示されるようにし(ピクセルデータを取得するために自分で撮影する)、重要なデスクトップの1つに移動しますフォルダを拾い上げてバラバラにし、ヒステリックに笑い始め、火の玉が出てデスクトップ全体を飲み込みます。 これはすべて幻想になりますが、少しおかしくなります。 しかし、これを学習体験として使用して、Linuxとオープンソースを披露し、初心者よりも実際よりもはるかに怖いことを示します。 [Linuxでの「ウイルス」は一般に無害な幻想です]

11


X11を実行している場合は、X11 APIを使用して画面に描画する必要があります。 Xサーバーを迂回することは非常に壊れています(そして、多くの場合、これまで見てきたように機能しません)。 また、クラッシュや、一般的なディスプレイの破損を引き起こす可能性があります。

すべての場所(コンソールとXの両方)で実行できるようにする場合は、SDLまたはGGIをご覧ください。 X11のみに関心がある場合は、GTK、QT、またはXlibを使用できます。 たくさんのオプションがあります…​

7


上記のように、/ dev / fb0への書き込みを試みる前に注意してください。 私はubuntu 10.04のXの下で試してみましたが、a)視覚的には何も起こりませんでした、b)すべてのシェルウィンドウ、他のttyも破壊し、カーネルエラーと機能不足につながりました。

2


乗算を自分で行うのではなく、screensizeにfb_fix_screeninfo.smem_lenを使用する必要があります。 バッファーは、4バイトまたは他の何かに整列している場合があります。

screensize = finfo.smem_len;

1


このプログラムを使用して全画面を記述したときにクラッシュしたのは、画面サイズの計算が間違っているためです。

// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

これは次のとおりです。

/* Calculate the size of the screen in bytes */
screensize = vinfo.xres_virtual * vinfo.yres_virtual * (vinfo.bits_per_pixel / 8);

0


プログラムをデバッグすると、次の行が見つかります。

 screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

`screensize`は0です。 vinfo.xresが0であるため。 次のように変更する必要があります。

long ppc_fx = (((long)fixed_info.smem_start) - ((long) fixed_info.smem_start & ~(PAGE_SIZE-1)));
screensize = finfo.smem_len + ppc_fx;

_
Linux 2.6.2以降? 、mmap()の2番目の引数 `screensize`は0であってはなりません。 そうでない場合、mmap()はMAP_FAILEDを返します。
_

0


スクロールできるようにする必要があるという理由だけで、フレームバッファベースのプログラムを書くことを考えています(SDRウォーターフォール)。 https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567スクロールテストの成功を確認してください。 これらの2つの構造体では、ioctlを使用して情報を取得しますが、色深度に関するものもあります。 あなたは私と同じ例に基づいてプログラムを作成したようです。 Linux(Raspberry Pi)のフレームバッファーからピクセルカラーを取得する方法

私のRaspberry Piでは、Xを使用しても使用しなくても、私のものは問題なく動作します。 私のラップトップの画面には影響しません。 / dev / fb0があり、プログラムは実行され、数字は正しく見えますが、視覚的には何もしません。 多分それはダブルバッファリングされているか何かです。

Xの下では、実際にはダメージを与えません。 いくつかのウィンドウをドラッグすると、すべてが再描画されます。 それから、画面に表示されているものをバックアップし、完了したら元に戻すことにしました。 移動して元に戻したウィンドウは、触ったことがないかのように機能します。 Xは、スクリーンバッファーを台無しにしたことを認識しません。Xがそこに何を置いているかを認識し、それに応じてマウスクリックを登録します。 ウィンドウを移動して元に戻さなかった場合、クリックは元の場所で機能します。

0


タイトルとURLをコピーしました