如何在 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? 会给你一些正确方向的提示。
比放弃更好的解决方案概述:
在digi-key上搜索输出同步信号的MAX芯片。
安装RS232卡
将同步信号连接到 RS232 上的握手线。
使用适用于任何 Linux.
的标准术语 API
用陶瓷环氧树脂块包裹惊人的产品,售价 500 美元。
一个简短的回答是:当视频缓冲很昂贵时,vsync 曾经在计算机上很流行。如今,随着双缓冲动画的普遍使用,它变得不那么重要了。在 Windowing 系统之前,我曾经从 IBM-PC 上的图形卡访问 vsync,即使现在也不介意获得 VSYNC。使用双缓冲,您仍然有可能在将缓冲区传输到视频内存时进行光栅扫描,因此同步它会很好。但是,使用双缓冲,您将消除直接视频绘图中的许多“闪烁”效果和其他伪影,因为您正在执行线性 blt 而不是单个像素操作。
也有可能(正如之前的海报所暗示的那样)您的两个缓冲区都存在于视频内存中这一事实,以及显示管理器可以仔细管理到屏幕的 blts(合成)的想法都可以渲染效果不存在。
我现在该如何处理?我有一个帧计时器,比如说每秒 30 次,我用它来翻转缓冲区。跟显卡上的实际帧时间不是特别同步。
我需要创建一个 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? 会给你一些正确方向的提示。
比放弃更好的解决方案概述:
在digi-key上搜索输出同步信号的MAX芯片。
安装RS232卡
将同步信号连接到 RS232 上的握手线。
使用适用于任何 Linux.
的标准术语 API
用陶瓷环氧树脂块包裹惊人的产品,售价 500 美元。
一个简短的回答是:当视频缓冲很昂贵时,vsync 曾经在计算机上很流行。如今,随着双缓冲动画的普遍使用,它变得不那么重要了。在 Windowing 系统之前,我曾经从 IBM-PC 上的图形卡访问 vsync,即使现在也不介意获得 VSYNC。使用双缓冲,您仍然有可能在将缓冲区传输到视频内存时进行光栅扫描,因此同步它会很好。但是,使用双缓冲,您将消除直接视频绘图中的许多“闪烁”效果和其他伪影,因为您正在执行线性 blt 而不是单个像素操作。
也有可能(正如之前的海报所暗示的那样)您的两个缓冲区都存在于视频内存中这一事实,以及显示管理器可以仔细管理到屏幕的 blts(合成)的想法都可以渲染效果不存在。
我现在该如何处理?我有一个帧计时器,比如说每秒 30 次,我用它来翻转缓冲区。跟显卡上的实际帧时间不是特别同步。