From 685f16cc39c8d1ae577a774058e4688e1d3ed68a Mon Sep 17 00:00:00 2001 From: Sergey Stepanov Date: Thu, 21 Mar 2024 16:03:52 +0300 Subject: [PATCH] Allow duplicate frames Some cores for performance reasons may return duplicate frames (i.e. previous frames) instead of rendering them again. --- pkg/config/config.yaml | 2 ++ pkg/config/emulator.go | 1 + pkg/worker/caged/libretro/frontend.go | 11 ++++++++++- pkg/worker/caged/libretro/nanoarch/nanoarch.go | 13 ++++++++----- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index 57cb39de9..60fc6f539 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -135,6 +135,8 @@ emulator: # Sets a limiter function for some spammy core callbacks. # 0 - disabled, otherwise -- time in milliseconds for ignoring repeated calls except the last. debounceMs: 0 + # Allow duplicate frames + dup: true # Libretro cores logging level: DEBUG = 0, INFO, WARN, ERROR, DUMMY = INT_MAX logLevel: 1 cores: diff --git a/pkg/config/emulator.go b/pkg/config/emulator.go index 49bf6713e..24993cbed 100644 --- a/pkg/config/emulator.go +++ b/pkg/config/emulator.go @@ -28,6 +28,7 @@ type LibretroConfig struct { List map[string]LibretroCoreConfig } DebounceMs int + Dup bool SaveCompression bool LogLevel int } diff --git a/pkg/worker/caged/libretro/frontend.go b/pkg/worker/caged/libretro/frontend.go index 1b6638e33..935a24f3c 100644 --- a/pkg/worker/caged/libretro/frontend.go +++ b/pkg/worker/caged/libretro/frontend.go @@ -93,6 +93,7 @@ var ( noData = func([]byte) {} noVideo = func(app.Video) {} videoPool sync.Pool + lastFrame *app.Video ) // NewFrontend implements Emulator interface for a Libretro frontend. @@ -156,6 +157,7 @@ func (f *Frontend) LoadCore(emu string) { conf := f.conf.GetLibretroCoreConfig(emu) meta := nanoarch.Metadata{ AutoGlContext: conf.AutoGlContext, + FrameDup: f.conf.Libretro.Dup, Hacks: conf.Hacks, HasVFR: conf.VFR, Hid: conf.Hid, @@ -190,7 +192,6 @@ func (f *Frontend) handleAudio(audio unsafe.Pointer, samples int) { } func (f *Frontend) handleVideo(data []byte, delta int32, fi nanoarch.FrameInfo) { - // !to merge both pools fr, _ := videoPool.Get().(*app.Video) if fr == nil { fr = new(app.Video) @@ -200,10 +201,17 @@ func (f *Frontend) handleVideo(data []byte, delta int32, fi nanoarch.FrameInfo) fr.Frame.H = int(fi.H) fr.Frame.Stride = int(fi.Stride) fr.Duration = delta + + lastFrame = fr f.onVideo(*fr) + videoPool.Put(fr) } +func (f *Frontend) handleDup() { + f.onVideo(*lastFrame) +} + func (f *Frontend) Shutdown() { f.mu.Lock() f.nano.Shutdown() @@ -224,6 +232,7 @@ func (f *Frontend) linkNano(nano *nanoarch.Nanoarch) { f.nano.OnDpad = f.input.isDpadTouched f.nano.OnVideo = f.handleVideo f.nano.OnAudio = f.handleAudio + f.nano.OnDup = f.handleDup } func (f *Frontend) SetVideoChangeCb(fn func()) { diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.go b/pkg/worker/caged/libretro/nanoarch/nanoarch.go index 95cd24a6f..94ff0b0d7 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.go +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.go @@ -78,6 +78,7 @@ type Handlers struct { OnKeyPress func(port uint, key int) int OnAudio func(ptr unsafe.Pointer, frames int) OnVideo func(data []byte, delta int32, fi FrameInfo) + OnDup func() OnSystemAvInfo func() } @@ -88,6 +89,7 @@ type FrameInfo struct { } type Metadata struct { + FrameDup bool LibPath string // the full path to some emulator lib IsGlAllowed bool UsesLibCo bool @@ -127,6 +129,7 @@ var Nan0 = Nanoarch{ OnKeyPress: func(uint, int) int { return 0 }, OnAudio: func(unsafe.Pointer, int) {}, OnVideo: func([]byte, int32, FrameInfo) {}, + OnDup: func() {}, }, } @@ -559,9 +562,9 @@ func coreVideoRefresh(data unsafe.Pointer, width, height uint, packed uint) { } Nan0.LastFrameTime = t - // some cores can return nothing - // !to add duplicate if can dup + // when the core returns a duplicate frame if data == nil { + Nan0.Handlers.OnDup() return } @@ -694,9 +697,9 @@ func coreEnvironment(cmd C.unsigned, data unsafe.Pointer) C.bool { setRotation((*(*uint)(data) % 4) * 90) return true case C.RETRO_ENVIRONMENT_GET_CAN_DUPE: - // !to implement frame dup (nil) some time later - *(*C.bool)(data) = C.bool(false) - return false + dup := C.bool(Nan0.meta.FrameDup) + *(*C.bool)(data) = dup + return dup case C.RETRO_ENVIRONMENT_GET_USERNAME: *(**C.char)(data) = Nan0.cUserName return true