Przeglądaj źródła

[Web] Require threads, rtti, allow optimize=speed.

Update export names (web[_dlink]_[release|debug].zip).

The Build with dynamic linking is broken due to high number of imports
in output wasm (likely emscripten regression issue 15487).
Fabio Alessandrelli 3 lat temu
rodzic
commit
f958f00283

+ 1 - 1
.github/workflows/web_builds.yml

@@ -6,7 +6,7 @@ env:
   # Only used for the cache key. Increment version to force clean build.
   GODOT_BASE_BRANCH: master
   SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
-  EM_VERSION: 3.1.10
+  EM_VERSION: 3.1.20
   EM_CACHE_FOLDER: "emsdk-cache"
 
 concurrency:

+ 1 - 7
modules/text_server_adv/SCsub

@@ -140,15 +140,9 @@ if env["builtin_harfbuzz"]:
             env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"])
             env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"])
 
-    if env["platform"] == "android" or env["platform"] == "linuxbsd":
+    if env["platform"] in ["android", "linuxbsd", "web"]:
         env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
 
-    if env["platform"] == "web":
-        if env["threads_enabled"]:
-            env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
-        else:
-            env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
-
     env_text_server_adv.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"])
 
     lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)

+ 10 - 16
platform/web/SCsub

@@ -35,18 +35,17 @@ for ext in env["JS_EXTERNS"]:
     sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath
 
 build = []
-if env["gdnative_enabled"]:
-    build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
-    if env["threads_enabled"]:
-        build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
+build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"]
+if env["dlink_enabled"]:
     # Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
     sys_env["LIBS"] = []
     # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
     sys_env.Append(LIBS=["idbfs.js"])
     # Configure it as a main module (dynamic linking support).
+    sys_env["CCFLAGS"].remove("SIDE_MODULE=2")
+    sys_env["LINKFLAGS"].remove("SIDE_MODULE=2")
     sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"])
     sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
-    sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
     sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
     sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"])
     # Force exporting the standard library (printf, malloc, etc.)
@@ -55,16 +54,9 @@ if env["gdnative_enabled"]:
     sys = sys_env.Program(build_targets, ["web_runtime.cpp"])
 
     # The side library, containing all Godot code.
-    wasm_env = env.Clone()
-    wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"])  # So that OS knows it can run GDNative libraries.
-    wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
-    wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
-    wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
+    wasm = env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
     build = sys + [wasm[0]]
 else:
-    build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
-    if env["threads_enabled"]:
-        build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
     # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
     sys_env.Append(LIBS=["idbfs.js"])
     build = sys_env.Program(build_targets, web_files + ["web_runtime.cpp"])
@@ -88,6 +80,8 @@ wrap_list = [
 ]
 js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
 
-# Extra will be the thread worker, or the GDNative side, or None
-extra = build[2:] if len(build) > 2 else None
-env.CreateTemplateZip(js_wrapped, build[1], extra)
+# 0 - unwrapped js file (use wrapped one instead)
+# 1 - wasm file
+# 2 - worker file
+# 3 - wasm side (when dlink is enabled).
+env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None)

+ 28 - 42
platform/web/detect.py

@@ -38,8 +38,9 @@ def get_opts():
         BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
         # eval() can be a security concern, so it can be disabled.
         BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
-        BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", True),
-        BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
+        BoolVariable(
+            "dlink_enabled", "Enable WebAssembly dynamic linking (GDExtension support). Produces bigger binaries", False
+        ),
         BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
     ]
 
@@ -50,6 +51,13 @@ def get_flags():
         ("tools", False),
         ("builtin_pcre2_with_jit", False),
         ("vulkan", False),
+        # Use -Os to prioritize optimizing for reduced file size. This is
+        # particularly valuable for the web platform because it directly
+        # decreases download time.
+        # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
+        # 100 KiB over -Os, which does not justify the negative impact on
+        # run-time performance.
+        ("optimize", "size"),
     ]
 
 
@@ -71,15 +79,12 @@ def configure(env):
 
     ## Build type
     if env["target"].startswith("release"):
-        # Use -Os to prioritize optimizing for reduced file size. This is
-        # particularly valuable for the web platform because it directly
-        # decreases download time.
-        # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
-        # 100 KiB over -Os, which does not justify the negative impact on
-        # run-time performance.
-        if env["optimize"] != "none":
+        if env["optimize"] == "size":
             env.Append(CCFLAGS=["-Os"])
             env.Append(LINKFLAGS=["-Os"])
+        elif env["optimize"] == "speed":
+            env.Append(CCFLAGS=["-O3"])
+            env.Append(LINKFLAGS=["-O3"])
 
         if env["target"] == "release_debug":
             # Retain function names for backtraces at the cost of file size.
@@ -93,21 +98,11 @@ def configure(env):
         env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
 
     if env["tools"]:
-        if not env["threads_enabled"]:
-            print('Note: Forcing "threads_enabled=yes" as it is required for the web editor.')
-            env["threads_enabled"] = "yes"
         if env["initial_memory"] < 64:
             print('Note: Forcing "initial_memory=64" as it is required for the web editor.')
             env["initial_memory"] = 64
-        env.Append(CCFLAGS=["-frtti"])
-    elif env["builtin_icu"]:
-        env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
     else:
-        # Disable exceptions and rtti on non-tools (template) builds
-        # These flags help keep the file size down.
-        env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"])
-        # Don't use dynamic_cast, necessary with no-rtti.
-        env.Append(CPPDEFINES=["NO_SAFE_CAST"])
+        env.Append(CPPFLAGS=["-fno-exceptions"])
 
     env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
 
@@ -171,9 +166,9 @@ def configure(env):
     env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
     env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
 
-    # All intermediate files are just LLVM bitcode.
+    # All intermediate files are just object files.
     env["OBJPREFIX"] = ""
-    env["OBJSUFFIX"] = ".bc"
+    env["OBJSUFFIX"] = ".o"
     env["PROGPREFIX"] = ""
     # Program() output consists of multiple files, so specify suffixes manually at builder.
     env["PROGSUFFIX"] = ""
@@ -196,31 +191,22 @@ def configure(env):
         env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
 
     # Thread support (via SharedArrayBuffer).
-    if env["threads_enabled"]:
-        env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
-        env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
-        env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
-        env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
-        env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
-        env.extra_suffix = ".threads" + env.extra_suffix
-    else:
-        env.Append(CPPDEFINES=["NO_THREADS"])
+    env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
+    env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
+    env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
+    env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
+    env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
 
-    if env["gdnative_enabled"]:
+    if env["dlink_enabled"]:
         cc_version = get_compiler_version(env)
         cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
-        if cc_semver < (2, 0, 10):
-            print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver)
+        if cc_semver < (3, 1, 14):
+            print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
             sys.exit(255)
 
-        if env["threads_enabled"] and cc_semver < (3, 1, 14):
-            print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
-            sys.exit(255)
-        env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
-        env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
-        # Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819
-        env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"])
-        env.extra_suffix = ".gdnative" + env.extra_suffix
+        env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
+        env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
+        env.extra_suffix = ".dlink" + env.extra_suffix
 
     # Reduce code size by generating less support code (e.g. skip NodeJS support).
     env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])

+ 6 - 7
platform/web/emscripten_helpers.py

@@ -37,26 +37,25 @@ def create_engine_file(env, target, source, externs):
     return env.Textfile(target, [env.File(s) for s in source])
 
 
-def create_template_zip(env, js, wasm, extra):
+def create_template_zip(env, js, wasm, worker, side):
     binary_name = "godot.tools" if env["tools"] else "godot"
     zip_dir = env.Dir("#bin/.web_zip")
     in_files = [
         js,
         wasm,
+        worker,
         "#platform/web/js/libs/audio.worklet.js",
     ]
     out_files = [
         zip_dir.File(binary_name + ".js"),
         zip_dir.File(binary_name + ".wasm"),
+        zip_dir.File(binary_name + ".worker.js"),
         zip_dir.File(binary_name + ".audio.worklet.js"),
     ]
-    # GDNative/Threads specific
-    if env["gdnative_enabled"]:
-        in_files.append(extra.pop())  # Runtime
+    # Dynamic linking (extensions) specific.
+    if env["dlink_enabled"]:
+        in_files.append(side)  # Side wasm (contains the actual Godot code).
         out_files.append(zip_dir.File(binary_name + ".side.wasm"))
-    if env["threads_enabled"]:
-        in_files.append(extra.pop())  # Worker
-        out_files.append(zip_dir.File(binary_name + ".worker.js"))
 
     service_worker = "#misc/dist/html/service-worker.js"
     if env["tools"]:

+ 11 - 19
platform/web/export/export_plugin.cpp

@@ -201,7 +201,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 	// Service worker
 	const String dir = p_path.get_base_dir();
 	const String name = p_path.get_file().get_basename();
-	const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+	bool extensions = (bool)p_preset->get("variant/extensions_support");
 	HashMap<String, String> replaces;
 	replaces["@GODOT_VERSION@"] = String::num_int64(OS::get_singleton()->get_unix_time()) + "|" + String::num_int64(OS::get_singleton()->get_ticks_usec());
 	replaces["@GODOT_NAME@"] = proj_name.substr(0, 16);
@@ -216,17 +216,15 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 		cache_files.push_back(name + ".icon.png");
 		cache_files.push_back(name + ".apple-touch-icon.png");
 	}
-	if (mode & EXPORT_MODE_THREADS) {
-		cache_files.push_back(name + ".worker.js");
-		cache_files.push_back(name + ".audio.worklet.js");
-	}
+	cache_files.push_back(name + ".worker.js");
+	cache_files.push_back(name + ".audio.worklet.js");
 	replaces["@GODOT_CACHE@"] = Variant(cache_files).to_json_string();
 
 	// Heavy files that are cached on demand.
 	Array opt_cache_files;
 	opt_cache_files.push_back(name + ".wasm");
 	opt_cache_files.push_back(name + ".pck");
-	if (mode & EXPORT_MODE_GDNATIVE) {
+	if (extensions) {
 		opt_cache_files.push_back(name + ".side.wasm");
 		for (int i = 0; i < p_shared_objects.size(); i++) {
 			opt_cache_files.push_back(p_shared_objects[i].path.get_file());
@@ -317,20 +315,14 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset>
 			r_features->push_back("etc2");
 		}
 	}
-	ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
-	if (mode & EXPORT_MODE_THREADS) {
-		r_features->push_back("threads");
-	}
-	if (mode & EXPORT_MODE_GDNATIVE) {
-		r_features->push_back("wasm32");
-	}
+	r_features->push_back("wasm32");
 }
 
 void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) {
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 
-	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
+	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "variant/extensions_support"), false)); // Export type.
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
 
@@ -374,11 +366,11 @@ bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExp
 
 	String err;
 	bool valid = false;
-	ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+	bool extensions = (bool)p_preset->get("variant/extensions_support");
 
 	// Look for export templates (first official, and if defined custom templates).
-	bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
-	bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
+	bool dvalid = exists_export_template(_get_template_name(extensions, true), &err);
+	bool rvalid = exists_export_template(_get_template_name(extensions, false), &err);
 
 	if (p_preset->get("custom_template/debug") != "") {
 		dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -456,8 +448,8 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
 	String template_path = p_debug ? custom_debug : custom_release;
 	template_path = template_path.strip_edges();
 	if (template_path.is_empty()) {
-		ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
-		template_path = find_export_template(_get_template_name(mode, p_debug));
+		bool extensions = (bool)p_preset->get("variant/extensions_support");
+		template_path = find_export_template(_get_template_name(extensions, p_debug));
 	}
 
 	if (!DirAccess::exists(base_dir)) {

+ 4 - 14
platform/web/export/export_plugin.h

@@ -57,20 +57,10 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
 	Mutex server_lock;
 	Thread server_thread;
 
-	enum ExportMode {
-		EXPORT_MODE_NORMAL = 0,
-		EXPORT_MODE_THREADS = 1,
-		EXPORT_MODE_GDNATIVE = 2,
-		EXPORT_MODE_THREADS_GDNATIVE = 3,
-	};
-
-	String _get_template_name(ExportMode p_mode, bool p_debug) const {
-		String name = "webassembly";
-		if (p_mode & EXPORT_MODE_GDNATIVE) {
-			name += "_gdnative";
-		}
-		if (p_mode & EXPORT_MODE_THREADS) {
-			name += "_threads";
+	String _get_template_name(bool p_extension, bool p_debug) const {
+		String name = "web";
+		if (p_extension) {
+			name += "_dlink";
 		}
 		if (p_debug) {
 			name += "_debug.zip";

+ 0 - 17
platform/web/os_web.cpp

@@ -140,26 +140,9 @@ int OS_Web::get_processor_count() const {
 }
 
 bool OS_Web::_check_internal_feature_support(const String &p_feature) {
-	if (p_feature == "html5" || p_feature == "web") {
-		return true;
-	}
-
-#ifdef JAVASCRIPT_EVAL_ENABLED
 	if (p_feature == "web") {
 		return true;
 	}
-#endif
-#ifndef NO_THREADS
-	if (p_feature == "threads") {
-		return true;
-	}
-#endif
-#if WASM_GDNATIVE
-	if (p_feature == "wasm32") {
-		return true;
-	}
-#endif
-
 	return false;
 }