mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	[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. | ||||
|     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) { | ||||
| 		EmscriptenWebGLContextAttributes attributes; | ||||
| 		emscripten_webgl_init_context_attributes(&attributes); | ||||
| 		//attributes.alpha = GLOBAL_GET("display/window/per_pixel_transparency/allowed");
 | ||||
| 		attributes.alpha = true; | ||||
| 		attributes.alpha = OS::get_singleton()->is_layered_allowed(); | ||||
| 		attributes.antialias = false; | ||||
| 		attributes.majorVersion = 2; | ||||
| 		attributes.explicitSwapControl = true; | ||||
| 
 | ||||
| 		webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes); | ||||
| 		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)) { | ||||
| 			const nodes = document.getElementsByTagName('canvas'); | ||||
| 			if (nodes.length && nodes[0] instanceof HTMLCanvasElement) { | ||||
| 				this.canvas = nodes[0]; | ||||
| 				const first = nodes[0]; | ||||
| 				this.canvas = /** @type {!HTMLCanvasElement} */ (first); | ||||
| 			} | ||||
| 			if (!this.canvas) { | ||||
| 				throw new Error('No canvas found in page'); | ||||
|  |  | |||
|  | @ -133,6 +133,8 @@ class GodotProcessor extends AudioWorkletProcessor { | |||
| 			this.running = false; | ||||
| 			this.output = null; | ||||
| 			this.input = null; | ||||
| 			this.lock = null; | ||||
| 			this.notifier = null; | ||||
| 		} else if (p_cmd === 'start_nothreads') { | ||||
| 			this.output = new RingBuffer(p_data[0], p_data[0].length, false); | ||||
| 		} else if (p_cmd === 'chunk') { | ||||
|  |  | |||
|  | @ -339,16 +339,21 @@ const GodotAudioWorklet = { | |||
| 				if (GodotAudioWorklet.promise === null) { | ||||
| 					return; | ||||
| 				} | ||||
| 				GodotAudioWorklet.promise.then(function () { | ||||
| 				const p = GodotAudioWorklet.promise; | ||||
| 				p.then(function () { | ||||
| 					GodotAudioWorklet.worklet.port.postMessage({ | ||||
| 						'cmd': 'stop', | ||||
| 						'data': null, | ||||
| 					}); | ||||
| 					GodotAudioWorklet.worklet.disconnect(); | ||||
| 					GodotAudioWorklet.worklet.port.onmessage = null; | ||||
| 					GodotAudioWorklet.worklet = null; | ||||
| 					GodotAudioWorklet.promise = null; | ||||
| 					resolve(); | ||||
| 				}).catch(function (err) { /* aborted? */ }); | ||||
| 				}).catch(function (err) { | ||||
| 					// Aborted?
 | ||||
| 					GodotRuntime.error(err); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}, | ||||
| 	}, | ||||
|  |  | |||
|  | @ -106,12 +106,14 @@ autoAddDeps(GodotConfig, '$GodotConfig'); | |||
| mergeInto(LibraryManager.library, GodotConfig); | ||||
| 
 | ||||
| const GodotFS = { | ||||
| 	$GodotFS__deps: ['$ERRNO_CODES', '$FS', '$IDBFS', '$GodotRuntime'], | ||||
| 	$GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'], | ||||
| 	$GodotFS__postset: [ | ||||
| 		'Module["initFS"] = GodotFS.init;', | ||||
| 		'Module["copyToFS"] = GodotFS.copy_to_fs;', | ||||
| 	].join(''), | ||||
| 	$GodotFS: { | ||||
| 		// ERRNO_CODES works every odd version of emscripten, but this will break too eventually.
 | ||||
| 		ENOENT: 44, | ||||
| 		_idbfs: false, | ||||
| 		_syncing: false, | ||||
| 		_mount_points: [], | ||||
|  | @ -138,8 +140,9 @@ const GodotFS = { | |||
| 				try { | ||||
| 					FS.stat(dir); | ||||
| 				} catch (e) { | ||||
| 					if (e.errno !== ERRNO_CODES.ENOENT) { | ||||
| 						throw e; | ||||
| 					if (e.errno !== GodotFS.ENOENT) { | ||||
| 						// Let mkdirTree throw in case, we cannot trust the above check.
 | ||||
| 						GodotRuntime.error(e); | ||||
| 					} | ||||
| 					FS.mkdirTree(dir); | ||||
| 				} | ||||
|  | @ -208,8 +211,9 @@ const GodotFS = { | |||
| 			try { | ||||
| 				FS.stat(dir); | ||||
| 			} catch (e) { | ||||
| 				if (e.errno !== ERRNO_CODES.ENOENT) { | ||||
| 					throw e; | ||||
| 				if (e.errno !== GodotFS.ENOENT) { | ||||
| 					// Let mkdirTree throw in case, we cannot trust the above check.
 | ||||
| 					GodotRuntime.error(e); | ||||
| 				} | ||||
| 				FS.mkdirTree(dir); | ||||
| 			} | ||||
|  |  | |||
|  | @ -55,6 +55,18 @@ void cleanup_after_sync() { | |||
| 	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() { | ||||
| 	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
 | ||||
| 	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.
 | ||||
| 	ResourceLoader::set_abort_on_missing_resources(false); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fabio Alessandrelli
						Fabio Alessandrelli