Skip to content

Instantly share code, notes, and snippets.

@FredEckert
Created August 22, 2012 13:15
Show Gist options
  • Star 48 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save FredEckert/3425429 to your computer and use it in GitHub Desktop.
Save FredEckert/3425429 to your computer and use it in GitHub Desktop.
Paint Pixels to Screen via Linux FrameBuffer
/*
To test that the Linux framebuffer is set up correctly, and that the device permissions
are correct, use the program below which opens the frame buffer and draws a gradient-
filled red square:
retrieved from:
Testing the Linux Framebuffer for Qtopia Core (qt4-x11-4.2.2)
http://cep.xor.aps.anl.gov/software/qt4-x11-4.2.2/qtopiacore-testingframebuffer.html
*/
#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;
}
@BartekLew
Copy link

BartekLew commented Apr 20, 2018

This code makes assumptions which may be false:

  1. There is no padding (ie. row length is xres*bytes_per_pixel -> see fixed_info.line_length) when counting buffer size. Interesting that in pixel location this variable is used (possible segmentation fault).
  2. Colors are in blue-green-red-transp order and all 8bit long if 32bpp.
    Probably more

plus, I don't know why location+=4 is commented. This stuff is generally very hardware/mode specific. Better be careful.

There is also another detail, when you run it, the console will override your changes. If you enter graphic mode, you'll get an exclusive access to the framebuffer and the console will come back to the original state when the program closes. Another good thing is that opening TTY will fail in X11 so the user won't be confused that nothing happens. Here's my implementation of a similar program with all above details taken into account:

https://github.com/BartekLew/fblib/tree/fb-example

Copy link

ghost commented Sep 12, 2020

Hey BartekLew,

the location += 4 is commented because it has no actual use, it will be reset the next run anyway. I guess this is a relict of not using the alpha-channel and skipping it for the next calculation of location?!

Your code here will segfault, because you take line_length from finfo, but that is based on x/yres_virtual, which may differ from the normal resolution.

If you switch to xres_virtual, the code will (likely) never segfault.

screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; <-- this will give different results each time you run it.
screensize = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8; <-- will always work

You can still write in only the "real" part (i have 2 screens diff. resolution) but you need to map it to the virtual resolution or it will segfault.

@Dhina17
Copy link

Dhina17 commented Oct 23, 2021

Can you add example for 1 bits per pixel fb?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment