Skip to content
Advertisement

Paint Pixels to Screen via Linux FrameBuffer

I was recently struck by a curious idea to take input from /dev/urandom, convert relevant characters to random integers, and use those integers as the rgb/x-y values for pixels to paint onto the screen.

I’ve done some research (here on StackOverflow and elsewhere) and many suggest that you can simply write to /dev/fb0 directly as it is the file representation of the device. Unfortunately, this does not seem to produce any visually apparent results.

I found a sample C program that was from a QT tutorial (no longer available) that used an mmap to write to the buffer. The program runs successfully, but again, no output to the screen. Interestingly enough, when I placed my laptop into Suspend and later restored, I saw a momentary flash of the image (a red square) that was written to the framebuffer much earlier. Does writing to the framebuffer work anymore in Linux for painting to screen? Ideally, I’d like to write a (ba)sh script, but C or similar would work as well. Thanks!

EDIT: Here’s the sample program…may look familiar to vets.

#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, %dbppn", 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;
}

Advertisement

Answer

If you’re running X11, you MUST go through X11 APIs to draw to the screen. Going around the X server is very broken (and, often as you’ve seen, does not work). It may also cause crashes, or just general display corruption.

If you want to be able to run everywhere (both console & under X), look at SDL or GGI. If you only care about X11, you can use GTK, QT, or even Xlib. There are many, many options…

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement