[cairo] Linux framebuffer surface
Andrea Rossignoli
cairo at armbox.net
Wed Jul 28 06:49:21 PDT 2010
Hi,
I successfully crosscompiled cairo 1.9.14 for ARM with DirectFB.
I tested it using qemu-system-arm with success.
I was looking for a linux framebuffer surface on cairo without finding it.
The framebuffer on my armbox required 16bpp.
So I saw that recently it was supported again the CAIRO_FORMAT_RGB16_565
format.
Now I can use cairo with direct access to the linux framebuffer without
installing DirectFB surface.
Below is what I did.
I don't have knowledge of cairo surface internals so the code is only a
quick test.
It works very well, at least using qemu-system-arm.
So my question is, do you plan in future to add support for a "linuxfb"
surface or find it worth adding it ?
Andrea
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <cairo.h>
typedef struct _cairo_linuxfb_device {
int fb_fd;
char *fb_data;
long fb_screensize;
struct fb_var_screeninfo fb_vinfo;
struct fb_fix_screeninfo fb_finfo;
} cairo_linuxfb_device_t;
static
void cairo_linuxfb_surface_destroy(void *device)
{
cairo_linuxfb_device_t *dev = (cairo_linuxfb_device_t *)device;
if (dev == NULL) {
return;
}
munmap(dev->fb_data, dev->fb_screensize);
close(dev->fb_fd);
free(dev);
}
cairo_surface_t *cairo_linuxfb_surface_create(const char *fb_name)
{
cairo_linuxfb_device_t *device;
cairo_surface_t *surface;
if (fb_name == NULL) {
fb_name = "/dev/fb0";
}
device = malloc(sizeof(*device));
// Open the file for reading and writing
device->fb_fd = open(fb_name, O_RDWR);
if (device->fb_fd == -1) {
perror("Error: cannot open framebuffer device");
exit(1);
}
// Get variable screen information
if (ioctl(device->fb_fd, FBIOGET_VSCREENINFO, &device->fb_vinfo) == -1) {
perror("Error reading variable information");
exit(3);
}
// Figure out the size of the screen in bytes
device->fb_screensize = device->fb_vinfo.xres * device->fb_vinfo.yres
* device->fb_vinfo.bits_per_pixel / 8;
// Map the device to memory
device->fb_data = (char *)mmap(0, device->fb_screensize,
PROT_READ | PROT_WRITE, MAP_SHARED,
device->fb_fd, 0);
if ((int)device->fb_data == -1) {
perror("Error: failed to map framebuffer device to memory");
exit(4);
}
// Get fixed screen information
if (ioctl(device->fb_fd, FBIOGET_FSCREENINFO, &device->fb_finfo) == -1) {
perror("Error reading fixed information");
exit(2);
}
surface = cairo_image_surface_create_for_data(device->fb_data,
CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres));
cairo_surface_set_user_data(surface, NULL, device,
&cairo_linuxfb_surface_destroy);
return surface;
}
int main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_linuxfb_surface_create(NULL);
cr = cairo_create(surface);
cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 32.0);
cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
cairo_move_to(cr, 100.0, 100.0);
cairo_show_text(cr, "Hello, CairoGraphics!");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
More information about the cairo
mailing list