设置fb_var_screeninfo中yres_virtual时出现无效参数错误

5

我正在尝试制作一个可以直接写入Linux framebuffer /dev/fb0的应用程序。为了实现双缓冲,我试图将虚拟屏幕的大小设置为屏幕大小的两倍。以下是我编写的程序:

struct fb_var_screeninfo screeninfo_var;
struct fb_fix_screeninfo screeninfo_fixed;
unsigned int* screenbuffer;

void gfx_init()
{
    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!");

    info("Detected monitor of %ix%i pixels using %i bit colors.",screeninfo_var.xres, screeninfo_var.yres, screeninfo_var.bits_per_pixel);

    screenbuffersize = screeninfo_var.xres_virtual * screeninfo_var.yres_virtual * screeninfo_var.bits_per_pixel/8;
    screenbuffer = (unsigned int *)mmap(0, screenbuffersize, PROT_READ | PROT_WRITE, MAP_SHARED, fb0, 0);
    if( (long)screenbuffer == 0 || (long)screenbuffer == -1 )
        error("Failed to map framebuffer to device memory!");
}

该程序在执行ioctl(fb0, FBIOPUT_VSCREENINFO, &screeninfo_var)时报告无效参数错误。当删除screeninfo_var.yres_virtual = screeninfo_var.yres * 2;这一行时,程序可以正常运行(但没有双缓冲功能)。
有人能看出我做错了什么吗?

2
你解决这个问题了吗?我目前遇到了类似的问题。 - Andreas Grapentin
2个回答

1
为了避免以后的麻烦,在Linux上使用低级图形(例如/dev/fb0)可以正确地进行双缓冲。然而,根据此线程:https://forum.odroid.com/viewtopic.php?f=55&t=8741,通过创建原始大小两倍的虚拟帧缓冲区来实现真正的双缓冲是不可能的(我已经读到树莓派可能是一个例外,因为它由不同的驱动程序支持)。
在Linux上使用低级图形进行双缓冲的正确方法是通过libdrm(或/dev/dri/card0)。这里有一个非常好的例子,我自己也跟着做了:https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-vsync.c。将我的/dev/fb0代码转换为/dev/dri/card0代码并不难。
无论如何,我希望我能帮助到未来可能遇到这个问题的人。

谢谢提供链接,但是在我的RTX3070上出现了“drm设备'/dev/dri/card0'不支持愚笨缓冲区”的错误。但是在我的Intel® UHD Graphics 770上可以正常工作。 - Bram

0

这是一个常见的问题,它是由于视频驱动程序的限制引起的。例如,Intel的810芯片组只允许640x480分辨率,而Broadcom的限制宽度不超过1200(http://www.raspberrypi.org/phpBB3/viewtopic.php?f=66&t=29968)。

除非更改驱动程序或显卡本身(如果可能),否则您无法做太多事情。

编辑:如果您在PC上,请尝试使用vesafb,而不是Intel的驱动程序。

这里有一个提示:http://www.mail-archive.com/debian-russian@lists.debian.org/msg27725.html


3
似乎不合逻辑,一款Nvidia Quadro 200M应该能够处理更大的帧缓冲区。我使用的屏幕分辨率是1600x900,但即使将虚拟屏幕大小设置为1600x901也会出现错误。 是否有办法查询最大虚拟屏幕尺寸? - STS

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