blog · git · desktop · images · contact


Erster Versuch, unter Linux „etwas zu zeichnen“

2020-05-30

Ein interessantes Argument für Wayland ist dieses „Weglassen des Mittelsmanns“. („Middleman“ im Englischen. Klingt albern auf Deutsch.) „Alles wurde in den Kernel verschoben, wofür brauchen wir X11 noch?“ Was ist dieses „alles“? Wieso sehe ich in wlroots keine Grafiktreiber? Wie malt man unter Linux überhaupt irgendwas?

Der Mittelsmann

Hier geht es um zwei Dinge. Das eine ist Compositing. Falls man einen Compositor benutzt (tue ich nicht, habe ich nie), dann ist X11 wirklich ein Mittelsmann. Aus dieser Sicht ist X11 Zeitverschwendung und sollte weg.

Daran bin ich aber nicht interessiert. Ich benutze das nicht. Aber bei der Mittelsmann-Story geht es noch um etwas anderes.

Das alte Framebuffer-Device

Wir fangen mit etwas ganz einfachem an. Man beende seine X11- oder Wayland-Session und gehe zurück zum Linux VT. Dann führe man das aus:

#include <fcntl.h>
#include <linux/fb.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

int
main()
{
    int fd;
    struct fb_var_screeninfo screeninfo;
    uint32_t *data;
    uint32_t x, y, width, height, xor;

    fd = open("/dev/fb0", O_RDWR);
    if (fd == -1)
    {
        perror("open /dev/fb0");
        exit(EXIT_FAILURE);
    }

    ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo);
    if (screeninfo.bits_per_pixel != 32)
    {
        fprintf(stderr, "Expected 32 bits per pixel\n");
        exit(EXIT_FAILURE);
    }

    width = screeninfo.xres;
    height = screeninfo.yres;

    data = (uint32_t *)mmap(0, width * height * 4, PROT_READ | PROT_WRITE,
                            MAP_SHARED, fd, 0);
    if (data == MAP_FAILED)
    {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++)
        {
            xor = (x ^ y) % 256;
            data[y * width + x] = (xor << 16) | (xor << 8) | xor;
        }
    }

    exit(EXIT_SUCCESS);
}

Wir öffnen hier /dev/fb0, was heute auf quasi jedem Linuxrechner verfügbar ist. Wir fragen dann seine Größe ab und mmap()en den File-Deskriptor. Am Ende zeichnen wir ein XOR-Pattern.

Das Linux VT benutzt denselben Framebuffer selbst, daher wird unser Output damit konfliktieren. Sobald das Programm fertig ist, kommt die Shell wieder und der Prompt wird gezeichnet – mitten in unsere Textur rein.

Aber das ist total einfach. Einfacher geht’s nicht.

Man beachte, dass ich hier keine Doku verlinken kann. Das Programm oben basiert auf Code, den ich vor Jahren geschrieben habe. Damals muss ich wohl Goo^W DuckDuckGo benutzt haben, denn weder apropos FBIOGET_VSCREENINFO noch apropos fb0 noch man fbdev noch irgendwas anderes in dieser Richtung bringen ein Ergebnis zutage. Wenn es eine Manpage gibt, finde ich sie nicht.

Außerdem sind hier keine Treiber involviert. Der Kernel stellt ein allgemeines Framebuffer-Device bereit.

Weiter zu DRM

„DRM“ ist einer der schlimmsten Namen überhaupt, weil es in Konflikt steht mit „Digital Rights/Restrictions Management“, also viel Spaß beim Suchen nach dieser Abkürzung. Hier geht es aber um den Direct Rendering Manager. Das ist, was Wayland-Compositors meistens unter der Haube benutzen.

Mein eigentliches Ziel für diesen Blogpost war, das obige Programm auf DRM zu portieren. Alleine habe ich das nicht geschafft, weil … ich keine Doku gefunden habe. Weiß nicht, ob das mein Fehler ist oder ob sie schlichtweg nicht existiert.

Wenn man libdrm installiert, bekommt man die Manpage man 7 drm. Sie gibt schonmal eine kurze Einführung. Da sind auch ein paar weitere Manpages genannt, zum Beispiel drmOpen. Die existieren aber fast alle nicht. Stellt sich raus, dass die auch Upstream nicht existieren.

Es gibt dann noch die Wikiseite zu DRM bei FDO. Auf der wird ein bisschen geflucht. Nicht schlimm, das ist eh keine Doku zu libdrm, also der Bibliothek, die vom Userspace benutzt werden soll, sondern um die darunterliegende Kernelebene – also genau um das, was libdrm wegabstrahieren soll.

Lange Rede, kurzer Sinn: Falls es Doku gibt, kann ich sie nicht finden.

Was man aber findet, sind Beispielprogramm mit der Lieblingssuchmaschine. Damit habe ich wirklich ein Problem, weil mir die offizielle Doku einer Bibliothek viel lieber ist. Muss ich wohl weiter danach suchen.

Ein gutes und kurzes Beispiel ist das hier:

https://gist.github.com/uobikiemukot/c2be4d7515e977fd9e85

Das ist dann einfach anzupassen, sodass es das XOR-Pattern malt. Weil das auf GitHub gehostet ist und jeden Moment verschwinden kann, habe ich die modifizierte Version auf meinen Server kopiert:

linux-xor-drm.tar.gz

Es ist deutlich länger als das erste Programm oben, aber trotzdem spannend zu sehen, wie es funktioniert und dass es sich doch einigermaßen in Grenzen hält. Auch beendet es sich sauber und lässt keine Artefakte zurück. Wenn man wollte, könnte man auch direkt auf verschiedenen Monitoren etwas anderes zeichnen.

Ein weiteres gutes Beispiel ist das hier:

https://waynewolf.github.io/2012/09/05/libdrm-samples/

Man beachte auch hier wieder, dass DRM ein generisches Interface ist, das nicht spezifisch für eine bestimmte Hardware ist.

Nochmal der Mittelsmann

Wenn ich mich richtig erinnere (und da könnte ich falsch liegen, weil ich mich schon ein Jahrzehnt lang nicht mehr wirklich mit X.Org-Konfiguration auseinandergesetzt habe – das funktioniert ja schon lange einfach so), dann war X.Org früher für das gesamte Display verantwortlich. Treiber kamen auch von dort. Benutzereingaben hat es ebenfalls verwaltet.

Das ist jetzt so ziemlich alles im Kernel. DRM ist da nur ein Puzzelstück.

Dazu kommt: Moderne X11-Clients benutzen die Renderig-API von X11 gar nicht mehr. Die sagen X11 nicht mehr: „Zeichne eine Linie!“ Stattdessen rendern die alle lokal, geben X11 die finale Pixmap und sagen ihm dann: „Zeig’ das an, aber fass’ es bitte nicht weiter an!“ Die machen das aus Performancegründen und weil die X11-Rendering-API wirklich veraltet ist.

Diese zwei Aspekte zusammen machen X11 und X.Org zu einem Mittelsmann. Und dann kommt da noch die Compositing-Geschichte oben drauf.

Was übrig bleibt, ist das: Clients wollen in einen Buffer zeichnen und den dann dargestellt bekommen. Dazu Eingabe-Handling. Das ist dann, nach meinem Verständnis, so ziemlich genau Wayland.

Fazit

Doku zu libdrm wäre toll. Suche ich vielleicht weiter danach. Falls das eine arme Seele da draußen liest und weiß, wo man die findet, wäre ich über eine E-Mail sehr dankbar.

DRM ist natürlich auf 3D-Grafik und Multimonitorbetrieb ausgelegt, also ist das längst nicht mehr so einfach wie das Öffnen eines Devices und dann da reinzeichnen.

Wäre auch noch interessant, zu schauen, wie Modesetting eigentlich funktioniert. Und libinput?

Comments?