Linux framebuffer图形和VSync

6
我正在使用C语言编写一款在Linux framebuffer上运行的游戏。目前我有一个100x100的红色正方形,它跟随着鼠标移动,就像一个指针。我已经实现了双缓冲并且它可以正确地工作(正方形不会闪烁)。然而,问题是在水平方向上存在相当大的撕裂。我的意思是,当正方形在X轴上移动时,它好像被水平地分成了两部分,并且其中一部分比另一部分稍微多移动了一点。如果我继续移动它,这个“撕裂”就会从顶部逐渐向下传播到整个正方形。
我认为这是因为硬件在我将双缓冲区拷贝到主缓冲区的那一刻读取了framebuffer。
我尝试使用FBIO_WAITFORVSYNC ioctl来解决这个问题,但没有成功。
请问有什么方法能够在framebuffer上进行VSync吗?由于这是我第一次在基于Linux的操作系统上编写此类代码,所以请详细说明,否则我可能无法理解。
这是我的代码:http://pastebin.com/KJ4iaVEL

你使用什么视频硬件?例如,Linux在Sandy Bridge英特尔图形方面存在撕裂问题。请澄清。 - palopezv
@vorbote 我有一张Nvidia 7800 GTX显卡,抱歉没有提到。在正常使用中没有撕裂现象(例如当我在X中移动窗口时)。 - Belgin
2个回答

6
这不是正确的双缓冲方式。你对于在后台缓存上完成所有绘图是正确的,但之后进行memcpy来传输数据到前台是错误的。屏幕刷新可能会在复制期间发生。
正确的做法是只需要切换指向数据的指针,而不是复制数据本身。使用Linux framebuffer设备,可以通过设置一个比物理屏幕大两倍的“虚拟”屏幕,并使用偏移变量来设置您正在显示的顶部或底部半部分。您可以使用FBIOGET_VSCREENINFOFBIOPUT_VSCREENINFOFBIOPAN_DISPLAY ioctl调用来查询大小并设置偏移量。
此页面简要介绍了这个过程:http://www.ummon.eu/Linux/API/Devices/framebuffer.html 所有相关的数据结构都在linux/fb.h头文件中。

1
链接失效了... :-( - Piranna
2
时光倒流机来帮忙了!https://web.archive.org/web/20180702063450/http://www.ummon.eu/Linux/API/Devices/framebuffer.html - Taywee

5

不幸的是,我用一种艰难的方式学到@Steven Bell的答案并不完全正确。虽然他是对的,在memcpy期间刷新屏幕可能会很容易发生,但正确的解决方案不是创建一个屏幕大小加倍的虚拟帧缓冲区,并像许多线程建议的那样在它们之间进行平移。任何尝试此解决方案的人都将收到一个错误,错误描述在这里: 在fb_var_screeninfo中设置yres_virtual时的无效参数错误

根据这个线程:https://forum.odroid.com/viewtopic.php?f=55&t=8741,真正实现双缓冲帧缓冲区(/dev/fb0),虽然我听说树莓派可能是个例外,但并不完全可能。但这并不意味着在Linux中没有一种使用低级图形的方法来实现双缓冲。

这里的真正解决方案是使用libdrm(/dev/dri/card0)绘制低级别图形到屏幕上。这里有一个非常好的示例:https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-vsync.c,我在解决这个问题时也使用了它。
无论如何,我希望我能为将来要解决这个问题的人节省一些不必要的麻烦。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接