[Web] Small fixes and enhancements.
- "Definitive" fix for ENOENT randomly disappearing from emscripten. - Proper shutdown when setup fails. - Re-enable WebGL explicit buffer swap. - Re-enable optional per-pixel transparency. - Add type cast to make closure compiler happy. - Remove emscripten Safari WebGL workaround. - Improve AudioWorklet cleanup.
This commit is contained in:
parent
c658fa8b77
commit
27f22b29f8
7 changed files with 51 additions and 11 deletions
|
@ -227,3 +227,7 @@ def configure(env):
|
||||||
|
|
||||||
# Add code that allow exiting runtime.
|
# Add code that allow exiting runtime.
|
||||||
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
||||||
|
|
||||||
|
# This workaround creates a closure that prevents the garbage collector from freeing the WebGL context.
|
||||||
|
# We also only use WebGL2, and changing context version is not widely supported anyway.
|
||||||
|
env.Append(LINKFLAGS=["-s", "GL_WORKAROUND_SAFARI_GETCONTEXT_BUG=0"])
|
||||||
|
|
|
@ -764,10 +764,10 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
|
||||||
if (wants_webgl2 && !webgl2_init_failed) {
|
if (wants_webgl2 && !webgl2_init_failed) {
|
||||||
EmscriptenWebGLContextAttributes attributes;
|
EmscriptenWebGLContextAttributes attributes;
|
||||||
emscripten_webgl_init_context_attributes(&attributes);
|
emscripten_webgl_init_context_attributes(&attributes);
|
||||||
//attributes.alpha = GLOBAL_GET("display/window/per_pixel_transparency/allowed");
|
attributes.alpha = OS::get_singleton()->is_layered_allowed();
|
||||||
attributes.alpha = true;
|
|
||||||
attributes.antialias = false;
|
attributes.antialias = false;
|
||||||
attributes.majorVersion = 2;
|
attributes.majorVersion = 2;
|
||||||
|
attributes.explicitSwapControl = true;
|
||||||
|
|
||||||
webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes);
|
webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes);
|
||||||
if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
|
if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
|
|
|
@ -317,7 +317,8 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
|
||||||
if (!(this.canvas instanceof HTMLCanvasElement)) {
|
if (!(this.canvas instanceof HTMLCanvasElement)) {
|
||||||
const nodes = document.getElementsByTagName('canvas');
|
const nodes = document.getElementsByTagName('canvas');
|
||||||
if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
|
if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
|
||||||
this.canvas = nodes[0];
|
const first = nodes[0];
|
||||||
|
this.canvas = /** @type {!HTMLCanvasElement} */ (first);
|
||||||
}
|
}
|
||||||
if (!this.canvas) {
|
if (!this.canvas) {
|
||||||
throw new Error('No canvas found in page');
|
throw new Error('No canvas found in page');
|
||||||
|
|
|
@ -133,6 +133,8 @@ class GodotProcessor extends AudioWorkletProcessor {
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.output = null;
|
this.output = null;
|
||||||
this.input = null;
|
this.input = null;
|
||||||
|
this.lock = null;
|
||||||
|
this.notifier = null;
|
||||||
} else if (p_cmd === 'start_nothreads') {
|
} else if (p_cmd === 'start_nothreads') {
|
||||||
this.output = new RingBuffer(p_data[0], p_data[0].length, false);
|
this.output = new RingBuffer(p_data[0], p_data[0].length, false);
|
||||||
} else if (p_cmd === 'chunk') {
|
} else if (p_cmd === 'chunk') {
|
||||||
|
|
|
@ -339,16 +339,21 @@ const GodotAudioWorklet = {
|
||||||
if (GodotAudioWorklet.promise === null) {
|
if (GodotAudioWorklet.promise === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GodotAudioWorklet.promise.then(function () {
|
const p = GodotAudioWorklet.promise;
|
||||||
|
p.then(function () {
|
||||||
GodotAudioWorklet.worklet.port.postMessage({
|
GodotAudioWorklet.worklet.port.postMessage({
|
||||||
'cmd': 'stop',
|
'cmd': 'stop',
|
||||||
'data': null,
|
'data': null,
|
||||||
});
|
});
|
||||||
GodotAudioWorklet.worklet.disconnect();
|
GodotAudioWorklet.worklet.disconnect();
|
||||||
|
GodotAudioWorklet.worklet.port.onmessage = null;
|
||||||
GodotAudioWorklet.worklet = null;
|
GodotAudioWorklet.worklet = null;
|
||||||
GodotAudioWorklet.promise = null;
|
GodotAudioWorklet.promise = null;
|
||||||
resolve();
|
resolve();
|
||||||
}).catch(function (err) { /* aborted? */ });
|
}).catch(function (err) {
|
||||||
|
// Aborted?
|
||||||
|
GodotRuntime.error(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -106,12 +106,14 @@ autoAddDeps(GodotConfig, '$GodotConfig');
|
||||||
mergeInto(LibraryManager.library, GodotConfig);
|
mergeInto(LibraryManager.library, GodotConfig);
|
||||||
|
|
||||||
const GodotFS = {
|
const GodotFS = {
|
||||||
$GodotFS__deps: ['$ERRNO_CODES', '$FS', '$IDBFS', '$GodotRuntime'],
|
$GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'],
|
||||||
$GodotFS__postset: [
|
$GodotFS__postset: [
|
||||||
'Module["initFS"] = GodotFS.init;',
|
'Module["initFS"] = GodotFS.init;',
|
||||||
'Module["copyToFS"] = GodotFS.copy_to_fs;',
|
'Module["copyToFS"] = GodotFS.copy_to_fs;',
|
||||||
].join(''),
|
].join(''),
|
||||||
$GodotFS: {
|
$GodotFS: {
|
||||||
|
// ERRNO_CODES works every odd version of emscripten, but this will break too eventually.
|
||||||
|
ENOENT: 44,
|
||||||
_idbfs: false,
|
_idbfs: false,
|
||||||
_syncing: false,
|
_syncing: false,
|
||||||
_mount_points: [],
|
_mount_points: [],
|
||||||
|
@ -138,8 +140,9 @@ const GodotFS = {
|
||||||
try {
|
try {
|
||||||
FS.stat(dir);
|
FS.stat(dir);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.errno !== ERRNO_CODES.ENOENT) {
|
if (e.errno !== GodotFS.ENOENT) {
|
||||||
throw e;
|
// Let mkdirTree throw in case, we cannot trust the above check.
|
||||||
|
GodotRuntime.error(e);
|
||||||
}
|
}
|
||||||
FS.mkdirTree(dir);
|
FS.mkdirTree(dir);
|
||||||
}
|
}
|
||||||
|
@ -208,8 +211,9 @@ const GodotFS = {
|
||||||
try {
|
try {
|
||||||
FS.stat(dir);
|
FS.stat(dir);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.errno !== ERRNO_CODES.ENOENT) {
|
if (e.errno !== GodotFS.ENOENT) {
|
||||||
throw e;
|
// Let mkdirTree throw in case, we cannot trust the above check.
|
||||||
|
GodotRuntime.error(e);
|
||||||
}
|
}
|
||||||
FS.mkdirTree(dir);
|
FS.mkdirTree(dir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,18 @@ void cleanup_after_sync() {
|
||||||
emscripten_set_main_loop(exit_callback, -1, false);
|
emscripten_set_main_loop(exit_callback, -1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void early_cleanup() {
|
||||||
|
emscripten_cancel_main_loop(); // After this, we can exit!
|
||||||
|
int exit_code = OS_Web::get_singleton()->get_exit_code();
|
||||||
|
memdelete(os);
|
||||||
|
os = nullptr;
|
||||||
|
emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
|
||||||
|
}
|
||||||
|
|
||||||
|
void early_cleanup_sync() {
|
||||||
|
emscripten_set_main_loop(early_cleanup, -1, false);
|
||||||
|
}
|
||||||
|
|
||||||
void main_loop_callback() {
|
void main_loop_callback() {
|
||||||
uint64_t current_ticks = os->get_ticks_usec();
|
uint64_t current_ticks = os->get_ticks_usec();
|
||||||
|
|
||||||
|
@ -87,7 +99,19 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
|
||||||
// We must override main when testing is enabled
|
// We must override main when testing is enabled
|
||||||
TEST_MAIN_OVERRIDE
|
TEST_MAIN_OVERRIDE
|
||||||
|
|
||||||
Main::setup(argv[0], argc - 1, &argv[1]);
|
Error err = Main::setup(argv[0], argc - 1, &argv[1]);
|
||||||
|
|
||||||
|
// Proper shutdown in case of setup failure.
|
||||||
|
if (err != OK) {
|
||||||
|
int exit_code = (int)err;
|
||||||
|
if (err == ERR_HELP) {
|
||||||
|
exit_code = 0; // Called with --help.
|
||||||
|
}
|
||||||
|
os->set_exit_code(exit_code);
|
||||||
|
// Will only exit after sync.
|
||||||
|
godot_js_os_finish_async(early_cleanup_sync);
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
// Ease up compatibility.
|
// Ease up compatibility.
|
||||||
ResourceLoader::set_abort_on_missing_resources(false);
|
ResourceLoader::set_abort_on_missing_resources(false);
|
||||||
|
|
Loading…
Reference in a new issue