Über Linux FrameBuffer Pixel auf den Bildschirm malen

Lesezeit: 12 Minuten

Benutzeravatar von Richard Martinez
Richard Martínez

Ich hatte kürzlich die merkwürdige Idee, Eingaben von /dev/urandom zu nehmen, relevante Zeichen in zufällige Ganzzahlen umzuwandeln und diese Ganzzahlen als RGB/XY-Werte für Pixel zu verwenden, die auf den Bildschirm gezeichnet werden sollen.

Ich habe einige Nachforschungen angestellt (hier auf StackOverflow und anderswo) und viele schlagen vor, dass Sie einfach direkt in /dev/fb0 schreiben können, da dies die Dateidarstellung des Geräts ist. Leider scheint dies zu keinen visuell erkennbaren Ergebnissen zu führen.

Ich habe ein Beispiel-C-Programm gefunden, das aus einem QT-Tutorial stammt (nicht mehr verfügbar), das eine mmap verwendet, um in den Puffer zu schreiben. Das Programm läuft erfolgreich, aber wieder keine Ausgabe auf dem Bildschirm. Interessanterweise sah ich, als ich meinen Laptop in den Suspend-Modus versetzte und ihn später wieder herstellte, ein kurzes Aufblitzen des Bildes (ein rotes Quadrat), das viel früher in den Framebuffer geschrieben wurde. Funktioniert das Schreiben in den Framebuffer unter Linux nicht mehr, um auf den Bildschirm zu malen? Idealerweise würde ich gerne ein (ba)sh-Skript schreiben, aber C oder ähnliches würde auch funktionieren. Vielen Dank!

EDIT: Hier ist das Beispielprogramm … kann Tierärzten bekannt vorkommen.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

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;
}

  • Idealerweise muss dies für die meisten (alle?) Linux-Systeme (DE-unabhängig) funktionieren, und andere Kompatibilität wird geschätzt, ist aber optional.

    – Richard Martínez

    14. Februar 2011 um 20:31 Uhr

  • Das Framebuffer-Gerät ist oft (aber nicht immer) unabhängig von X – versuchen Sie es mit einem Wechsel auf eine virtuelle Konsole ctrl-alt-f1 oder ctrl-alt-f2 und dort die Demo laufen lassen.

    – Café

    14. Februar 2011 um 20:41 Uhr

  • Interessant … das scheint zu funktionieren. Gibt es eine Möglichkeit, dass ich die Anzeige als tty7 (X-Server) einstellen könnte?

    – Richard Martínez

    14. Februar 2011 um 20:58 Uhr

  • Hinweis, Wikipedia Verknüpfung[/link] erwähnt einige Programme, die den Framebuffer direkt verwenden, wie MPlayer. Wie hängen sie die Ausgabe an die Desktop-Umgebung an?

    – Richard Martínez

    14. Februar 2011 um 21:07 Uhr


  • @RichardMartinez: Wie es heißt: “Grafikprogramme vermeiden den hohen Overhead des X Window Systems.” Diese Programme können direkt darauf zugreifen, wenn sie es sind nicht läuft unter X Windows (z. B. auf einem eingebetteten Gerät mit einem LCD-Bildschirm), denke ich.

    – Craig McQueen

    20. März 2013 um 0:40 Uhr


Benutzeravatar von Jose_X
Jose_X

Ich hatte Erfolg mit den folgenden wenigen Experimenten.

Finden Sie zuerst heraus, ob X TrueColor RGB verwendet, das auf 32 Bit aufgefüllt ist (oder nehmen Sie einfach an, dass dies der Fall ist). Finden Sie dann heraus, ob Sie Schreibrechte auf fb0 haben (und dass es existiert). Wenn diese zutreffen (und ich gehe davon aus, dass viele moderne Toolkits/Desktops/PCs diese als Standard verwenden), sollten Sie in der Lage sein, Folgendes zu tun (und wenn diese Standardwerte nicht gelten, können Sie wahrscheinlich immer noch etwas Erfolg damit haben die folgenden Tests, obwohl die Details variieren können):

Test 1: Öffnen Sie ein virtuelles Terminal (in X) und geben Sie Folgendes ein: $ echo “ddd … ddd” >/dev/fb0 wobei … eigentlich ein paar Bildschirme von d sind. Das Ergebnis sind eine oder mehrere (teilweise) graue Linien am oberen Rand Ihres Bildschirms, je nachdem, wie lang Ihr Echo-String ist und welche Pixelauflösung Sie aktiviert haben. Sie können auch beliebige Buchstaben auswählen (die ASCII-Werte sind alle kleiner als 0x80, sodass die erzeugte Farbe dunkelgrau ist.. und variieren Sie die Buchstaben, wenn Sie etwas anderes als Grau wünschen). Offensichtlich kann dies auf eine Shell-Schleife verallgemeinert werden, oder Sie können eine große Datei caten, um den Effekt deutlicher zu sehen: zB: $ cat /lib/libc.so.6 >/dev/fb0, um das wahre Gesicht einiger zu sehen fsf-Anhänger ;-P

Machen Sie sich keine Sorgen, wenn ein großer Teil Ihres Bildschirms überschrieben wird. X hat immer noch die Kontrolle über den Mauszeiger und hat immer noch eine Vorstellung davon, wo Fenster abgebildet werden. Alles, was Sie tun müssen, ist, ein beliebiges Fenster zu greifen und es ein wenig herumzuziehen, um das Rauschen zu löschen.

Test 2: cat /dev/fb0 > xxx ändern Sie dann das Aussehen Ihres Desktops (z. B. neue Fenster öffnen und andere schließen). Machen Sie schließlich das Gegenteil: cat xxx > /dev/fb0, um Ihren alten Desktop wiederherzustellen!

Ha, naja, nicht ganz. Das Bild Ihres alten Desktops ist eine Illusion, und Sie werden schnell darauf verzichten, wenn Sie ein beliebiges Fenster im Vollbildmodus öffnen.

Test 3: Schreiben Sie eine kleine App, die sich einen vorherigen Dump von /dev/fb0 schnappt und die Farben der Pixel ändert, z. B. um die rote Komponente zu entfernen oder das Blau zu verstärken oder Rot und Grün umzukehren usw. Dann schreiben Sie diese zurück Pixel in eine neue Datei, die Sie sich später über den einfachen Shell-Ansatz von Test 2 ansehen können. Beachten Sie auch, dass Sie es wahrscheinlich mit BGRA-4-Byte-Mengen pro Pixel zu tun haben werden. Das bedeutet, dass Sie jedes vierte Byte ignorieren und auch das erste in jedem Satz als blaue Komponente behandeln möchten. “ARGB” ist Big-Endian, wenn Sie also diese Bytes durch den zunehmenden Index eines C-Arrays besuchen, würde Blau zuerst kommen, dann Grün, dann Rot … dh BGRA (nicht ARGB).

Test 4: Schreiben Sie eine App in einer beliebigen Sprache, die sich mit Videogeschwindigkeit wiederholt und ein nicht quadratisches Bild (denken Sie an Xeyes) an einen Teil des Bildschirms sendet, um eine Animation ohne Fensterränder zu erstellen. Lassen Sie sich für Extrapunkte die Animation über den gesamten Bildschirm bewegen. Sie müssen sicherstellen, dass Sie einen großen Raum überspringen, nachdem Sie eine kleine Reihe von Pixeln gezeichnet haben (um die Bildschirmbreite auszugleichen, die wahrscheinlich viel breiter ist als das animierte Bild).

Test 5: Spielen Sie einem Freund einen Streich, erweitern Sie zB Test 4 so, dass ein Bild einer animierten Person auf ihrem Desktop erscheint (vielleicht filmen Sie sich selbst, um die Pixeldaten zu erhalten) und gehen dann zu einem ihrer wichtigen Desktops Ordner, hebt den Ordner auf und zerfetzt ihn, fängt dann an, hysterisch zu lachen, und dann kommt ein Feuerball heraus und verschlingt ihren gesamten Desktop. Obwohl dies alles eine Illusion sein wird, werden sie vielleicht ein bisschen ausflippen … aber nutzen Sie das als Lernerfahrung, um Linux und Open Source vorzuführen und zu zeigen, wie es für einen Anfänger viel beängstigender aussieht, als es tatsächlich ist. [the “virus” are generally harmless illusions on Linux]

  • 1. Ich konnte X nie mit dem Framebuffer beeinflussen. Es funktioniert nur in einem TTY. 2. Es ist tatsächlich BGRT. Sie werden sehen, dass darauf verwiesen wird, wenn Sie die Kernel-Meldungen ungefähr zu dem Zeitpunkt beachten, zu dem es das fb-Gerät während des Bootens einrichtet. Ich weiß nicht, was das T bedeutet, aber es ist sicherlich nicht Alpha oder “Transparenz”. Tatsächlich scheint das vierte Byte überhaupt nichts zu tun. Ich habe versucht, Farben mit dem vierten Byte von 0 bis 255 zu zeichnen, und es sieht genau gleich aus. Ich schätze, sie sparen nur einen vierten Kanal für den Fall, dass Aliens uns neue Farben oder so etwas vorstellen.

    – Braden Best

    23. September 2015 um 17:32 Uhr

  • Bearbeiten: Herausgefunden dass die T in BGRT eigentlich ist Transparenz. Auch bestätigt direkt aus dem Maul des Pferdes, dass es so ist BGRT und nicht BGRA. Obwohl ich immer noch keine Transparenz bekomme, um irgendetwas transparent zu machen.

    – Braden Best

    23. September 2015 um 19:52 Uhr


  • @B1KMusic AIUI Sie erhalten keine Transparenz, da der Bildspeicher das “hinterste” Ding ist. Dahinter ist nichts. T ist für die meisten Geräte nur ein Dummy-Wert. Wenn Sie ein spezielles Framebuffer-Gerät hätten, das mit einem Bildschirm spricht, der Transparenz/Opazität unterstützt (z. B. ein TFT, das auch weiße Pixel erzeugen kann, nicht nur transparente, die die Hintergrundbeleuchtung durchscheinen lassen), würden Sie einen Effekt sehen. Außerdem überschreiben Sie den Backbuffer, sodass Sie alle vorherigen Werte zerstören und Alpha selbst berücksichtigen müssten.

    – Ulizeuge

    1. Oktober 2015 um 7:37 Uhr


  • Ja, versuche einzustellen 0x00 zu 0xFF denn das erste Byte wird es nicht auf magische Weise einstellen 0x77 wenn das vierte Byte ist 0x77oder was auch immer interpretiert werden würde 50%. Ich erinnere mich, dass ich eine Art Algorithmus implementiert habe, um zwei Farben und einen Alphawert zu nehmen und die resultierende Farbe zurückzugeben. Ich glaube, ich habe den Algorithmus gefunden, also Hier ist eine Demo, die zeigt, wovon ich spreche.

    – Braden Best

    1. Oktober 2015 um 14:42 Uhr

  • (@uliwitness, dass dieser Kommentar an Sie gerichtet war)

    – Braden Best

    1. Oktober 2015 um 14:49 Uhr

Wenn Sie X11 ausführen, MÜSSEN Sie die X11-APIs durchlaufen, um auf den Bildschirm zu zeichnen. Das Umgehen des X-Servers ist sehr kaputt (und funktioniert, wie Sie gesehen haben, oft nicht). Es kann auch zu Abstürzen oder nur zu einer allgemeinen Beschädigung der Anzeige kommen.

Wenn Sie überall laufen wollen (sowohl Konsole als auch unter X), schauen Sie sich SDL oder GGI an. Wenn Sie sich nur für X11 interessieren, können Sie GTK, QT oder sogar Xlib verwenden. Es gibt viele, viele Möglichkeiten…

  • Danke für den Tipp. Zwischen diesem und dem obigen Kommentar von caf ist mir klar geworden, wie niedrig der Framebuffer ist. Ich denke, ich bleibe der Einfachheit halber für dieses Skript dabei, aber ich werde definitiv Systeme höherer Ebene (mindestens X) verwenden, wenn ich an etwas Komplexerem interessiert bin.

    – Richard Martínez

    14. Februar 2011 um 21:21 Uhr

Ich würde sagen, seien Sie vorsichtig, bevor Sie versuchen, in /dev/fb0 zu schreiben, wie oben vorgeschlagen. Ich habe es unter X in Ubuntu 10.04 ausprobiert und a) es ist visuell nichts passiert, b) es hat alle Shell-Fenster zerstört, sogar andere ttys, was zu Kernel-Fehlern und mangelnder Funktionalität führte.

  • Das ist interessant. Ich habe dies (cat /dev/urandom > /dev/fb0) auf ein paar verschiedenen Systemen durchgeführt, und ich bekomme normalerweise keine Ausgabe, während ich auf X bin, aber einen coolen Bildschirm voller zufälliger Pixel, wenn ich mich auf einem der virtuellen TTYs befinde . Ich bin überrascht, dass so etwas andere Teile des Betriebssystems ruinieren würde, aber vielleicht ist X ausgeflippt, wenn es sagt, dass Dinge bereits auf dem Bildschirm gezeichnet wurden.

    – Richard Martínez

    29. Juni 2012 um 16:34 Uhr

  • Soweit ich weiß, funktioniert das Schreiben zufälliger Werte in den Grafikspeicher (/dev/fd0) eher, wenn X den Framebuffer verwendet und KMS verwendet wird, als wenn X seine eigene Art der Grafikverwaltung verwendet.

    – Alexander

    24. Oktober 2012 um 18:58 Uhr

Benutzeravatar von Alan Corey
Alan Corey

Ich denke darüber nach, ein Framebuffer-basiertes Programm zu schreiben, nur weil ich scrollen können muss (SDR-Wasserfall). Sehen https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567 Den Scrolltest halte ich für gelungen. In diesen 2 Strukturen, die wir von ioctl für Informationen abrufen, gibt es auch Dinge über die Farbtiefe. Sie scheinen Ihr Programm auf dem gleichen Beispiel aufgebaut zu haben wie ich. So erhalten Sie Pixelfarbe aus Framebuffer unter Linux (Raspberry Pi)

Mine funktioniert gut auf meinem Raspberry Pi, entweder mit X oder nicht. Es hat keine Auswirkungen auf den Bildschirm meines Laptops. Das hat eine /dev/fb0, das Programm läuft und die Zahlen sehen richtig aus, aber es macht optisch nichts. Vielleicht ist es doppelt gepuffert oder so.

Unter X richtet es eigentlich keinen Schaden an. Wenn Sie einige Fenster herumziehen, damit die Dinge neu gezeichnet werden, kommt alles zurück. Dann habe ich beschlossen, das, was auf dem Bildschirm ist, zu sichern und es wieder zurückzusetzen, wenn ich fertig bin, das funktioniert auch. Ein Fenster, das ich verschoben und wieder eingesetzt habe, funktioniert genauso, als hätte ich es nie berührt. X merkt nicht, dass ich mit dem Bildschirmpuffer herumgespielt habe, es weiß, was es dort abgelegt hat, und registriert Mausklicks entsprechend. Wenn ich ein Fenster bewegte und es nicht zurückstellte, funktionierten die Klicks immer noch dort, wo es war.

Sie sollten fb_fix_screeninfo.smem_len für die Bildschirmgröße verwenden, anstatt die Multiplikation selbst durchzuführen. Der Puffer kann auf 4 Bytes oder etwas anderes ausgerichtet sein.

screensize = finfo.smem_len;

Benutzeravatar von Hsiang Chen
Hsiang Chen

Wenn Sie Ihr Programm debuggen, finden Sie die Zeile:

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

screensize ist 0. weil vinfo.xres 0 ist. Sie sollten es ändern in:

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

seit Linux 2.6.2? , das zweite Argument von mmap(), screensizedarf nicht 0 sein. Andernfalls gibt mmap() MAP_FAILED zurück.

Benutzeravatar von Getz
Getz

Als ich dieses Programm benutzte, um Vollbild zu schreiben, war es abgestürzt, weil die Berechnung der Bildschirmgröße falsch war.

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

Das soll sein:

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

1400140cookie-checkÜber Linux FrameBuffer Pixel auf den Bildschirm malen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy