Kode / Kha

Ultra-portable, high performance, open source multimedia framework.
http://kha.tech
zlib License
1.49k stars 170 forks source link

Scheduler/Timetasks stop updating while actual framerate significantly higher than detected refresh rate #1277

Closed zshoals closed 3 years ago

zshoals commented 3 years ago

This describes the actual issue more accurately than https://github.com/Kode/Kha/issues/1266.

Describe the bug It's a little more nuanced than the title.

Scheduler will miss updating Timetasks properly if the actual framerate exceeds Kha's internal detected frequency, causing noticeable hitching and stuttering. The greater the difference between the actual framerate and the detected refresh rate, the more severe the issue becomes. With a big enough difference, updates will stop entirely, unless something interferes with the framerate.

When I say stop, I do actually mean that Timetasks cease execution, or at least the ones with intervals set do.

The issue probably arises from this piece of code: https://github.com/Kode/Kha/blob/1891555b39557e74da61d6648fd9087c184dc919/Sources/kha/Scheduler.hx#L193-L198

As an example, when the monitor's refresh rate is 120hz, and the detected frequency is 30hz, this math equates to (0.00833 / 0.033333) ~ 0.25, which is then rounded down to 0, then 0 propagates through the rest of this section. I'm uncertain of the exact behavior afterwards but I assume that Timetasks compare how much of this adjusted time has passed to their target update time, and since the time passed is always 0 updates effectively cease.

I'm not sure if this is a bug with improperly detected refresh rates internally (HTML5 being the big culprit here with its locked 60hz value), or if it's actually a Scheduler issue. Either way the effect it has is pretty...show stopping, you could say.

To Reproduce Steps to reproduce the behavior (probably easiest to test on the HTML5 backend): 1a. Make a simple project that does something noticeable (trace is good enough) in the update loop, or... 1b. ...clone this repo for a simple visual demo: https://github.com/zshoals/timetask-bug

  1. Set get_frequency in Display.hx to a low value, let's say 10, which should be low enough to trigger it on any monitor
  2. Run it. Notice that updates don't actually occur after the framerate stabilizes after startup.

Expected behavior Dunno exactly, Scheduler is still elusive to me. However, I would assume that Timetasks stopping entirely is not appropriate behavior.

Execution Environment:

Additional context Hopefully I got it right this time :cold_sweat:

RobDangerous commented 3 years ago

Super thanks for the nice analysis! Will get to it ASAP.

RobDangerous commented 3 years ago

Could reproduce the complete halt in the Scheduler with big internal vs external frequency differences but as long as it did still execute time-tasks it executed all of them as far as I could tell.

zshoals commented 3 years ago

Thanks! I didn't mean to imply that particular Timetasks worked and others didn't, it was certainly an all or nothing situation.

Ah, I see where I wasn't clear about that. I failed to specify that I just...didn't try with an unset interval, so I wasn't sure. Don't even know why I skipped trying that, now that I think about it, it was literally trivial to experiment with...