it-swarm.com.de

Malen Sie Pixel mit Linux FrameBuffer auf dem Bildschirm

Ich war neulich von der kuriosen Idee beeindruckt, Eingaben aus/dev/urandom zu übernehmen, relevante Zeichen in zufällige Ganzzahlen umzuwandeln und diese Ganzzahlen als die rgb/x-y-Werte für Pixel für das Malen auf dem Bildschirm zu verwenden.

Ich habe einige Nachforschungen angestellt (hier zu StackOverflow und anderswo), und viele meinen, dass Sie einfach in/dev/fb0 schreiben können, da es sich um die Dateidarstellung des Geräts handelt. Leider scheint dies keine sichtbaren Ergebnisse zu ergeben.

Ich habe ein Beispiel-C-Programm gefunden, das aus einem QT-Lernprogramm stammt (nicht mehr verfügbar), das eine MMAP zum Schreiben in den Puffer verwendet hat. Das Programm wird erfolgreich ausgeführt, jedoch keine Ausgabe auf dem Bildschirm. Interessanterweise sah ich, als ich meinen Laptop in Suspend ablegte und später wieder herstellte, ein kurzes Aufleuchten des Bildes (ein rotes Quadrat), das viel früher in den Framebuffer geschrieben wurde. Funktioniert das Schreiben in den Framebuffer in Linux nicht mehr für das Malen auf dem Bildschirm? Idealerweise würde ich gerne ein (ba) sh-Skript schreiben, aber C oder ähnliches würde auch funktionieren. Vielen Dank!

BEARBEITEN: Hier ist das Beispielprogramm ..., das Tierärzten bekannt vorkommen kann.

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

Wenn Sie X11 ausführen, MÜSSEN Sie X11-APIs durchlaufen, um auf den Bildschirm zu zeichnen. Das Durchlaufen des X-Servers ist sehr fehlerhaft (und funktioniert oftmals nicht). Dies kann auch zu Abstürzen führen oder nur zu einer allgemeinen Anzeige.

Wenn Sie überall laufen möchten (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 ...

7
derobert

Ich hatte Erfolg mit den folgenden wenigen Experimenten.

Stellen Sie zunächst fest, ob X TrueColor RGB auf 32 Bit aufgefüllt hat (oder nehmen Sie einfach an, dies ist der Fall). Finden Sie dann heraus, ob Sie Schreibberechtigung für fb0 haben (und dass es existiert). Wenn diese zutreffend sind (und ich erwarte, dass viele moderne Toolkits/Desktops/PCs diese als Standard verwenden), sollten Sie Folgendes tun können (und wenn diese Standardeinstellungen nicht zutreffen, können Sie wahrscheinlich trotzdem Erfolg haben.) die folgenden Tests, die Details können jedoch variieren):

Test 1: Öffnen Sie ein virtuelles Terminal (in X) und geben Sie Folgendes ein: $ Echo "ddd ... ddd">/dev/fb0 Wobei die ... eigentlich ein paar Bildschirmfüllungen von d ist . Das Ergebnis wird eine oder mehrere (teilweise) graue Linien am oberen Bildschirmrand sein, abhängig davon, wie lange 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, dh, die erzeugte Farbe ist dunkelgrau .. und variiert die Buchstaben, wenn Sie etwas anderes als Grau möchten). Natürlich kann dies auf eine Shell-Schleife verallgemeinert werden, oder Sie können eine große Datei kategorisieren, um den Effekt klarer zu sehen: zB: $ Cat /lib/libc.so.6>/dev/fb0 Um sehen die wahren farben einiger fsf-unterstützer ;-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 weiß immer noch, wo die Fenster zugeordnet sind. Alles, was Sie tun müssen, ist, jedes Fenster zu packen und etwas zu verschieben, um das Rauschen zu löschen.

Test 2: cat/dev/fb0> xxx Dann ändere das Aussehen deines Desktops (z. B. neue Fenster öffnen und andere schließen) . Zum Abschluss mache ich die umgekehrte Richtung: cat xxx>/dev/fb0 Holen Sie sich Ihren alten Desktop zurück!

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

Test 3: Schreiben Sie eine kleine App, die einen vorherigen Dump von/dev/fb0 abruft und die Farben der Pixel ändert, z. B. um die rote Komponente zu entfernen oder das Blau zu erhöhen oder Rot und Grün umzukehren usw. Schreiben Sie diese dann zurück Pixel in eine neue Datei, die Sie später mit dem einfachen Shell-Ansatz von Test 2 betrachten können. Beachten Sie außerdem, dass Sie mit BGRA-4-Byte-Mengen pro Pixel zu tun haben werden. Das bedeutet, dass Sie jedes 4. Byte ignorieren und das erste in jedem Satz als blauen Anteil behandeln möchten. "ARGB" ist Big-Endian. Wenn Sie also diese Bytes durch einen ansteigenden Index eines C-Arrays aufrufen, würde zuerst Blau und dann Grün und dann Rot erscheinen. B-G-R-A (nicht A-R-G-B).

Test 4: Schreiben Sie eine App in einer beliebigen Sprache, die mit Videogeschwindigkeit durchläuft und ein nicht quadratisches Bild (think xeyes) an einen Teil des Bildschirms sendet, um eine Animation ohne Fensterrahmen zu erstellen. Wenn Sie zusätzliche Punkte erhalten möchten, bewegen Sie die Animation über den gesamten Bildschirm. Nach dem Zeichnen der Pixel einer kleinen Zeile müssen Sie einen großen Bereich überspringen (um die Bildschirmbreite auszugleichen, die wahrscheinlich viel breiter ist als das animierte Bild).

Test 5: Spielen Sie einem Freund einen Trick, zB erweitern Sie Test 4, sodass ein Bild einer animierten Person auf dem Desktop erscheint (möglicherweise filmen Sie sich selbst, um die Pixeldaten zu erhalten), und geht dann zu einem der wichtigsten Desktops Ordner, nimmt den Ordner auf und zerfetzt ihn, dann beginnt er hysterisch zu lachen, und dann muss ein Feuerball herauskommen und seinen gesamten Desktop überdecken. Obwohl dies alles eine Illusion sein wird, sind sie vielleicht ein bisschen ausgeflippt. Verwenden Sie dies jedoch als Lernerfahrung, um Linux und Open Source vorzuführen und zu zeigen, wie viel beängstigender es für einen Anfänger aussieht, als es tatsächlich ist. [die "Viren" sind unter Linux im Allgemeinen harmlose Illusionen]

11
Jose_X

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

2
David

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

screensize = finfo.smem_len;
1
Alex Arsenault

wenn Sie Ihr Programm debuggen, finden Sie die Zeile:

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

screensize ist 0. da 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 2. Argument von mmap (), screensize, darf nicht 0 sein. Andernfalls gibt mmap () MAP_FAILED zurück.

0
Hsiang Chen

Ich denke darüber nach, ein Framebuffer-basiertes Programm zu schreiben, nur weil ich scrollen muss (SDR-Wasserfall). Siehe https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567 Den Scroll-Test halte ich für erfolgreich. In diesen 2 Strukturen holen wir von ioctl für Infos auch Sachen zur Farbtiefe. Sie scheinen Ihr Programm auf demselben Beispiel aufgebaut zu haben wie ich. Wie bekomme ich Pixelfarbe aus dem Framebuffer unter Linux (Raspberry Pi)

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

Unter X macht es eigentlich keinen Schaden. Wenn Sie einige Fenster herumziehen, wird alles neu erstellt. Dann entschied ich mich, das auf dem Bildschirm zu sichern und zurückzusetzen, wenn ich fertig war, das funktioniert auch. Ein Fenster, das ich verschoben und zurückgesetzt habe, funktioniert genauso, als hätte ich es nie berührt. X erkennt nicht, dass ich den Bildschirmpuffer durcheinander gebracht habe, er weiß, was er dort abgelegt hat, und registriert entsprechend Mausklicks. Wenn ich ein Fenster bewegte und es nicht zurücklegte, funktionierten die Klicks immer noch dort, wo sie waren.

0
Alan Corey

Als ich dieses Programm zum Schreiben des Vollbildschirms verwendete, war es abgestürzt, dass die Berechnung der Bildschirmgröße falsch ist.

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

Dies soll sein:

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