Add variable frame rate (VFR) option for cores.

It is enabled only for N64.
Disabling it for everything else may lead to a much smoother video playback (less stuttering).
This commit is contained in:
Sergey Stepanov 2023-02-10 18:03:50 +03:00
parent beaf862dec
commit d27d819821
No known key found for this signature in database
GPG key ID: A56B4929BAA8556B
5 changed files with 40 additions and 19 deletions

View file

@ -174,6 +174,13 @@ emulator:
# - isGlAllowed (bool)
# - usesLibCo (bool)
# - hasMultitap (bool)
# - vfr (bool)
# (experimental)
# Enable variable frame rate only for cores that can't produce a constant frame rate.
# By default, we assume that cores output frames at a constant rate which equals
# their tick rate (1/system FPS), but OpenGL cores like N64 may have significant
# frame rendering time inconsistencies. In general, VFR for CFR cores leads to
# noticeable video stutter (with the current frame rendering time calculations).
list:
gba:
lib: mgba_libretro
@ -203,6 +210,7 @@ emulator:
roms: [ "n64", "v64", "z64" ]
isGlAllowed: true
usesLibCo: true
vfr: true
encoder:
audio:

View file

@ -59,19 +59,18 @@ type LibretroRepoConfig struct {
}
type LibretroCoreConfig struct {
Lib string
Config string
Roms []string
Folder string
Width int
Height int
IsGlAllowed bool
UsesLibCo bool
HasMultitap bool
AltRepo bool
// hack: keep it here to pass it down the emulator
AutoGlContext bool
AltRepo bool
AutoGlContext bool // hack: keep it here to pass it down the emulator
Config string
Folder string
HasMultitap bool
Height int
IsGlAllowed bool
Lib string
Roms []string
UsesLibCo bool
VFR bool
Width int
}
type CoreInfo struct {

View file

@ -54,6 +54,7 @@ type Metadata struct {
UsesLibCo bool
AutoGlContext bool
HasMultitap bool
HasVFR bool
}
type (

View file

@ -108,12 +108,13 @@ func (f *Frontend) LoadMetadata(emu string) {
config := f.conf.GetLibretroCoreConfig(emu)
f.mu.Lock()
coreLoad(emulator.Metadata{
LibPath: config.Lib,
ConfigPath: config.Config,
IsGlAllowed: config.IsGlAllowed,
UsesLibCo: config.UsesLibCo,
HasMultitap: config.HasMultitap,
AutoGlContext: config.AutoGlContext,
ConfigPath: config.Config,
HasMultitap: config.HasMultitap,
HasVFR: config.VFR,
IsGlAllowed: config.IsGlAllowed,
LibPath: config.Lib,
UsesLibCo: config.UsesLibCo,
})
f.mu.Unlock()
}

View file

@ -69,6 +69,8 @@ var (
libretroLogger = logger.Default()
sdlCtx *graphics.SDL
usesLibCo bool
hasVFR bool
tickTime int64
cSaveDirectory *C.char
cSystemDirectory *C.char
cUserName *C.char
@ -113,7 +115,11 @@ func coreVideoRefresh(data unsafe.Pointer, width, height uint, packed uint) {
// this is useful only for cores with variable framerate, for the fixed framerate cores this adds stutter
// !to find docs on Libretro refresh sync and frame times
t := time.Now().UnixNano()
dt := t - lastFrameTime
dt := tickTime
// override frame rendering with dynamic frame times
if hasVFR {
dt = t - lastFrameTime
}
lastFrameTime = t
// some cores can return nothing
@ -414,6 +420,7 @@ func coreLoad(meta emulator.Metadata) {
nano.v.isGl = meta.IsGlAllowed
usesLibCo = meta.UsesLibCo
nano.v.autoGlContext = meta.AutoGlContext
hasVFR = meta.HasVFR
coreConfig, err = ReadProperties(meta.ConfigPath)
if err != nil {
libretroLogger.Warn().Err(err).Msg("config scan has been failed")
@ -510,6 +517,11 @@ func LoadGame(path string) error {
nano.sysAvInfo.timing.fps, nano.sysAvInfo.geometry.aspect_ratio, nano.sysAvInfo.timing.sample_rate,
)
tickTime = int64(time.Second / time.Duration(nano.sysAvInfo.timing.fps))
if hasVFR {
libretroLogger.Info().Msgf("variable framerate (VFR) is enabled")
}
if nano.v.isGl {
// flip Y coordinates of OpenGL
setRotation(uint(image.Flip180))