Fix a bug where multiple rAF-based frame update loops could stack on top of each other and run in parallel. This fixes the additions to the test from before.

This commit is contained in:
Jukka Jylänki 2014-09-27 00:06:40 +03:00
Родитель cdaaa74df7
Коммит 96912bee22
1 изменённых файлов: 20 добавлений и 25 удалений

Просмотреть файл

@ -2,7 +2,7 @@
// Utilities for browser environments // Utilities for browser environments
mergeInto(LibraryManager.library, { mergeInto(LibraryManager.library, {
$Browser__deps: ['$PATH'], $Browser__deps: ['$PATH', 'emscripten_set_main_loop'],
$Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports $Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports
'Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };\n' + 'Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };\n' +
'Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' + 'Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' +
@ -13,18 +13,17 @@ mergeInto(LibraryManager.library, {
mainLoop: { mainLoop: {
scheduler: null, scheduler: null,
method: '', method: '',
shouldPause: false, // Each main loop is numbered with a ID in sequence order. Only one main loop can run at a time. This variable stores the ordinal number of the main loop that is currently
paused: false, // allowed to run. All previous main loops will quit themselves. This is incremented whenever a new main loop is created.
currentlyRunningMainloop: 0,
queue: [], queue: [],
pause: function() { pause: function() {
Browser.mainLoop.shouldPause = true; Browser.mainLoop.scheduler = null;
Browser.mainLoop.currentlyRunningMainloop++; // Incrementing this signals the previous main loop that it's now become old, and it must return.
}, },
resume: function() { resume: function() {
if (Browser.mainLoop.paused) { Browser.mainLoop.currentlyRunningMainloop++;
Browser.mainLoop.paused = false; _emscripten_set_main_loop(Browser.mainLoop.func, Browser.mainLoop.fps, false, Browser.mainLoop.arg);
Browser.mainLoop.scheduler();
}
Browser.mainLoop.shouldPause = false;
}, },
updateStatus: function() { updateStatus: function() {
if (Module['setStatus']) { if (Module['setStatus']) {
@ -966,9 +965,13 @@ mergeInto(LibraryManager.library, {
emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop, arg) { emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop, arg) {
Module['noExitRuntime'] = true; Module['noExitRuntime'] = true;
assert(!Browser.mainLoop.scheduler, 'there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one, if you want to'); assert(!Browser.mainLoop.scheduler, 'there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.');
Browser.mainLoop.shouldPause = Browser.mainLoop.paused = false; // if we were cancelled or paused, undo that Browser.mainLoop.func = func;
Browser.mainLoop.fps = fps;
Browser.mainLoop.arg = arg;
var thisMainLoopId = Browser.mainLoop.currentlyRunningMainloop;
Browser.mainLoop.runner = function Browser_mainLoop_runner() { Browser.mainLoop.runner = function Browser_mainLoop_runner() {
if (ABORT) return; if (ABORT) return;
@ -992,12 +995,9 @@ mergeInto(LibraryManager.library, {
setTimeout(Browser.mainLoop.runner, 0); setTimeout(Browser.mainLoop.runner, 0);
return; return;
} }
if (Browser.mainLoop.shouldPause) {
// catch pauses from non-main loop sources // catch pauses from non-main loop sources
Browser.mainLoop.paused = true; if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) return;
Browser.mainLoop.shouldPause = false;
return;
}
// Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize // 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. // VBO double-buffering and reduce GPU stalls.
@ -1018,12 +1018,8 @@ mergeInto(LibraryManager.library, {
} }
}); });
if (Browser.mainLoop.shouldPause) { // catch pauses from the main loop itself
// catch pauses from the main loop itself if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) return;
Browser.mainLoop.paused = true;
Browser.mainLoop.shouldPause = false;
return;
}
// Queue new audio data. This is important to be right after the main loop invocation, so that we will immediately be able // 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. // to queue the newest produced audio samples.
@ -1057,8 +1053,7 @@ mergeInto(LibraryManager.library, {
}, },
emscripten_cancel_main_loop: function() { emscripten_cancel_main_loop: function() {
Browser.mainLoop.scheduler = null; Browser.mainLoop.pause();
Browser.mainLoop.shouldPause = true;
}, },
emscripten_pause_main_loop: function() { emscripten_pause_main_loop: function() {