Proper double buffering with linux framebuffer
Asked Answered
L

1

8

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.

Lacerta answered 4/4, 2018 at 17:33 Comment(6)
Please post a minimal reproducible example so we can help you determine the root cause of the problemStereopticon
I have added some sample code as well.Lacerta
regarding: fb0 = open("/dev/fb0", O_RDWR); if(fb0 == 0) error("Could not open framebuffer located in /dev/fb0!"); The function: open() always returns a <0 value when it fails (then the code should be calling perror() so the text reason the system thinks the function failed is written to stderr 0 is a valid return value (although, the code should only see that value if stdin has been closedStereopticon
when the call to open() fails, after displaying the error message, the code should be calling exit() as there is no file descriptor available to enable access to the file.Stereopticon
I appreciate the replies... but they do not address the question at all. My question is about double buffering with the framebuffer... not the open() functionLacerta
We are, in the comments, either asking for clarification or pointing out problems that are NOT the problem ask about.Stereopticon
U
-1

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.

Urana answered 12/8, 2018 at 16:9 Comment(1)
Could you please try playing a video using this double buffering algorithm? You'll see that the screen does indeed tear. This basic double buffering algorithm is not good enough to avoid screen tearing with things like video on the framebuffer. Please try libdri if you want to get rid of all screen tearing for low level graphics programming.Lacerta

© 2022 - 2024 — McMap. All rights reserved.