diff --git a/audio/audio.go b/audio/audio.go index 250dd501c..78612398d 100644 --- a/audio/audio.go +++ b/audio/audio.go @@ -262,7 +262,7 @@ func (c *Context) loop() { c.pingCount-- c.m.Unlock() c.frames++ - clock.Tick() + clock.Inc() bytesPerFrame := c.sampleRate * bytesPerSample * channelNum / loop.FPS l := (c.frames * int64(bytesPerFrame)) - c.writtenBytes l &= mask diff --git a/internal/clock/clock.go b/internal/clock/clock.go index 956f0cef0..4307c6cbd 100644 --- a/internal/clock/clock.go +++ b/internal/clock/clock.go @@ -15,32 +15,63 @@ package clock import ( + "time" + "github.com/hajimehoshi/ebiten/internal/sync" ) var ( - m sync.Mutex - valid bool - now int64 + m sync.Mutex + valid bool + tick int64 + lastTick int64 + frames int64 ) -func IsValid() bool { - m.Lock() - v := valid - m.Unlock() - return v -} - -func Tick() { +func Inc() { m.Lock() valid = true - now++ + tick++ m.Unlock() } -func Now() int64 { +func Frames(timeDuration time.Duration, fps int) (int, bool) { m.Lock() - n := now - m.Unlock() - return n + defer m.Unlock() + + count := 0 + + sync := false + if valid && lastTick != tick { + if frames < tick { + count = int(tick - frames) + } + lastTick = tick + sync = true + } else { + // Use system clock when + // 1) Inc() is not called, or + // 2) tick is not updated yet. + // As tick can be updated discountinuously, use system clock supplementarily. + + if int64(timeDuration) > 5*int64(time.Second)/int64(fps) { + // The previous time is too old. Let's assume that the window was unfocused. + return 0, true + } + count = int(int64(timeDuration) * int64(fps) / int64(time.Second)) + } + + // Stabilize FPS. + if count == 0 && (int64(time.Second)/int64(fps)/2) < int64(timeDuration) { + count = 1 + } + if count == 2 && (int64(time.Second)/int64(fps)*3/2) > int64(timeDuration) { + count = 1 + } + if count > 3 { + count = 3 + } + + frames += int64(count) + return count, sync } diff --git a/internal/loop/run.go b/internal/loop/run.go index 16e037a73..1b1e5b628 100644 --- a/internal/loop/run.go +++ b/internal/loop/run.go @@ -34,11 +34,9 @@ func CurrentFPS() float64 { type runContext struct { currentFPS float64 runningSlowly bool - frames int64 framesForFPS int64 lastUpdated int64 lastFPSUpdated int64 - lastClockFrame int64 ping func() m sync.RWMutex } @@ -81,42 +79,12 @@ func End() { } func (c *runContext) updateCount(now int64) int { - count := 0 - sync := false - t := now - c.lastUpdated if t < 0 { return 0 } - if clock.IsValid() && c.lastClockFrame != clock.Now() { - sync = true - f := clock.Now() - if c.frames < f { - count = int(f - c.frames) - } - c.lastClockFrame = f - } else { - if t > 5*int64(time.Second)/int64(FPS) { - // The previous time is too old. Let's assume that the window was unfocused. - count = 0 - sync = true - } else { - count = int(t * int64(FPS) / int64(time.Second)) - } - } - - // Stabilize FPS. - if count == 0 && (int64(time.Second)/int64(FPS)/2) < t { - count = 1 - } - if count == 2 && (int64(time.Second)/int64(FPS)*3/2) > t { - count = 1 - } - - if count > 3 { - count = 3 - } + count, sync := clock.Frames(time.Duration(t), FPS) if sync { c.lastUpdated = now @@ -124,7 +92,6 @@ func (c *runContext) updateCount(now int64) int { c.lastUpdated += int64(count) * int64(time.Second) / int64(FPS) } - c.frames += int64(count) return count }