【问题标题】:Proper double buffering with linux framebuffer使用 linux framebuffer 进行适当的双缓冲
【发布时间】:2018-09-14 08:59:06
【问题描述】:

我想知道如何正确地对帧缓冲区进行双重缓冲以避免撕裂。我已经对这个主题进行了大量研究,但似乎找不到任何东西。

我已经尝试过 FBIO_WAITFORVSYNC。但是根据这个帖子:How to query Vsync phase in Linux 这似乎行不通。

我也尝试过使用 FBIOGET_VSCREENINFO 和 FBIOPAN_DISPLAY 每个线程:Linux framebuffer graphics and VSync。但由于此线程中讨论的错误而失败:invalid argument error when setting yres_virtual in fb_var_screeninfo

该线程建议使用不同的驱动程序 (vesafb) 来解决错误。我设法在我的机器上安装了 uvesafb,但“无效参数”错误并没有消失。

我也尝试按照此人的建议映射更大的缓冲区:http://betteros.org/tut/graphics1.php#doublebuffer 但 mmap 一直返回 -1。

我还尝试实施此处讨论的解决方案:https://pyra-handheld.com/boards/threads/my-frustrating-experiences-with-dev-fb.21062/。然而,线程在没有发布实际解决方案的情况下就死了,我怀疑交换硬件地址的效率(或者甚至可以做到)。

非常感谢您对此主题的任何帮助!

由于一个请求,这里是我希望开始工作的代码:

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!");

这将始终打印“无法设置可变屏幕信息!”由于一些扩展虚拟帧缓冲区大小的问题。

【问题讨论】:

  • 请发minimal reproducible example,以便我们帮助您确定问题的根本原因
  • 我也添加了一些示例代码。
  • 关于:fb0 = open("/dev/fb0", O_RDWR); if(fb0 == 0) error("Could not open framebuffer located in /dev/fb0!"); 函数:open() 在失败时总是返回 perror() 所以系统认为函数失败的文本原因被写入到stderr 0 是一个有效的返回值(尽管,如果stdin 已关闭,代码应该只看到该值
  • 当调用open()失败时,显示错误信息后,代码应该调用exit(),因为没有file descriptor可用于启用对文件的访问。
  • 我很欣赏这些回复......但他们根本没有解决这个问题。我的问题是关于使用帧缓冲区进行双缓冲......而不是 open() 函数

标签: c linux framebuffer double-buffering


【解决方案1】:

我在 linux 上解决帧缓冲区双缓冲问题的方法是使用单独的后台缓冲区,使用 mmap 为相同的屏幕大小分配:

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

(其中screensize = vinfo.yres_virtual * finfo.line_length;

然后将所有更改写入此后台缓冲区,并在所有写入结束后,使用 update() 函数将整个后台缓冲区复制到主帧缓冲区指针位置:

memcpy(fbp, bbp, screensize);

您也可以有一个仅复制给定区域的 updateRect() 函数。这个逻辑在我的 x64 PC gnu/linux 平台上运行良好。

【讨论】:

  • 您能尝试使用这种双缓冲算法播放视频吗?你会看到屏幕确实撕裂了。这种基本的双缓冲算法不足以避免帧缓冲区上的视频等内容导致屏幕撕裂。如果您想摆脱低级图形编程的所有屏幕撕裂,请尝试使用 libdri。
最近更新 更多