FBIO_WAITFORVSYNC succeeds, but does not wait

I’m on the 580.95.05 driver with open kernel modules, with a gtx 1650.

I am using the framebuffer provided by the nvidia modesetting driver:

options nvidia-drm fbdev=1 modeset=1

The ioctl FBIO_WAITFORVSYNC succeeds, but doesn’t wait for vsync.

$ cat fb_rate.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

#define PICOS2HZ(a) (1000000000000UL/(a))

int main(int ac, char **av)
{
    int fd = open(ac > 1 ? av[1] : "/dev/fb0", O_RDWR);
    if (fd < 0) {
        perror("open");
    }
    struct fb_var_screeninfo info = {0};
    int ret = ioctl(fd, FBIOGET_VSCREENINFO, &info);
    if (ret < 0) {
        perror("FBIOGET_VSCREENINFO");
    }
    long scanline = info.left_margin + info.xres * info.pixclock + info.right_margin + info.hsync_len;
    long vblank = info.upper_margin + info.yres * scanline + info.lower_margin + info.vsync_len;

    long freq = vblank ? PICOS2HZ(vblank) : -1;
    printf("freq: %ld\n", freq);

    long real_freq = 0;
    struct timespec tv1 = {0};
    struct timespec tv2 = {0};
    long zero_arg = 0;
    ret = ioctl(fd, FBIO_WAITFORVSYNC, &info);
    if (ret < 0) {
        perror("FBIO_WAITFORVSYNC");
    }
    ret = clock_gettime(CLOCK_REALTIME, &tv1);
    if (ret < 0) {
        perror("clock_gettime");
    }

    ret = ioctl(fd, FBIO_WAITFORVSYNC, &info);
    if (ret < 0) {
        perror("FBIO_WAITFORVSYNC");
    }
    ret = clock_gettime(CLOCK_REALTIME, &tv2);
    if (ret < 0) {
        perror("clock_gettime");
    }

    real_freq = (long)(tv2.tv_sec - tv1.tv_sec) * 1000000000L + (tv2.tv_nsec - tv1.tv_nsec);
    real_freq = 1000000000L / real_freq;
    printf("real_freq: %ld\n", real_freq);
}
$ gcc fb_rate.c -o fb_rate && ./fb_rate /dev/fb1
freq: -1
real_freq: 5263157

For comparison with the intel driver:

$ gcc fb_rate.c -o fb_rate && ./fb_rate /dev/fb0
freq: -1
real_freq: 144

Hi there @stefan11111, welcome to the NVIDIA developer forums.

fbdev is legacy, so it might very well be that support for that is limited, even though it should still work.

The “modern” path is to use DRM: DRM_IOCTL_WAIT_VBLANK via libdrm, maybe that helps in your case?