-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Add support for preMainLoop/postMainLoop functions #22621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -149,12 +149,23 @@ LibraryJSEventLoop = { | |||||
| clearInterval(id); | ||||||
| }, | ||||||
|
|
||||||
| $registerPostMainLoop: (f) => { | ||||||
| // Does nothing unless $MainLoop is included/used. | ||||||
| typeof MainLoop != 'undefined' && MainLoop.postMainLoop.push(f); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sadly I don't think the ? operator works like that (i.e. it doesn't work on top level things): There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh sorry. That is unfortunate, I wonder why it has that restriction. |
||||||
| }, | ||||||
|
|
||||||
| $registerPreMainLoop: (f) => { | ||||||
| // Does nothing unless $MainLoop is included/used. | ||||||
| typeof MainLoop != 'undefined' && MainLoop.preMainLoop.push(f); | ||||||
| }, | ||||||
|
|
||||||
| $MainLoop__internal: true, | ||||||
| $MainLoop__deps: ['$setMainLoop', '$callUserCallback', 'emscripten_set_main_loop_timing'], | ||||||
| $MainLoop__postset: ` | ||||||
| Module["requestAnimationFrame"] = MainLoop.requestAnimationFrame; | ||||||
| Module["pauseMainLoop"] = MainLoop.pause; | ||||||
| Module["resumeMainLoop"] = MainLoop.resume;`, | ||||||
| Module["resumeMainLoop"] = MainLoop.resume; | ||||||
| MainLoop.init();`, | ||||||
| $MainLoop: { | ||||||
| running: false, | ||||||
| scheduler: null, | ||||||
|
|
@@ -173,6 +184,8 @@ LibraryJSEventLoop = { | |||||
| timingValue: 0, | ||||||
| currentFrameNumber: 0, | ||||||
| queue: [], | ||||||
| preMainLoop: [], | ||||||
| postMainLoop: [], | ||||||
|
|
||||||
| pause() { | ||||||
| MainLoop.scheduler = null; | ||||||
|
|
@@ -211,19 +224,28 @@ LibraryJSEventLoop = { | |||||
| #endif | ||||||
| }, | ||||||
|
|
||||||
| init() { | ||||||
| #if expectToReceiveOnModule('preMainLoop') | ||||||
| Module['preMainLoop'] && MainLoop.preMainLoop.push(Module['preMainLoop']); | ||||||
| #endif | ||||||
| #if expectToReceiveOnModule('postMainLoop') | ||||||
| Module['postMainLoop'] && MainLoop.postMainLoop.push(Module['postMainLoop']); | ||||||
| #endif | ||||||
| }, | ||||||
|
|
||||||
| runIter(func) { | ||||||
| if (ABORT) return; | ||||||
| #if expectToReceiveOnModule('preMainLoop') | ||||||
| if (Module['preMainLoop']) { | ||||||
| var preRet = Module['preMainLoop'](); | ||||||
| if (preRet === false) { | ||||||
| for (var pre of MainLoop.preMainLoop) { | ||||||
| if (pre() === false) { | ||||||
| return; // |return false| skips a frame | ||||||
| } | ||||||
| } | ||||||
| #endif | ||||||
| callUserCallback(func); | ||||||
| #if expectToReceiveOnModule('postMainLoop') | ||||||
| Module['postMainLoop']?.(); | ||||||
| for (var post of MainLoop.postMainLoop) { | ||||||
| post(); | ||||||
| } | ||||||
| #if STACK_OVERFLOW_CHECK | ||||||
| checkStackCookie(); | ||||||
| #endif | ||||||
| }, | ||||||
|
|
||||||
|
|
@@ -424,28 +446,6 @@ LibraryJSEventLoop = { | |||||
| MainLoop.tickStartTime = _emscripten_get_now(); | ||||||
| } | ||||||
|
|
||||||
| // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize | ||||||
| // VBO double-buffering and reduce GPU stalls. | ||||||
| #if FULL_ES2 || LEGACY_GL_EMULATION | ||||||
| GL.newRenderingFrameStarted(); | ||||||
| #endif | ||||||
|
|
||||||
| #if PTHREADS && OFFSCREEN_FRAMEBUFFER && GL_SUPPORT_EXPLICIT_SWAP_CONTROL | ||||||
| // If the current GL context is a proxied regular WebGL context, and was initialized with implicit swap mode on the main thread, and we are on the parent thread, | ||||||
| // perform the swap on behalf of the user. | ||||||
| if (typeof GL != 'undefined' && GL.currentContext && GL.currentContextIsProxied) { | ||||||
| var explicitSwapControl = {{{ makeGetValue('GL.currentContext', 0, 'i32') }}}; | ||||||
| if (!explicitSwapControl) _emscripten_webgl_commit_frame(); | ||||||
| } | ||||||
| #endif | ||||||
|
|
||||||
| #if OFFSCREENCANVAS_SUPPORT | ||||||
| // If the current GL context is an OffscreenCanvas, but it was initialized with implicit swap mode, perform the swap on behalf of the user. | ||||||
| if (typeof GL != 'undefined' && GL.currentContext && !GL.currentContextIsProxied && !GL.currentContext.attributes.explicitSwapControl && GL.currentContext.GLctx.commit) { | ||||||
| GL.currentContext.GLctx.commit(); | ||||||
| } | ||||||
| #endif | ||||||
|
|
||||||
| #if ASSERTIONS | ||||||
| if (MainLoop.method === 'timeout' && Module.ctx) { | ||||||
| warnOnce('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!'); | ||||||
|
|
@@ -455,19 +455,9 @@ LibraryJSEventLoop = { | |||||
|
|
||||||
| MainLoop.runIter(iterFunc); | ||||||
|
|
||||||
| #if STACK_OVERFLOW_CHECK | ||||||
| checkStackCookie(); | ||||||
| #endif | ||||||
|
|
||||||
| // catch pauses from the main loop itself | ||||||
| if (!checkIsRunning()) return; | ||||||
|
|
||||||
| // Queue new audio data. This is important to be right after the main loop invocation, so that we will immediately be able | ||||||
| // to queue the newest produced audio samples. | ||||||
| // TODO: Consider adding pre- and post- rAF callbacks so that GL.newRenderingFrameStarted() and SDL.audio.queueNewAudioData() | ||||||
| // do not need to be hardcoded into this function, but can be more generic. | ||||||
| if (typeof SDL == 'object') SDL.audio?.queueNewAudioData?.(); | ||||||
|
|
||||||
| MainLoop.scheduler(); | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment that as an optimization, this does not include MainLoop but instead checks for it at runtime and does nothing?
Separately, I wonder if we can do better than this. We could in theory add a "weak linking" mechanism, that would add some code only if MainLoop was actually included. Though if it's complicated it might not be worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly I don't think we have such a weak linking mechanism today. The way I did it here I think is the closest thing we have to weak linking in JS code.