mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-22 01:29:14 +00:00
Switch to the more precise runtime.nanotime for frame timing
This commit is contained in:
parent
f2cb7ebc7a
commit
68ac6afab4
2 changed files with 25 additions and 15 deletions
9
pkg/os/nanotime.go
Normal file
9
pkg/os/nanotime.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package os
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
//go:linkname nanotime runtime.nanotime
|
||||
func nanotime() int64
|
||||
|
||||
// Nanotime returns a monotonic timestamp in nanoseconds.
|
||||
func Nanotime() int64 { return nanotime() }
|
||||
|
|
@ -320,17 +320,17 @@ func (f *Frontend) Start() {
|
|||
|
||||
// The main loop of Libretro
|
||||
|
||||
targetFrameTime := time.Duration(float64(time.Second) / f.nano.VideoFramerate())
|
||||
targetFrameTimeNs := int64(float64(time.Second) / f.nano.VideoFramerate())
|
||||
|
||||
// stop sleeping and start spinning in the remaining 1ms
|
||||
const spinThreshold = 1 * time.Millisecond
|
||||
const spinThresholdNs = int64(1 * time.Millisecond)
|
||||
|
||||
// how many frames will be considered not normal
|
||||
const lateFramesThreshold = 3
|
||||
|
||||
batch := max(f.SpinBatch, 1)
|
||||
|
||||
lastFrameStart := time.Now()
|
||||
lastFrameStart := os.Nanotime()
|
||||
|
||||
for {
|
||||
select {
|
||||
|
|
@ -339,27 +339,28 @@ func (f *Frontend) Start() {
|
|||
default:
|
||||
f.Tick()
|
||||
|
||||
elapsed := time.Since(lastFrameStart)
|
||||
sleepTime := targetFrameTime - elapsed
|
||||
deadline := lastFrameStart.Add(targetFrameTime)
|
||||
now := os.Nanotime()
|
||||
elapsed := now - lastFrameStart
|
||||
sleepTimeNs := targetFrameTimeNs - elapsed
|
||||
deadline := lastFrameStart + targetFrameTimeNs
|
||||
|
||||
if sleepTime > 0 {
|
||||
if sleepTimeNs > 0 {
|
||||
// SLEEP
|
||||
// if we have plenty of time, sleep to save CPU and
|
||||
// wake up slightly before the target time
|
||||
if sleepTime > spinThreshold {
|
||||
time.Sleep(sleepTime - spinThreshold)
|
||||
if sleepTimeNs > spinThresholdNs {
|
||||
time.Sleep(time.Duration(sleepTimeNs - spinThresholdNs))
|
||||
}
|
||||
|
||||
// SPIN
|
||||
// if we are close to the target,
|
||||
// burn CPU and check the clock with ns resolution.
|
||||
// SpinBatch batches the time check to reduce
|
||||
// syscall overhead while keeping sub-us precision.
|
||||
// overhead while keeping sub-us precision.
|
||||
for {
|
||||
for range batch - 1 {
|
||||
}
|
||||
if !time.Now().Before(deadline) {
|
||||
if os.Nanotime() >= deadline {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -368,7 +369,7 @@ func (f *Frontend) Start() {
|
|||
// lagging behind the target framerate so we don't sleep
|
||||
if f.conf.LogDroppedFrames {
|
||||
// !to make some stats counter instead
|
||||
f.log.Debug().Msgf("[] Frame drop: %v", elapsed)
|
||||
f.log.Debug().Msgf("[] Frame drop: %v", time.Duration(elapsed))
|
||||
}
|
||||
f.skipVideo = true
|
||||
}
|
||||
|
|
@ -378,13 +379,13 @@ func (f *Frontend) Start() {
|
|||
// adding targetFrameTime to the previous start
|
||||
// prevents drift, if one frame was late,
|
||||
// we try to catch up in the next frame
|
||||
lastFrameStart = lastFrameStart.Add(targetFrameTime)
|
||||
lastFrameStart = lastFrameStart + targetFrameTimeNs
|
||||
|
||||
// if execution was paused or heavily delayed,
|
||||
// reset lastFrameStart so we don't try to run
|
||||
// a bunch of frames instantly to catch up
|
||||
if time.Since(lastFrameStart) > targetFrameTime*lateFramesThreshold {
|
||||
lastFrameStart = time.Now()
|
||||
if os.Nanotime()-lastFrameStart > targetFrameTimeNs*lateFramesThreshold {
|
||||
lastFrameStart = os.Nanotime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue