Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to query Vsync phase in Linux

Tags:

c++

linux

vsync

I need to create a C++ function that will return the number of seconds until the next Vsync interval as a floating point value.

Why?

I am creating programs that display rectangles that follow the mouse cursor. Ostensibly OpenGL provides a vsync mechanism in the glXSwapBuffers function, but I have found this to be unreliable. With some card drivers you get vsync; with others you don't. On some you get vsync but you also get an extra 2-frames of latency.

But this is not a bug in OpenGL. The spec is intentionally vague: "The contents of the back buffer then become undefined. The update typically takes place during the vertical retrace of the monitor, rather than immediately after glXSwapBuffers is called." The key word being "typically"... basically glXSwapBuffers doesn't promise squat w.r.t. vsync. Go figure.

In my current attempt to solve this basic problem, I currently guess an initial vsync time and then afterwords assume the phase equals elapsed time MOD 1/(59.85Hz) which seems to sync up with my current monitor. But this doesn't work so well because I don't actually know the initial phase. So I get one tear. At least it doesn't move around. But what I really need is to just measure the current vsync phase somehow.

No, I don't want to rely on some OpenGL call to do a vsync for me. Because of the vagueness in the spec, this gives the OpenGL implementation to add as much latency as it pleases.

No, I don't want to rely on some SGI extension or some other thing that has to be installed to make it work. This is graphics 101. Vsync. Just need a way to query its state. SOME builtin, always-installed API must have this.

Maybe I can create a secondary thread that waits for Vsync somehow, and records the time when this happens? But be aware that the following sequence:

#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));
}

does NOT work in Debian. Result:

% ./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

There must be some way to just read the phase from a device, or some other OpenGL call. OpenGL is THE THING for graphics. Vsync is graphics 101.

Please help.

like image 497
personal_cloud Avatar asked Sep 02 '16 19:09

personal_cloud


2 Answers

When you search for FBIO_WAITFORVSYNC in the Linux kernel sources, you can see, that it is implemented only for a few graphics cards, but not for all.

So, if you happen to have one of the many other cards, you get "Inappropriate ioctl for device", which just means not implemented for this graphics card driver.

Maybe How to wait for VSYNC in Xlib app? gives you some hint into the right direction.

like image 55
Olaf Dietsche Avatar answered Nov 06 '22 03:11

Olaf Dietsche


Outline of a solution that is better than giving up:

  1. Search on digi-key for a MAX chip that outputs the sync signal.

  2. Install RS232 card.

  3. Connect the sync signal to a handshake line on the RS232.

  4. Use standard termios API that will work on any Linux.

  5. Encase amazing product in ceramic epoxy block and sell for $500.

like image 28
personal_cloud Avatar answered Nov 06 '22 02:11

personal_cloud