Linux framebuffer programming

framebuffer and memory

framebuffer is a memory area, provide “/dev/fbN” to access it.

open framebuffer

int fbdev_fd = open("/dev/fb0",O_RDWR);

get framebuffer size

struct fb_fix_screeninfo fbdev_finfo;
ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fbdev_finfo);
uint32_t fbdev_size = fbdev_finfo.smem_len;

use mmap()

uint8_t *fbdev_mem = (uint8_t *)mmap(NULL,fbdev_size,
				    PROT_READ | PROT_WRITE,
				    MAP_SHARED, fbdev_fd ,0);
memset(fbdev_mem, 0, fbdev_size); // make screen blank

use read() / write()

uint8_t *buf = (uint8_t *)malloc(fbdev_size);
memset(buf,0,fbdev_size);
write(fbdev_fd, buf, fbdev_size); // make screen blank

framebuffer data format

You can get and set parts of the color map. Communication is done with
16 bits per color part (red, green, blue, transparency) to support all
existing hardware. The driver does all the computations needed to
apply it to the hardware (round it down to less bits, maybe throw
away transparency).
       -- from:https://www.kernel.org/doc/html/latest/fb/framebuffer.html

get bits per pixel

struct fb_var_screeninfo fbdev_vinfo;
ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &fbdev_vinfo);
// you need fbdev_vinfo.bits_per_pixel

if bits_per_pixel is 8, it mean a pixel in memory use 1 bytes.

if bits_per_pixel is 32, it mean a pixel in memory use 4 bytes.

draw pixel

void fbdev_draw_pixel(uint x, uint y, uint32_t color) {
	// position in framebuffer, you can also use lseek(), write()
	int pos = y * fbdev_finfo.line_length +
		x * fbdev_vinfo.bits_per_pixel / 8;
	uint8_t *fbp8 = (uint8_t *)fbdev_mem + pos;
	uint16_t *fbp16 = (uint16_t *)fbp8;
	uint32_t *fbp32 = (uint32_t *)fbp8;
	switch(fbdev_vinfo.bits_per_pixel) {
	case 32:
		*fbp32 = color;
		break;
	case 16:
		*fbp16 = color;
		break;
	case 8:
		*fbp8 = color;
		break;
	default:
		*fbp8 = color;
		break;
	}
	return;
}

example:

fbdev_draw_pixel(100,100,0xFFFFFF);

you will see a white point on screen (100,100)

draw char use bitmap font

a simple 8x8 bitmap font define:

uint8_t bm_0[8] = {
  0b00000000,
  0b01111110,
  0b01000010,
  0b01000010,
  0b01000010,
  0b01000010,
  0b01111110,
  0b00000000
};

draw this font use printf:

int x, y;
for (y = 0; y < 8; y++) {
  for (x = 0; x < 8; x++) {
    if (bm_0[y] & 1 << x)
      putchar('#');
    else
      putchar(' ');
  }
  putchar('\n');
 }

draw this font on framebuffer:

int pos_x, pos_y;
pos_x = 100;
pos_y = 50;
int x, y;
for (y = 0; y < 8; y++) {
  for (x = 0; x < 8; x++) {
    if (bm_0[y] & 1 << x)
      fbdev_draw_pixel(pos_x+x,pos_y+y,0xFFFFFF);
    else
      fbdev_draw_pixel(pos_x+x,pos_y+y,0x000000);
  }
 }

this code will draw a 0 on screen (100,50) .

Last updated: 2023-06-28