简体   繁体   中英

Proper double buffering with linux framebuffer

I am wondering how to properly double buffer the framebuffer to avoid tearing. I've done lots of research on this topic and I can't seem to find anything.

I've tried FBIO_WAITFORVSYNC. But per this thread: How to query Vsync phase in Linux it seems that this won't work.

I've also tried using FBIOGET_VSCREENINFO and FBIOPAN_DISPLAY per this thread: Linux framebuffer graphics and VSync . But it failed due to an error discussed in this thread: invalid argument error when setting yres_virtual in fb_var_screeninfo

That thread suggested using a different driver (vesafb) to resolve the error. I managed to install uvesafb on my machine but the "Invalid Argument" error didn't go away.

I've also tried just mmaping a larger buffer per this person's suggestion: http://betteros.org/tut/graphics1.php#doublebuffer but mmap keeps returning -1.

I've also tried to implement the solution discussed here: https://pyra-handheld.com/boards/threads/my-frustrating-experiences-with-dev-fb.21062/ . However the thread died without the actual solution being posted and I am doubtful of the efficiency of swapping hardware addresses (or if it can even be done).

Any help would be so greatly appreciated on this topic!

Due to a request here is the code I would ideally like to get to work:

fb0 = open("/dev/fb0", O_RDWR);
    if(fb0 == 0)
        error("Could not open framebuffer located in /dev/fb0!");

    if (ioctl(fb0, FBIOGET_FSCREENINFO, &screeninfo_fixed) == -1)
        error("Could not retrive fixed screen info!");

    if (ioctl(fb0, FBIOGET_VSCREENINFO, &screeninfo_var) == -1)
        error("Could not retrive variable screen info!");

    screeninfo_var.xres_virtual = screeninfo_var.xres;
    screeninfo_var.yres_virtual = screeninfo_var.yres * 2;
    screeninfo_var.width = screeninfo_var.xres;
    screeninfo_var.height = screeninfo_var.yres;
    screeninfo_var.xoffset = 0;
    screeninfo_var.yoffset = 0;

    if (ioctl(fb0, FBIOPUT_VSCREENINFO, &screeninfo_var) == -1)
        error("Could not set variable screen info!");

This will always print "Could not set variable screen info!" due to some issue extending the virtual framebuffer size.

The way I have solved the double buffering issue for framebuffer on linux is by using a separate back buffer, allocated using mmap for the same screensize:

bbp = mmap(0, screensize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

(where screensize = vinfo.yres_virtual * finfo.line_length; )

Then write all changes to this back buffer, and after all writes are over, copy the entire back buffer to the main framebuffer pointer location using say, an update() function:

memcpy(fbp, bbp, screensize);

You could, also have an updateRect() function that copies only a given area. This logic is working fine on my x64 PC gnu/linux platform.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM