clock: Refactoring

This commit is contained in:
Hajime Hoshi 2017-08-06 00:52:12 +09:00
parent e98475cf9d
commit 2e7a477f9d
3 changed files with 50 additions and 41 deletions

View File

@ -262,7 +262,7 @@ func (c *Context) loop() {
c.pingCount-- c.pingCount--
c.m.Unlock() c.m.Unlock()
c.frames++ c.frames++
clock.Inc() clock.ProceedPrimaryTimer()
bytesPerFrame := c.sampleRate * bytesPerSample * channelNum / loop.FPS bytesPerFrame := c.sampleRate * bytesPerSample * channelNum / loop.FPS
l := (c.frames * int64(bytesPerFrame)) - c.writtenBytes l := (c.frames * int64(bytesPerFrame)) - c.writtenBytes
l &= mask l &= mask

View File

@ -21,50 +21,73 @@ import (
) )
var ( var (
m sync.Mutex m sync.Mutex
tick int64 primaryTime int64
lastTick int64 lastPrimaryTime int64
frames int64 frames int64
logicalTime int64
) )
func Inc() { // ProceedPrimaryTimer increments the primary time by a frame.
func ProceedPrimaryTimer() {
m.Lock() m.Lock()
tick++ primaryTime++
m.Unlock() m.Unlock()
} }
func Frames(timeDuration time.Duration, fps int) (int, bool) { // Frames returns an integer value indicating how many logical frames the game should update.
//
// Frames also updates the inner timer states.
func Frames(now int64, fps int) int {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
// Initialize logicalTime if needed.
if logicalTime == 0 {
logicalTime = now
}
t := now - logicalTime
if t < 0 {
return 0
}
count := 0 count := 0
// There are two time lines: one is the logical time and the other is the system clock.
//
// Usually logical time is updated based on the number of frames, but
// when sync is true, the logical time is forced to sync with the system clock.
sync := false sync := false
if tick > 0 && lastTick != tick {
if frames < tick { if primaryTime > 0 && lastPrimaryTime != primaryTime {
count = int(tick - frames) // If the primary time is updated, use this.
if frames < primaryTime {
count = int(primaryTime - frames)
} }
lastTick = tick lastPrimaryTime = primaryTime
sync = true sync = true
} else { } else {
// Use system clock when // Use system clock when
// 1) Inc() is not called, or // 1) Inc() is not called, or
// 2) tick is not updated yet. // 2) the primary time is not updated yet.
// As tick can be updated discountinuously, use system clock supplementarily. // As the primary time can be updated discountinuously,
// the system clock is still needed.
if int64(timeDuration) > 5*int64(time.Second)/int64(fps) { if t > 5*int64(time.Second)/int64(fps) {
// The previous time is too old. // The previous time is too old.
// Let's force to sync the logical frame with the OS clock (or tick). // Let's force to sync the logical time with the OS clock.
return 0, true sync = true
} else {
count = int(t * int64(fps) / int64(time.Second))
} }
count = int(int64(timeDuration) * int64(fps) / int64(time.Second))
} }
// Stabilize FPS. // Stabilize FPS.
if count == 0 && (int64(time.Second)/int64(fps)/2) < int64(timeDuration) { if count == 0 && (int64(time.Second)/int64(fps)/2) < t {
count = 1 count = 1
} }
if count == 2 && (int64(time.Second)/int64(fps)*3/2) > int64(timeDuration) { if count == 2 && (int64(time.Second)/int64(fps)*3/2) > t {
count = 1 count = 1
} }
if count > 3 { if count > 3 {
@ -72,5 +95,10 @@ func Frames(timeDuration time.Duration, fps int) (int, bool) {
} }
frames += int64(count) frames += int64(count)
return count, sync if sync {
logicalTime = now
} else {
logicalTime += int64(count) * int64(time.Second) / int64(fps)
}
return count
} }

View File

@ -35,7 +35,6 @@ type runContext struct {
currentFPS float64 currentFPS float64
runningSlowly bool runningSlowly bool
framesForFPS int64 framesForFPS int64
lastUpdated int64
lastFPSUpdated int64 lastFPSUpdated int64
ping func() ping func()
m sync.RWMutex m sync.RWMutex
@ -67,7 +66,6 @@ func Start() error {
theRunContext = &runContext{} theRunContext = &runContext{}
n := now() n := now()
theRunContext.lastUpdated = n
theRunContext.lastFPSUpdated = n theRunContext.lastFPSUpdated = n
close(contextInitCh) close(contextInitCh)
@ -78,23 +76,6 @@ func End() {
theRunContext = nil theRunContext = nil
} }
func (c *runContext) updateCount(now int64) int {
t := now - c.lastUpdated
if t < 0 {
return 0
}
count, sync := clock.Frames(time.Duration(t), FPS)
if sync {
c.lastUpdated = now
} else {
c.lastUpdated += int64(count) * int64(time.Second) / int64(FPS)
}
return count
}
func RegisterPing(ping func()) { func RegisterPing(ping func()) {
<-contextInitCh <-contextInitCh
theRunContext.registerPing(ping) theRunContext.registerPing(ping)
@ -124,7 +105,7 @@ func (c *runContext) update(u Updater) error {
} }
c.m.Unlock() c.m.Unlock()
count := c.updateCount(n) count := clock.Frames(n, FPS)
if err := u.Update(count); err != nil { if err := u.Update(count); err != nil {
return err return err
} }