0
\$\begingroup\$

What is the preferred way of synchronizing with monitor refreshes, when vsync is not an option? We enable vsync, however, some users disable it in driver settings, and those override app preferences. We need reliable predictable frame lengths to simulate the world correctly, do some visual effects, and synchronize audio (more precisely, we need to estimate how long a frame is going to be on screen, and when it will be on screen).

Is there any way to force drivers to enable vsync despite what the user set in the driver? Or to wait for a swap manually? We have issues with manual sleeping when our frame boundaries line up closely to buffer swaps. It causes occasional missed frames, and up to 1 extra frame of input latency.

We mainly use OpenGL, but Direct3D advice is also appreciated.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ It feels like you want to solve problems with your physics engine, when the framerate changes. It's usually better to put that into its own thread. \$\endgroup\$
    – Bálint
    Jul 23 '19 at 12:25
  • \$\begingroup\$ @Bálint No, we need to know when images are going to show up on screen to synchronize audio to that time, and to do visual effects like motion blur properly. Not related to gameplay. It's also useful just to prevent wasting CPU time drawing frames that will never be shown (no need to run at 100 FPS on a 60 Hz monitor, it just causes jitter and wastes time) \$\endgroup\$
    – Kalinovcic
    Jul 23 '19 at 12:30
  • \$\begingroup\$ I would also like to point out that synchronizing audio to your video is largely affected by the user's monitor/TV as well, much more than the error introduced by not using Vsync. If you are trying to time the audio so that it plays exactly in sync with effects on the screen you may need to prompt the user to do a calibration for their screen. The game Rock Band has a good example of how that calibration is done, and it was absolutely necessary for that game on TVs. \$\endgroup\$
    – Romen
    Aug 22 '19 at 21:52
1
\$\begingroup\$

In OpenGL you can control the swap interval of your application, which will limit the frame swap to the refresh rate of the monitor (v-sync). However, the user can override this by disallowing applications to control vertical sync within the Nvidia preferences application. In such as case, you have to make a choice:

  1. live with the issue, and inform your users that to fix any A/V de-sync they have to allow the application to control v-sync.

  2. Cap the refresh rate in your software: have a timer event, triggered every 60th of a second (16.667ms), which will trigger a redraw. Additionally/Alternatively, after every frame draw call glFinish() which will force every queued API call to be executed, and will prevent further queuing until complete. This means that more CPU/GPU sync is performed, thus reducing frame draws, however, on it's own is limited only by hardware performance, and thus, is unpredictable as a frame limiter.

Generally, if you cap your frame draws in the same way you would limit solver cycles for your physics engine, then you should get a controlled frame-rate unaffected by vertical sync/driver settings.

example:

void engine::run()
{
    float dt = 0f;
    time_t last = 0;
    time_t now = 0;
    float gfx_timer = 1.0f/60;
    float gfx_accumulator = 0f;
    while (m_running == true)
    {
         now = time::now();
         dt = (now - last)/(float)CLOCKS_PER_SECOND;
         updateGame(dt); // update gamestate
         if (dt >= gfx_timer) // ensures the renderer will only call once per 16.667ms at most
         {
             gfx_accumulator = 0.0f;
             m_renderer.renderScene();
         {
         else
             gfx_accumulator += dt;
         last = now;
    }
}

In general frame capping is a good idea, to not melt people's gpus, but be warned, gamers with an expensive graphics card will not thank you for capping them at 60fps.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .