Skip to content

Instantly share code, notes, and snippets.

@angelcaru
Created February 27, 2025 22:35
Show Gist options
  • Save angelcaru/bbc9de6290e8d1372609f252adc91a45 to your computer and use it in GitHub Desktop.
Save angelcaru/bbc9de6290e8d1372609f252adc91a45 to your computer and use it in GitHub Desktop.
Simple example of writing directly to `/dev/fb0` in C on Linux
#include <stdint.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
typedef union {
uint32_t rgba;
struct {
uint8_t b, g, r, a;
};
} Color;
#define RGBA(val) ((Color) { .rgba = val })
typedef struct {
size_t width;
size_t height;
size_t stride;
Color *pixels;
} Canvas;
#define CANVAS_AT(c, x, y) (c).pixels[(y) * (c).stride + (x)]
Canvas canvas_alloc(size_t width, size_t height) {
return (Canvas) {
.width = width,
.height = height,
.stride = width,
.pixels = malloc(sizeof(Color)*width*height),
};
}
void canvas_fill(Canvas c, Color color) {
for (size_t y = 0; y < c.height; y++) {
for (size_t x = 0; x < c.width; x++) {
CANVAS_AT(c, x, y) = color;
}
}
}
void canvas_fill_rect(Canvas c, int x0, int y0, int w, int h, Color color) {
for (int x = x0; x <= x0 + w; x++) {
if (0 <= x && x < c.width) {
for (int y = y0; y <= y0 + h; y++) {
if (0 <= y && y < c.height) {
CANVAS_AT(c, x, y) = color;
}
}
}
}
}
void canvas_write_to_fb0(Canvas c, int fd) {
lseek(fd, 0, SEEK_SET);
if (c.width != c.stride) {
for (size_t y = 0; y < c.height; y++) {
for (size_t x = 0; x < c.width; x++) {
write(fd, &CANVAS_AT(c, x, y), sizeof(Color));
}
}
} else {
write(fd, c.pixels, sizeof(Color)*c.width*c.height);
}
}
int main(void) {
if (setuid(0) < 0) {
fprintf(stderr, "ERROR: Could not setuid(0): %s\n", strerror(errno));
if (errno == EPERM) {
fprintf(stderr, "Maybe try running with sudo?\n");
}
return 1;
}
const char *file_path = "/dev/fb0";
int fd = open(file_path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "ERROR: Could not open file %s: %s\n", file_path, strerror(errno));
return 1;
}
printf("File descriptor of %s is %d\n", file_path, fd);
struct fb_var_screeninfo screeninfo;
if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo) < 0) {
fprintf(stderr, "ERROR: Could not use ioctl(): %s\n", strerror(errno));
return 1;
}
if (screeninfo.bits_per_pixel != 32) {
fprintf(stderr, "ERROR: color depths other than RGBA32? fuck that shii\n");
return 1;
}
Canvas c = canvas_alloc(screeninfo.xres, screeninfo.yres);
int x = 0;
int y = 0;
int w = 50;
while (1) {
canvas_fill(c, RGBA(0xFF181818));
canvas_fill_rect(c, x, y, w, w, RGBA(0xFFFF2020));
x += 1;
y += 1;
canvas_write_to_fb0(c, fd);
usleep(16);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment