[Linux][Android] Access framebuffer directly – how to

Sometimes, we want to access framebuffer directly.
Here is template and simple description to do this (on Android  as an example.)
(Note: This is just template. Some modification may be required according to driver.)

Things used in this example.
(Refer kernel source code for details - comments in code.)
linux/fb.h
    - struct fb_var_screeninfo
        xres, yres, xres_virtual, yres_virtual, xoffset, yoffset, bits_per_pixel
    - struct fb_fix_screeninfo
        smem_len
    - FBIOGET_FSCREENINFO, FBIOGET_VSCREENINFO, FBIOPUT_VSCREENINFO
    - FB_ACTIVATE_NOW, FB_ACTIVATE_FORCE
See fbmem.c as your starting point of source analysis.

...
int                      fd;
struct fb_var_screeninfo vi;
struct fb_fix_screeninfo fi;
void*                    bits;
int                      bpp;    /* byte per pixel */
int                      stride; /* size of stride in pixel */

...
/* Open framebuffer */
if(0 > (fd = open("/dev/graphics/fb0", O_RDWR)) {
    printf("Fail to open fb\n");
    return -1;
}

/* Get fixed information */
if(0 > ioctl(fd, FBIOGET_FSCREENINFO, &fi)) {
    printf("Fail to get fixed info\n")
    return -1;
}

/* Get variable information */
if(0 > ioctl(fd, FBIOGET_VSCREENINFO, &vi)) {
    printf("Failed to get variable info\n");
    return -1;
}

/* Get raw bits buffer */
if(MAP_FAILED == (bits = mmap(0, fi.smem_len,
                              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))) {
    printf("Failed to mmap fb\n");
    return -1;
}

/* Calculate useful information */
bpp = vi.bits_per_pixel >> 3;
stride = fi.line_length / bpp;

...
/* Getting raw-image snapshot of current framebuffer */
void* curbits; /* current framebuffer raw data */
curbits = (unsigned char*)bits + (vi.xoffset + vi.yoffset*vi.xres_virtual)*bpp;
memcpy(raw_image_buffer, curbits, vi.yres*stride*bpp);

...
/* Modifying directly */
do_something(curbits...); /* change buffer directly... */

/* Refresh buffer manually */
vi.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
if(0 > ioctl(fd, FBIOPUT_VSCREENINFO, &vi)) {
    printf("Failed to refresh\n");
    return -1;
}

Linux usually use ‘double buffer’.
For this, usually,

vi.yres_virtual == vi.yres * 2
vi.yoffset == 0 or vi.yres
(0 for 1st buffer, vi.yres for 2nd buffer)

But, it’s totally dependent on driver. So, to get portability, we should not assume those.

Advertisements

4 thoughts on “[Linux][Android] Access framebuffer directly – how to

    • As mentioned, it depends on device driver.
      But, I think this sample will work on goldfish – Android emulator device – too.

  1. Hi,

    I am trying to draw an image on the framebuffer with the alpha channel set. The phone I am using supports argb format and the framebuffer device driver also reports 32 bits per pixel. I am unable to see any effect of the transparency channel. This is what I do:

    bits = mmap(…)
    location = compute the location on screen
    *(bits + location) = 34; // Blue
    *(bits + location + 1) = 100; // Green
    *(bits + location + 2) = 100; // Red
    *(bits + location + 3) = 200; // Alpha

    Even though I set the alpha channel to 200, I do not see a transparent image on the screen. Is there something I am missing?

    Thanks and Regards,
    Abhinav

    • Hi.
      I am quite sure that alpha value is *NOT* effective at framebuffer and it’s trivial.
      Because, most case, alpha value is used at “composition step” and framebuffer is final destination of composition step.
      So, in most case, alpha value at framebuffer is NOT used and effective.
      If you want alpha effect, I think you should composite target value manually.
      For example, “(old Red) * 0.5 + (new Red) * 0.5” => write to framebuffer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s