Skip to content

Instantly share code, notes, and snippets.

@uobikiemukot
Created July 10, 2013 07:19
Show Gist options
  • Save uobikiemukot/5964110 to your computer and use it in GitHub Desktop.
Save uobikiemukot/5964110 to your computer and use it in GitHub Desktop.
framebuffer drawing library
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/fb.h>
enum {
BITS_PER_BYTE = 8,
COLORS = 256, /* num of colors */
X_SCALE = 1, /* horizontal scale */
};
/*
Standard VGA colors
http://en.wikipedia.org/wiki/ANSI_escape_code
*/
const uint32_t color_list[COLORS] = {
/* system color: 16 */
0x000000, 0xAA0000, 0x00AA00, 0xAA5500, 0x0000AA, 0xAA00AA, 0x00AAAA, 0xAAAAAA,
0x555555, 0xFF5555, 0x55FF55, 0xFFFF55, 0x5555FF, 0xFF55FF, 0x55FFFF, 0xFFFFFF,
/* color cube: 216 */
0x000000, 0x00005F, 0x000087, 0x0000AF, 0x0000D7, 0x0000FF, 0x005F00, 0x005F5F,
0x005F87, 0x005FAF, 0x005FD7, 0x005FFF, 0x008700, 0x00875F, 0x008787, 0x0087AF,
0x0087D7, 0x0087FF, 0x00AF00, 0x00AF5F, 0x00AF87, 0x00AFAF, 0x00AFD7, 0x00AFFF,
0x00D700, 0x00D75F, 0x00D787, 0x00D7AF, 0x00D7D7, 0x00D7FF, 0x00FF00, 0x00FF5F,
0x00FF87, 0x00FFAF, 0x00FFD7, 0x00FFFF, 0x5F0000, 0x5F005F, 0x5F0087, 0x5F00AF,
0x5F00D7, 0x5F00FF, 0x5F5F00, 0x5F5F5F, 0x5F5F87, 0x5F5FAF, 0x5F5FD7, 0x5F5FFF,
0x5F8700, 0x5F875F, 0x5F8787, 0x5F87AF, 0x5F87D7, 0x5F87FF, 0x5FAF00, 0x5FAF5F,
0x5FAF87, 0x5FAFAF, 0x5FAFD7, 0x5FAFFF, 0x5FD700, 0x5FD75F, 0x5FD787, 0x5FD7AF,
0x5FD7D7, 0x5FD7FF, 0x5FFF00, 0x5FFF5F, 0x5FFF87, 0x5FFFAF, 0x5FFFD7, 0x5FFFFF,
0x870000, 0x87005F, 0x870087, 0x8700AF, 0x8700D7, 0x8700FF, 0x875F00, 0x875F5F,
0x875F87, 0x875FAF, 0x875FD7, 0x875FFF, 0x878700, 0x87875F, 0x878787, 0x8787AF,
0x8787D7, 0x8787FF, 0x87AF00, 0x87AF5F, 0x87AF87, 0x87AFAF, 0x87AFD7, 0x87AFFF,
0x87D700, 0x87D75F, 0x87D787, 0x87D7AF, 0x87D7D7, 0x87D7FF, 0x87FF00, 0x87FF5F,
0x87FF87, 0x87FFAF, 0x87FFD7, 0x87FFFF, 0xAF0000, 0xAF005F, 0xAF0087, 0xAF00AF,
0xAF00D7, 0xAF00FF, 0xAF5F00, 0xAF5F5F, 0xAF5F87, 0xAF5FAF, 0xAF5FD7, 0xAF5FFF,
0xAF8700, 0xAF875F, 0xAF8787, 0xAF87AF, 0xAF87D7, 0xAF87FF, 0xAFAF00, 0xAFAF5F,
0xAFAF87, 0xAFAFAF, 0xAFAFD7, 0xAFAFFF, 0xAFD700, 0xAFD75F, 0xAFD787, 0xAFD7AF,
0xAFD7D7, 0xAFD7FF, 0xAFFF00, 0xAFFF5F, 0xAFFF87, 0xAFFFAF, 0xAFFFD7, 0xAFFFFF,
0xD70000, 0xD7005F, 0xD70087, 0xD700AF, 0xD700D7, 0xD700FF, 0xD75F00, 0xD75F5F,
0xD75F87, 0xD75FAF, 0xD75FD7, 0xD75FFF, 0xD78700, 0xD7875F, 0xD78787, 0xD787AF,
0xD787D7, 0xD787FF, 0xD7AF00, 0xD7AF5F, 0xD7AF87, 0xD7AFAF, 0xD7AFD7, 0xD7AFFF,
0xD7D700, 0xD7D75F, 0xD7D787, 0xD7D7AF, 0xD7D7D7, 0xD7D7FF, 0xD7FF00, 0xD7FF5F,
0xD7FF87, 0xD7FFAF, 0xD7FFD7, 0xD7FFFF, 0xFF0000, 0xFF005F, 0xFF0087, 0xFF00AF,
0xFF00D7, 0xFF00FF, 0xFF5F00, 0xFF5F5F, 0xFF5F87, 0xFF5FAF, 0xFF5FD7, 0xFF5FFF,
0xFF8700, 0xFF875F, 0xFF8787, 0xFF87AF, 0xFF87D7, 0xFF87FF, 0xFFAF00, 0xFFAF5F,
0xFFAF87, 0xFFAFAF, 0xFFAFD7, 0xFFAFFF, 0xFFD700, 0xFFD75F, 0xFFD787, 0xFFD7AF,
0xFFD7D7, 0xFFD7FF, 0xFFFF00, 0xFFFF5F, 0xFFFF87, 0xFFFFAF, 0xFFFFD7, 0xFFFFFF,
/* gray scale: 24 */
0x080808, 0x121212, 0x1C1C1C, 0x262626, 0x303030, 0x3A3A3A, 0x444444, 0x4E4E4E,
0x585858, 0x626262, 0x6C6C6C, 0x767676, 0x808080, 0x8A8A8A, 0x949494, 0x9E9E9E,
0xA8A8A8, 0xB2B2B2, 0xBCBCBC, 0xC6C6C6, 0xD0D0D0, 0xDADADA, 0xE4E4E4, 0xEEEEEE,
};
const uint32_t bit_mask[] = {
0x00,
0x01, 0x03, 0x07, 0x0F,
0x1F, 0x3F, 0x7F, 0xFF,
0x1FF, 0x3FF, 0x7FF, 0xFFF,
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
};
const char *fb_path = "/dev/fb0";
struct pair { int x, y; };
struct color_t { uint32_t r, g, b; };
struct framebuffer {
char *fp; /* pointer of framebuffer(read only) */
//char *buf; /* copy of framebuffer */
int fd; /* file descriptor of framebuffer */
struct pair res; /* resolution (x, y) */
long screen_size; /* screen data size (byte) */
int line_length; /* line length (byte) */
int bpp; /* BYTES per pixel */
uint32_t color_palette[COLORS];
struct fb_cmap *cmap, *cmap_org;
};
struct fb_cmap *cmap_create(struct fb_var_screeninfo *vinfo)
{
struct fb_cmap *cmap;
if ((cmap = (struct fb_cmap *) calloc(1, sizeof(struct fb_cmap))) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
cmap->start = 0;
cmap->len = COLORS;
if ((cmap->red = (uint16_t *) calloc(1, sizeof(uint16_t) * COLORS)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
if ((cmap->green = (uint16_t *) calloc(1, sizeof(uint16_t) * COLORS)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
if ((cmap->blue = (uint16_t *) calloc(1, sizeof(uint16_t) * COLORS)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
cmap->transp = NULL;
return cmap;
}
void cmap_die(struct fb_cmap *cmap)
{
if (cmap) {
free(cmap->red);
free(cmap->green);
free(cmap->blue);
free(cmap->transp);
free(cmap);
}
}
void get_rgb(int i, struct color_t *color)
{
color->r = (color_list[i] >> 16) & bit_mask[8];
color->g = (color_list[i] >> 8) & bit_mask[8];
color->b = (color_list[i] >> 0) & bit_mask[8];
}
uint32_t bit_reverse(uint32_t val, int bits)
{
uint32_t ret = val;
int shift = bits - 1;
for (val >>= 1; val; val >>= 1) {
ret <<= 1;
ret |= val & 1;
shift--;
}
return ret <<= shift;
}
void cmap_init(struct framebuffer *fb, struct fb_var_screeninfo *vinfo)
{
int i;
uint16_t r, g, b;
struct color_t color;
if (ioctl(fb->fd, FBIOGETCMAP, fb->cmap_org) < 0) { /* not fatal */
cmap_die(fb->cmap_org);
fb->cmap_org = NULL;
}
for (i = 0; i < COLORS; i++) {
get_rgb(i, &color);
r = (color.r << BITS_PER_BYTE) | color.r;
g = (color.g << BITS_PER_BYTE) | color.g;
b = (color.b << BITS_PER_BYTE) | color.b;
*(fb->cmap->red + i) = (vinfo->red.msb_right) ?
bit_reverse(r, 16) & bit_mask[16]: r;
*(fb->cmap->green + i) = (vinfo->green.msb_right) ?
bit_reverse(g, 16) & bit_mask[16]: g;
*(fb->cmap->blue + i) = (vinfo->blue.msb_right) ?
bit_reverse(b, 16) & bit_mask[16]: b;
}
if (ioctl(fb->fd, FBIOPUTCMAP, fb->cmap) < 0) {
fprintf(stderr, "ioctl: FBIOPUTCMAP failed\n");
exit(EXIT_FAILURE);
}
}
uint32_t get_color(struct fb_var_screeninfo *vinfo, int i)
{
uint32_t r, g, b;
struct color_t color;
if (vinfo->bits_per_pixel == 8)
return i;
get_rgb(i, &color);
r = color.r >> (BITS_PER_BYTE - vinfo->red.length);
g = color.g >> (BITS_PER_BYTE - vinfo->green.length);
b = color.b >> (BITS_PER_BYTE - vinfo->blue.length);
if (vinfo->red.msb_right)
r = bit_reverse(r, vinfo->red.length) & bit_mask[vinfo->red.length];
if (vinfo->green.msb_right)
g = bit_reverse(g, vinfo->green.length) & bit_mask[vinfo->green.length];
if (vinfo->blue.msb_right)
b = bit_reverse(b, vinfo->blue.length) & bit_mask[vinfo->blue.length];
return (r << vinfo->red.offset)
+ (g << vinfo->green.offset)
+ (b << vinfo->blue.offset);
}
void fb_init(struct framebuffer *fb)
{
int i;
char *path, *env;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
if ((path = getenv("FRAMEBUFFER")) != NULL) {
if ((fb->fd = open(path, O_RDWR)) < 0) {
fprintf(stderr, "cannot open \"%s\"\n", path);
perror("open");
exit(EXIT_FAILURE);
}
}
else {
if ((fb->fd = open(fb_path, O_RDWR)) < 0) {
fprintf(stderr, "cannot open \"%s\"\n", fb_path);
perror("open");
exit(EXIT_FAILURE);
}
}
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
fprintf(stderr, "ioctl: FBIOGET_FSCREENINFO failed\n");
exit(EXIT_FAILURE);
}
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
fprintf(stderr, "ioctl: FBIOGET_VSCREENINFO failed\n");
exit(EXIT_FAILURE);
}
fb->res.x = vinfo.xres;
fb->res.y = vinfo.yres;
fb->screen_size = finfo.smem_len;
fb->line_length = finfo.line_length;
if ((finfo.visual == FB_VISUAL_TRUECOLOR || finfo.visual == FB_VISUAL_DIRECTCOLOR)
&& (vinfo.bits_per_pixel == 15 || vinfo.bits_per_pixel == 16
|| vinfo.bits_per_pixel == 24 || vinfo.bits_per_pixel == 32)) {
fb->cmap = fb->cmap_org = NULL;
fb->bpp = (vinfo.bits_per_pixel + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
}
else if (finfo.visual == FB_VISUAL_PSEUDOCOLOR
&& vinfo.bits_per_pixel == 8) {
fb->cmap = cmap_create(&vinfo);
fb->cmap_org = cmap_create(&vinfo);
cmap_init(fb, &vinfo);
fb->bpp = 1;
}
else {
/* non packed pixel, mono color, grayscale: not implimented */
fprintf(stderr, "unsupported framebuffer type\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < COLORS; i++) /* init color palette */
fb->color_palette[i] = get_color(&vinfo, i);
if ((fb->fp = (char *) mmap(0, fb->screen_size,
PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0)) == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
/*
if ((fb->buf = (char *) calloc(1, fb->screen_size)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
*/
}
void fb_die(struct framebuffer *fb)
{
cmap_die(fb->cmap);
if (fb->cmap_org) {
ioctl(fb->fd, FBIOPUTCMAP, fb->cmap_org); /* not fatal */
cmap_die(fb->cmap_org);
}
//free(fb->buf);
if ((munmap(fb->fp, fb->screen_size)) < 0) {
perror("munmap");
exit(EXIT_FAILURE);
}
if (close(fb->fd) < 0) {
perror("close");
exit(EXIT_FAILURE);
}
}
void fb_putpixel(struct framebuffer *fb, int x, int y, int color_index)
{
int i;
//fprintf(stderr, "color[%d]: 0x%.6X\n", color_index, fb->color_palette[color_index]);
for (i = 0; i < X_SCALE; i++)
memcpy(fb->fp + (x * X_SCALE + i) * fb->bpp + (y * fb->line_length), &fb->color_palette[color_index], fb->bpp);
}
void fb_drawline(struct framebuffer *fb, int x, int y, int color_index)
{
}
void fb_drawrectangle()
{
}
void fb_fillrectangle()
{
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment