With asyncify, emscripten_sleep becomes incredibly useful to implement game loops. However, the use of setTimeout means that the timing is inconsistent whereas requestAnimationFrame attempts to hold a consistent framerate.
Is there a version of this?
I am currently achieving it with this monkey patch:
const timeoutToAnimationId = {}
const originalSetTimeout = window.setTimeout;
const originalClearTimeout = window.clearTimeout;
window.setTimeout = (func, delay, ...args) => {
if (typeof delay === 'undefined' || delay === 0) {
const timeoutId = originalSetTimeout(() => {});
const animationId = requestAnimationFrame(() =>
{
delete timeoutToAnimationId[timeoutId];
func(...args);
});
timeoutToAnimationId[timeoutId] = animationId
return timeoutId;
} else {
return originalSetTimeout(func, delay, ...args);
}
}
window.clearTimeout = window.clearInterval = (timeoutId) => {
const animationId = timeoutToAnimationId[timeoutId];
if (typeof animationId !== 'undefined') {
cancelAnimationFrame(animationId);
delete timeoutToAnimationId[timeoutId];
} else {
return originalClearTimeout(id);
}
}
I think there isn't a version yet for it. I agree it would be nice to add, PR would be welcome!
One possible API approach is that currently emscripten_set_main_loop takes a timing param, which if it's negative means to use requestAnimationFrame. Perhaps we can do a similar thing in emscripten_sleep. Alternatively, maybe we could just add emscripten_request_animation_frame().
I think having a separate function would be better, only because the behavior of emscripten_set_main_loop is to use requestAnimationFrame if it's 0 or negative. To be consistent, emscripten_sleep could take 0 or a negative value, but then you can never intentionally setTimeout with 0 using emscripten_sleep (I have no idea why anyone would want to use setTimeout with 0 over requestAnimationFrame, but I'm sure there are reasons). We could just do negative, but that seems confusing and inconsistent. I think emscripten_request_animation_frame seems better.
I'd be happy to make the PR this weekend :)
Unrelated comment, I had a lot of problems with the old Emterpreter using Asyncify, but the new version of Asyncify works beautifully on a very large code base, and doesn't seem to increase the size of the wasm. Thank you for your blog post about it, and wonderful job to everyone involved!
@TrevorSundberg I agree, yeah, a new function is probably best. Sounds good about the PR!
And thanks for the kind words! :)
This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.
A PR for this would still be a good I think.
Does it really need to be included? It's such a small and simple thing to add yourself:
EM_JS(void, emscripten_sleep_using_raf, (), {
Asyncify.handleSleep(wakeUp => {
requestAnimationFrame(wakeUp);
});
});
(Though it would be a little more complex if you needed the timestamp to be returned.)
Good point @curiousdannii , maybe a small doc addition would be good enough.
To use @curiousdannii's code, I had to also link with -sASYNCIFY_IMPORTS=["emscripten_sleep_using_raf"] to avoid a stack overflow.
Most helpful comment
To use @curiousdannii's code, I had to also link with
-sASYNCIFY_IMPORTS=["emscripten_sleep_using_raf"]to avoid a stack overflow.