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.)
(Below way works on Android 2.3 ~ 4.1 emulator by turning off 'Use Host GPU' option at AVD Manager.)
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.
'Domain > Linux' 카테고리의 다른 글
| [Ubuntu] visual effect doens't work with Nvidia driver... (0) | 2011.01.19 |
|---|---|
| [Linux] Writing input event directly. (0) | 2010.11.29 |
| [Ubuntu] alacarte를 사용하지 않고 GNOME desktop menu수정하기. (0) | 2010.11.10 |
| [Linux][Prog] Understanding Standard IO (0) | 2010.11.03 |
| [Linux] fork in multi-threaded program. (0) | 2010.08.16 |