如何在 Linux 中查询 Vsync 相位

How to query Vsync phase in Linux

我需要创建一个 C++ 函数,它将 return 到下一个 Vsync 间隔的秒数作为浮点值。

为什么?

我正在创建显示跟随鼠标光标的矩形的程序。 表面上 OpenGL 在 glXSwapBuffers 函数中提供了一个 vsync 机制,但我发现这是不可靠的。使用某些卡驱动程序,您可以获得 vsync;与其他人你没有。在某些设备上,您可以获得 vsync,但您还会获得额外的 2 帧延迟。

但这不是 OpenGL 中的错误。规范故意含糊不清: “然后后台缓冲区的内容变得不确定。 更新通常发生在垂直回扫期间 显示器, 而不是在调用 glXSwapBuffers 之后立即执行。” 关键字是 "typically"... 基本上 glXSwapBuffers 不保证下蹲 w.r.t。垂直同步。去图吧。

在我目前解决这个基本问题的尝试中,我目前猜测初始 vsync 时间然后后记假设相位等于经过时间 MOD 1/(59.85Hz) 这似乎与我当前的同步监视器。但这并不是很好,因为我实际上并不知道初始阶段。所以我流下了眼泪。至少它不会四处移动。但我真正需要的只是以某种方式测量当前的垂直同步相位。

不,我不想依赖某些 OpenGL 调用来为我执行垂直同步。由于规范中的模糊性,这让 OpenGL 实现可以根据需要添加尽可能多的延迟。

不,我不想依赖某些 SGI 扩展或其他必须安装才能使其工作的东西。这是图形 101。Vsync。只需要一种查询其状态的方法。一些内置的,总是安装的 API 必须有这个。

也许我可以创建一个辅助线程以某种方式等待 Vsync,并记录发生这种情况的时间?但请注意以下顺序:

#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/fb.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

int main()
{
  int fb = open("/dev/fb0", O_RDWR);
  assert(fb != -1);
  int zero = 0;
  if (ioctl(fb, FBIO_WAITFORVSYNC, &zero) == -1)
    printf("fb ioctl failed: %s\n", strerror(errno));
}

在 Debian 中不起作用。结果:

% ./a.out
fb ioctl failed: Inappropriate ioctl for device
% ls -l /dev/fb0
crw-rw-rw- 1 root video 29, 0 Sep  1 20:52 /dev/fb0

一定有某种方法可以从设备或其他设备读取相位 OpenGL 调用。 OpenGL 是图形的东西。 Vsync 是图形 101.

请帮忙。

This is graphics 101. Vsync. Just need a way to query its state. SOME builtin, always-installed API must have this.

不,"must"没有办法做到这一点。至少,没有任何东西会暴露给。当然不是任何跨平台的东西。

屏幕毕竟不是你的。系统拥有屏幕;您只是租用其中的一部分,因此受系统的支配。系统处理vsync;你的工作是填写显示在那里的图像。

考虑一下 Vulkan,它与现在您将要获得的级别一样低,实际上 图形驱动程序。它的 WSI 接口明确设计为 避免 允许您执行 "wait until the next vsync".

之类的事情

它的演示系统确实提供了多种模式,但唯一需要实现支持的模式是 FIFO:严格的垂直同步,但不撕裂。当然,Vulkan 的 WSI 至少允许您选择所需的图像缓冲量。但是,如果您仅使用带双缓冲区的 FIFO,并且提供该图像的时间较晚,那么您的交换将在下一个垂直同步之前不可见。

当您在 Linux 内核源代码中搜索 FBIO_WAITFORVSYNC 时,您会看到它只针对少数显卡实现,而不是针对所有显卡。

因此,如果您碰巧拥有众多其他显卡中的一种,您会得到 "Inappropriate ioctl for device",这只是意味着未针对此显卡驱动程序实现。

也许 How to wait for VSYNC in Xlib app? 会给你一些正确方向的提示。

比放弃更好的解决方案概述:

  1. 在digi-key上搜索输出同步信号的MAX芯片。

  2. 安装RS232卡

  3. 将同步信号连接到 RS232 上的握手线。

  4. 使用适用于任何 Linux.

  5. 的标准术语 API
  6. 用陶瓷环氧树脂块包裹惊人的产品,售价 500 美元。

一个简短的回答是:当视频缓冲很昂贵时,vsync 曾经在计算机上很流行。如今,随着双缓冲动画的普遍使用,它变得不那么重要了。在 Windowing 系统之前,我曾经从 IBM-PC 上的图形卡访问 vsync,即使现在也不介意获得 VSYNC。使用双缓冲,您仍然有可能在将缓冲区传输到视频内存时进行光栅扫描,因此同步它会很好。但是,使用双缓冲,您将消除直接视频绘图中的许多“闪烁”效果和其他伪影,因为您正在执行线性 blt 而不是单个像素操作。

也有可能(正如之前的海报所暗示的那样)您的两个缓冲区都存在于视频内存中这一事实,以及显示管理器可以仔细管理到屏幕的 blts(合成)的想法都可以渲染效果不存在。

我现在该如何处理?我有一个帧计时器,比如说每秒 30 次,我用它来翻转缓冲区。跟显卡上的实际帧时间不是特别同步。