Created
February 27, 2025 22:35
-
-
Save angelcaru/bbc9de6290e8d1372609f252adc91a45 to your computer and use it in GitHub Desktop.
Simple example of writing directly to `/dev/fb0` in C on Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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