Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync video on non-60Hz displays #315

Open
Selicre opened this issue Dec 13, 2021 · 4 comments
Open

Sync video on non-60Hz displays #315

Selicre opened this issue Dec 13, 2021 · 4 comments

Comments

@Selicre
Copy link

Selicre commented Dec 13, 2021

My monitor is set to 120Hz. The emulator assumes that the refresh rate is set to 60Hz and tries to paint a frame every vsync, which makes the game run at >60fps. Audio sync works, but is very jittery.

I would check if sufficient time has elapsed since the last frame, and only then advance the emulation.

@devinacker
Copy link
Owner

Right now, the recommended (and default) setting is to have audio sync enabled and video sync disabled, which limits the emulation speed to something that doesn't depend on your monitor's refresh rate.

At some point, mainline bsnes redid the video/audio sync system to handle vsync in a better/more flexible way, but it needs to be backported at some point.

@Selicre
Copy link
Author

Selicre commented Dec 13, 2021

Unfortunately, only audio sync jitters to the point where just playing the game is uncomfortable. I've managed to fix it by adding this timer to Interface::video_refresh:

  typedef std::chrono::duration<double> fsec;
  auto now = std::chrono::steady_clock::now();
  fsec frameTime = now - lastTimePoint;
  fsec target(0.016);
  while (frameTime < target) {
    // video.refresh() and everything else goes here
    now = std::chrono::steady_clock::now();
    frameTime = now - lastTimePoint;
  }

However, it has an odd bug where the emulator won't close properly if it's running. I'm not sure why that's the case, so I can't really PR that.

@devinacker
Copy link
Owner

That's also going to break the speedup key and emulation speed settings. A proper solution is going to require something better than just jamming a busy loop into GUI code like that.

@carmiker
Copy link

carmiker commented Dec 20, 2021

The solution that works for me is to figure out the screen's refresh rate and divide the core refresh rate by it as well as collect remainders to determine when to skip or run an extra frame. I do it something like this:

int frames_to_run = 0;
int collector = 0;
while (1) {
    frames_to_run = core_refresh / screen_refresh;
    collector += core_refresh % screen_refresh;

    if (collector >= core_refresh) {
        ++frames_to_run;
        collector -= core_refresh;
    }

    for (int i = 0; i < frames_to_to_run; ++i)
        execute_emulation_frame();
}

If you want to do fast forward you can just add to the number of frames you want to run. You will also need to resample audio, which should be happening anyway so that you can use vsync and still have smooth audio. bsnes, in my experience, lends itself well to libsamplerate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants